diff options
Diffstat (limited to 'drivers/media/common/tuners/tda18271-fe.c')
-rw-r--r-- | drivers/media/common/tuners/tda18271-fe.c | 1153 |
1 files changed, 1153 insertions, 0 deletions
diff --git a/drivers/media/common/tuners/tda18271-fe.c b/drivers/media/common/tuners/tda18271-fe.c new file mode 100644 index 000000000000..b262100ae897 --- /dev/null +++ b/drivers/media/common/tuners/tda18271-fe.c | |||
@@ -0,0 +1,1153 @@ | |||
1 | /* | ||
2 | tda18271-fe.c - driver for the Philips / NXP TDA18271 silicon tuner | ||
3 | |||
4 | Copyright (C) 2007, 2008 Michael Krufky <mkrufky@linuxtv.org> | ||
5 | |||
6 | This program is free software; you can redistribute it and/or modify | ||
7 | it under the terms of the GNU General Public License as published by | ||
8 | the Free Software Foundation; either version 2 of the License, or | ||
9 | (at your option) any later version. | ||
10 | |||
11 | This program is distributed in the hope that it will be useful, | ||
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | GNU General Public License for more details. | ||
15 | |||
16 | You should have received a copy of the GNU General Public License | ||
17 | along with this program; if not, write to the Free Software | ||
18 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
19 | */ | ||
20 | |||
21 | #include <linux/delay.h> | ||
22 | #include <linux/videodev2.h> | ||
23 | #include "tda18271-priv.h" | ||
24 | |||
25 | int tda18271_debug; | ||
26 | module_param_named(debug, tda18271_debug, int, 0644); | ||
27 | MODULE_PARM_DESC(debug, "set debug level " | ||
28 | "(info=1, map=2, reg=4, adv=8, cal=16 (or-able))"); | ||
29 | |||
30 | static int tda18271_cal_on_startup; | ||
31 | module_param_named(cal, tda18271_cal_on_startup, int, 0644); | ||
32 | MODULE_PARM_DESC(cal, "perform RF tracking filter calibration on startup"); | ||
33 | |||
34 | static DEFINE_MUTEX(tda18271_list_mutex); | ||
35 | static LIST_HEAD(hybrid_tuner_instance_list); | ||
36 | |||
37 | /*---------------------------------------------------------------------*/ | ||
38 | |||
39 | static inline int charge_pump_source(struct dvb_frontend *fe, int force) | ||
40 | { | ||
41 | struct tda18271_priv *priv = fe->tuner_priv; | ||
42 | return tda18271_charge_pump_source(fe, | ||
43 | (priv->role == TDA18271_SLAVE) ? | ||
44 | TDA18271_CAL_PLL : | ||
45 | TDA18271_MAIN_PLL, force); | ||
46 | } | ||
47 | |||
48 | static int tda18271_channel_configuration(struct dvb_frontend *fe, | ||
49 | struct tda18271_std_map_item *map, | ||
50 | u32 freq, u32 bw) | ||
51 | { | ||
52 | struct tda18271_priv *priv = fe->tuner_priv; | ||
53 | unsigned char *regs = priv->tda18271_regs; | ||
54 | u32 N; | ||
55 | |||
56 | /* update TV broadcast parameters */ | ||
57 | |||
58 | /* set standard */ | ||
59 | regs[R_EP3] &= ~0x1f; /* clear std bits */ | ||
60 | regs[R_EP3] |= (map->agc_mode << 3) | map->std; | ||
61 | |||
62 | /* set rfagc to high speed mode */ | ||
63 | regs[R_EP3] &= ~0x04; | ||
64 | |||
65 | /* set cal mode to normal */ | ||
66 | regs[R_EP4] &= ~0x03; | ||
67 | |||
68 | /* update IF output level & IF notch frequency */ | ||
69 | regs[R_EP4] &= ~0x1c; /* clear if level bits */ | ||
70 | regs[R_EP4] |= (map->if_lvl << 2); | ||
71 | |||
72 | switch (priv->mode) { | ||
73 | case TDA18271_ANALOG: | ||
74 | regs[R_MPD] &= ~0x80; /* IF notch = 0 */ | ||
75 | break; | ||
76 | case TDA18271_DIGITAL: | ||
77 | regs[R_MPD] |= 0x80; /* IF notch = 1 */ | ||
78 | break; | ||
79 | } | ||
80 | |||
81 | /* update FM_RFn */ | ||
82 | regs[R_EP4] &= ~0x80; | ||
83 | regs[R_EP4] |= map->fm_rfn << 7; | ||
84 | |||
85 | /* update rf top / if top */ | ||
86 | regs[R_EB22] = 0x00; | ||
87 | regs[R_EB22] |= map->rfagc_top; | ||
88 | tda18271_write_regs(fe, R_EB22, 1); | ||
89 | |||
90 | /* --------------------------------------------------------------- */ | ||
91 | |||
92 | /* disable Power Level Indicator */ | ||
93 | regs[R_EP1] |= 0x40; | ||
94 | |||
95 | /* frequency dependent parameters */ | ||
96 | |||
97 | tda18271_calc_ir_measure(fe, &freq); | ||
98 | |||
99 | tda18271_calc_bp_filter(fe, &freq); | ||
100 | |||
101 | tda18271_calc_rf_band(fe, &freq); | ||
102 | |||
103 | tda18271_calc_gain_taper(fe, &freq); | ||
104 | |||
105 | /* --------------------------------------------------------------- */ | ||
106 | |||
107 | /* dual tuner and agc1 extra configuration */ | ||
108 | |||
109 | switch (priv->role) { | ||
110 | case TDA18271_MASTER: | ||
111 | regs[R_EB1] |= 0x04; /* main vco */ | ||
112 | break; | ||
113 | case TDA18271_SLAVE: | ||
114 | regs[R_EB1] &= ~0x04; /* cal vco */ | ||
115 | break; | ||
116 | } | ||
117 | |||
118 | /* agc1 always active */ | ||
119 | regs[R_EB1] &= ~0x02; | ||
120 | |||
121 | /* agc1 has priority on agc2 */ | ||
122 | regs[R_EB1] &= ~0x01; | ||
123 | |||
124 | tda18271_write_regs(fe, R_EB1, 1); | ||
125 | |||
126 | /* --------------------------------------------------------------- */ | ||
127 | |||
128 | N = map->if_freq * 1000 + freq; | ||
129 | |||
130 | switch (priv->role) { | ||
131 | case TDA18271_MASTER: | ||
132 | tda18271_calc_main_pll(fe, N); | ||
133 | tda18271_write_regs(fe, R_MPD, 4); | ||
134 | break; | ||
135 | case TDA18271_SLAVE: | ||
136 | tda18271_calc_cal_pll(fe, N); | ||
137 | tda18271_write_regs(fe, R_CPD, 4); | ||
138 | |||
139 | regs[R_MPD] = regs[R_CPD] & 0x7f; | ||
140 | tda18271_write_regs(fe, R_MPD, 1); | ||
141 | break; | ||
142 | } | ||
143 | |||
144 | tda18271_write_regs(fe, R_TM, 7); | ||
145 | |||
146 | /* force charge pump source */ | ||
147 | charge_pump_source(fe, 1); | ||
148 | |||
149 | msleep(1); | ||
150 | |||
151 | /* return pll to normal operation */ | ||
152 | charge_pump_source(fe, 0); | ||
153 | |||
154 | msleep(20); | ||
155 | |||
156 | /* set rfagc to normal speed mode */ | ||
157 | if (map->fm_rfn) | ||
158 | regs[R_EP3] &= ~0x04; | ||
159 | else | ||
160 | regs[R_EP3] |= 0x04; | ||
161 | tda18271_write_regs(fe, R_EP3, 1); | ||
162 | |||
163 | return 0; | ||
164 | } | ||
165 | |||
166 | static int tda18271_read_thermometer(struct dvb_frontend *fe) | ||
167 | { | ||
168 | struct tda18271_priv *priv = fe->tuner_priv; | ||
169 | unsigned char *regs = priv->tda18271_regs; | ||
170 | int tm; | ||
171 | |||
172 | /* switch thermometer on */ | ||
173 | regs[R_TM] |= 0x10; | ||
174 | tda18271_write_regs(fe, R_TM, 1); | ||
175 | |||
176 | /* read thermometer info */ | ||
177 | tda18271_read_regs(fe); | ||
178 | |||
179 | if ((((regs[R_TM] & 0x0f) == 0x00) && ((regs[R_TM] & 0x20) == 0x20)) || | ||
180 | (((regs[R_TM] & 0x0f) == 0x08) && ((regs[R_TM] & 0x20) == 0x00))) { | ||
181 | |||
182 | if ((regs[R_TM] & 0x20) == 0x20) | ||
183 | regs[R_TM] &= ~0x20; | ||
184 | else | ||
185 | regs[R_TM] |= 0x20; | ||
186 | |||
187 | tda18271_write_regs(fe, R_TM, 1); | ||
188 | |||
189 | msleep(10); /* temperature sensing */ | ||
190 | |||
191 | /* read thermometer info */ | ||
192 | tda18271_read_regs(fe); | ||
193 | } | ||
194 | |||
195 | tm = tda18271_lookup_thermometer(fe); | ||
196 | |||
197 | /* switch thermometer off */ | ||
198 | regs[R_TM] &= ~0x10; | ||
199 | tda18271_write_regs(fe, R_TM, 1); | ||
200 | |||
201 | /* set CAL mode to normal */ | ||
202 | regs[R_EP4] &= ~0x03; | ||
203 | tda18271_write_regs(fe, R_EP4, 1); | ||
204 | |||
205 | return tm; | ||
206 | } | ||
207 | |||
208 | /* ------------------------------------------------------------------ */ | ||
209 | |||
210 | static int tda18271c2_rf_tracking_filters_correction(struct dvb_frontend *fe, | ||
211 | u32 freq) | ||
212 | { | ||
213 | struct tda18271_priv *priv = fe->tuner_priv; | ||
214 | struct tda18271_rf_tracking_filter_cal *map = priv->rf_cal_state; | ||
215 | unsigned char *regs = priv->tda18271_regs; | ||
216 | int tm_current, rfcal_comp, approx, i; | ||
217 | u8 dc_over_dt, rf_tab; | ||
218 | |||
219 | /* power up */ | ||
220 | tda18271_set_standby_mode(fe, 0, 0, 0); | ||
221 | |||
222 | /* read die current temperature */ | ||
223 | tm_current = tda18271_read_thermometer(fe); | ||
224 | |||
225 | /* frequency dependent parameters */ | ||
226 | |||
227 | tda18271_calc_rf_cal(fe, &freq); | ||
228 | rf_tab = regs[R_EB14]; | ||
229 | |||
230 | i = tda18271_lookup_rf_band(fe, &freq, NULL); | ||
231 | if (i < 0) | ||
232 | return -EINVAL; | ||
233 | |||
234 | if ((0 == map[i].rf3) || (freq / 1000 < map[i].rf2)) { | ||
235 | approx = map[i].rf_a1 * | ||
236 | (freq / 1000 - map[i].rf1) + map[i].rf_b1 + rf_tab; | ||
237 | } else { | ||
238 | approx = map[i].rf_a2 * | ||
239 | (freq / 1000 - map[i].rf2) + map[i].rf_b2 + rf_tab; | ||
240 | } | ||
241 | |||
242 | if (approx < 0) | ||
243 | approx = 0; | ||
244 | if (approx > 255) | ||
245 | approx = 255; | ||
246 | |||
247 | tda18271_lookup_map(fe, RF_CAL_DC_OVER_DT, &freq, &dc_over_dt); | ||
248 | |||
249 | /* calculate temperature compensation */ | ||
250 | rfcal_comp = dc_over_dt * (tm_current - priv->tm_rfcal); | ||
251 | |||
252 | regs[R_EB14] = approx + rfcal_comp; | ||
253 | tda18271_write_regs(fe, R_EB14, 1); | ||
254 | |||
255 | return 0; | ||
256 | } | ||
257 | |||
258 | static int tda18271_por(struct dvb_frontend *fe) | ||
259 | { | ||
260 | struct tda18271_priv *priv = fe->tuner_priv; | ||
261 | unsigned char *regs = priv->tda18271_regs; | ||
262 | |||
263 | /* power up detector 1 */ | ||
264 | regs[R_EB12] &= ~0x20; | ||
265 | tda18271_write_regs(fe, R_EB12, 1); | ||
266 | |||
267 | regs[R_EB18] &= ~0x80; /* turn agc1 loop on */ | ||
268 | regs[R_EB18] &= ~0x03; /* set agc1_gain to 6 dB */ | ||
269 | tda18271_write_regs(fe, R_EB18, 1); | ||
270 | |||
271 | regs[R_EB21] |= 0x03; /* set agc2_gain to -6 dB */ | ||
272 | |||
273 | /* POR mode */ | ||
274 | tda18271_set_standby_mode(fe, 1, 0, 0); | ||
275 | |||
276 | /* disable 1.5 MHz low pass filter */ | ||
277 | regs[R_EB23] &= ~0x04; /* forcelp_fc2_en = 0 */ | ||
278 | regs[R_EB23] &= ~0x02; /* XXX: lp_fc[2] = 0 */ | ||
279 | tda18271_write_regs(fe, R_EB21, 3); | ||
280 | |||
281 | return 0; | ||
282 | } | ||
283 | |||
284 | static int tda18271_calibrate_rf(struct dvb_frontend *fe, u32 freq) | ||
285 | { | ||
286 | struct tda18271_priv *priv = fe->tuner_priv; | ||
287 | unsigned char *regs = priv->tda18271_regs; | ||
288 | u32 N; | ||
289 | |||
290 | /* set CAL mode to normal */ | ||
291 | regs[R_EP4] &= ~0x03; | ||
292 | tda18271_write_regs(fe, R_EP4, 1); | ||
293 | |||
294 | /* switch off agc1 */ | ||
295 | regs[R_EP3] |= 0x40; /* sm_lt = 1 */ | ||
296 | |||
297 | regs[R_EB18] |= 0x03; /* set agc1_gain to 15 dB */ | ||
298 | tda18271_write_regs(fe, R_EB18, 1); | ||
299 | |||
300 | /* frequency dependent parameters */ | ||
301 | |||
302 | tda18271_calc_bp_filter(fe, &freq); | ||
303 | tda18271_calc_gain_taper(fe, &freq); | ||
304 | tda18271_calc_rf_band(fe, &freq); | ||
305 | tda18271_calc_km(fe, &freq); | ||
306 | |||
307 | tda18271_write_regs(fe, R_EP1, 3); | ||
308 | tda18271_write_regs(fe, R_EB13, 1); | ||
309 | |||
310 | /* main pll charge pump source */ | ||
311 | tda18271_charge_pump_source(fe, TDA18271_MAIN_PLL, 1); | ||
312 | |||
313 | /* cal pll charge pump source */ | ||
314 | tda18271_charge_pump_source(fe, TDA18271_CAL_PLL, 1); | ||
315 | |||
316 | /* force dcdc converter to 0 V */ | ||
317 | regs[R_EB14] = 0x00; | ||
318 | tda18271_write_regs(fe, R_EB14, 1); | ||
319 | |||
320 | /* disable plls lock */ | ||
321 | regs[R_EB20] &= ~0x20; | ||
322 | tda18271_write_regs(fe, R_EB20, 1); | ||
323 | |||
324 | /* set CAL mode to RF tracking filter calibration */ | ||
325 | regs[R_EP4] |= 0x03; | ||
326 | tda18271_write_regs(fe, R_EP4, 2); | ||
327 | |||
328 | /* --------------------------------------------------------------- */ | ||
329 | |||
330 | /* set the internal calibration signal */ | ||
331 | N = freq; | ||
332 | |||
333 | tda18271_calc_cal_pll(fe, N); | ||
334 | tda18271_write_regs(fe, R_CPD, 4); | ||
335 | |||
336 | /* downconvert internal calibration */ | ||
337 | N += 1000000; | ||
338 | |||
339 | tda18271_calc_main_pll(fe, N); | ||
340 | tda18271_write_regs(fe, R_MPD, 4); | ||
341 | |||
342 | msleep(5); | ||
343 | |||
344 | tda18271_write_regs(fe, R_EP2, 1); | ||
345 | tda18271_write_regs(fe, R_EP1, 1); | ||
346 | tda18271_write_regs(fe, R_EP2, 1); | ||
347 | tda18271_write_regs(fe, R_EP1, 1); | ||
348 | |||
349 | /* --------------------------------------------------------------- */ | ||
350 | |||
351 | /* normal operation for the main pll */ | ||
352 | tda18271_charge_pump_source(fe, TDA18271_MAIN_PLL, 0); | ||
353 | |||
354 | /* normal operation for the cal pll */ | ||
355 | tda18271_charge_pump_source(fe, TDA18271_CAL_PLL, 0); | ||
356 | |||
357 | msleep(10); /* plls locking */ | ||
358 | |||
359 | /* launch the rf tracking filters calibration */ | ||
360 | regs[R_EB20] |= 0x20; | ||
361 | tda18271_write_regs(fe, R_EB20, 1); | ||
362 | |||
363 | msleep(60); /* calibration */ | ||
364 | |||
365 | /* --------------------------------------------------------------- */ | ||
366 | |||
367 | /* set CAL mode to normal */ | ||
368 | regs[R_EP4] &= ~0x03; | ||
369 | |||
370 | /* switch on agc1 */ | ||
371 | regs[R_EP3] &= ~0x40; /* sm_lt = 0 */ | ||
372 | |||
373 | regs[R_EB18] &= ~0x03; /* set agc1_gain to 6 dB */ | ||
374 | tda18271_write_regs(fe, R_EB18, 1); | ||
375 | |||
376 | tda18271_write_regs(fe, R_EP3, 2); | ||
377 | |||
378 | /* synchronization */ | ||
379 | tda18271_write_regs(fe, R_EP1, 1); | ||
380 | |||
381 | /* get calibration result */ | ||
382 | tda18271_read_extended(fe); | ||
383 | |||
384 | return regs[R_EB14]; | ||
385 | } | ||
386 | |||
387 | static int tda18271_powerscan(struct dvb_frontend *fe, | ||
388 | u32 *freq_in, u32 *freq_out) | ||
389 | { | ||
390 | struct tda18271_priv *priv = fe->tuner_priv; | ||
391 | unsigned char *regs = priv->tda18271_regs; | ||
392 | int sgn, bcal, count, wait; | ||
393 | u8 cid_target; | ||
394 | u16 count_limit; | ||
395 | u32 freq; | ||
396 | |||
397 | freq = *freq_in; | ||
398 | |||
399 | tda18271_calc_rf_band(fe, &freq); | ||
400 | tda18271_calc_rf_cal(fe, &freq); | ||
401 | tda18271_calc_gain_taper(fe, &freq); | ||
402 | tda18271_lookup_cid_target(fe, &freq, &cid_target, &count_limit); | ||
403 | |||
404 | tda18271_write_regs(fe, R_EP2, 1); | ||
405 | tda18271_write_regs(fe, R_EB14, 1); | ||
406 | |||
407 | /* downconvert frequency */ | ||
408 | freq += 1000000; | ||
409 | |||
410 | tda18271_calc_main_pll(fe, freq); | ||
411 | tda18271_write_regs(fe, R_MPD, 4); | ||
412 | |||
413 | msleep(5); /* pll locking */ | ||
414 | |||
415 | /* detection mode */ | ||
416 | regs[R_EP4] &= ~0x03; | ||
417 | regs[R_EP4] |= 0x01; | ||
418 | tda18271_write_regs(fe, R_EP4, 1); | ||
419 | |||
420 | /* launch power detection measurement */ | ||
421 | tda18271_write_regs(fe, R_EP2, 1); | ||
422 | |||
423 | /* read power detection info, stored in EB10 */ | ||
424 | tda18271_read_extended(fe); | ||
425 | |||
426 | /* algorithm initialization */ | ||
427 | sgn = 1; | ||
428 | *freq_out = *freq_in; | ||
429 | bcal = 0; | ||
430 | count = 0; | ||
431 | wait = false; | ||
432 | |||
433 | while ((regs[R_EB10] & 0x3f) < cid_target) { | ||
434 | /* downconvert updated freq to 1 MHz */ | ||
435 | freq = *freq_in + (sgn * count) + 1000000; | ||
436 | |||
437 | tda18271_calc_main_pll(fe, freq); | ||
438 | tda18271_write_regs(fe, R_MPD, 4); | ||
439 | |||
440 | if (wait) { | ||
441 | msleep(5); /* pll locking */ | ||
442 | wait = false; | ||
443 | } else | ||
444 | udelay(100); /* pll locking */ | ||
445 | |||
446 | /* launch power detection measurement */ | ||
447 | tda18271_write_regs(fe, R_EP2, 1); | ||
448 | |||
449 | /* read power detection info, stored in EB10 */ | ||
450 | tda18271_read_extended(fe); | ||
451 | |||
452 | count += 200; | ||
453 | |||
454 | if (count <= count_limit) | ||
455 | continue; | ||
456 | |||
457 | if (sgn <= 0) | ||
458 | break; | ||
459 | |||
460 | sgn = -1 * sgn; | ||
461 | count = 200; | ||
462 | wait = true; | ||
463 | } | ||
464 | |||
465 | if ((regs[R_EB10] & 0x3f) >= cid_target) { | ||
466 | bcal = 1; | ||
467 | *freq_out = freq - 1000000; | ||
468 | } else | ||
469 | bcal = 0; | ||
470 | |||
471 | tda_cal("bcal = %d, freq_in = %d, freq_out = %d (freq = %d)\n", | ||
472 | bcal, *freq_in, *freq_out, freq); | ||
473 | |||
474 | return bcal; | ||
475 | } | ||
476 | |||
477 | static int tda18271_powerscan_init(struct dvb_frontend *fe) | ||
478 | { | ||
479 | struct tda18271_priv *priv = fe->tuner_priv; | ||
480 | unsigned char *regs = priv->tda18271_regs; | ||
481 | |||
482 | /* set standard to digital */ | ||
483 | regs[R_EP3] &= ~0x1f; /* clear std bits */ | ||
484 | regs[R_EP3] |= 0x12; | ||
485 | |||
486 | /* set cal mode to normal */ | ||
487 | regs[R_EP4] &= ~0x03; | ||
488 | |||
489 | /* update IF output level & IF notch frequency */ | ||
490 | regs[R_EP4] &= ~0x1c; /* clear if level bits */ | ||
491 | |||
492 | tda18271_write_regs(fe, R_EP3, 2); | ||
493 | |||
494 | regs[R_EB18] &= ~0x03; /* set agc1_gain to 6 dB */ | ||
495 | tda18271_write_regs(fe, R_EB18, 1); | ||
496 | |||
497 | regs[R_EB21] &= ~0x03; /* set agc2_gain to -15 dB */ | ||
498 | |||
499 | /* 1.5 MHz low pass filter */ | ||
500 | regs[R_EB23] |= 0x04; /* forcelp_fc2_en = 1 */ | ||
501 | regs[R_EB23] |= 0x02; /* lp_fc[2] = 1 */ | ||
502 | |||
503 | tda18271_write_regs(fe, R_EB21, 3); | ||
504 | |||
505 | return 0; | ||
506 | } | ||
507 | |||
508 | static int tda18271_rf_tracking_filters_init(struct dvb_frontend *fe, u32 freq) | ||
509 | { | ||
510 | struct tda18271_priv *priv = fe->tuner_priv; | ||
511 | struct tda18271_rf_tracking_filter_cal *map = priv->rf_cal_state; | ||
512 | unsigned char *regs = priv->tda18271_regs; | ||
513 | int bcal, rf, i; | ||
514 | #define RF1 0 | ||
515 | #define RF2 1 | ||
516 | #define RF3 2 | ||
517 | u32 rf_default[3]; | ||
518 | u32 rf_freq[3]; | ||
519 | u8 prog_cal[3]; | ||
520 | u8 prog_tab[3]; | ||
521 | |||
522 | i = tda18271_lookup_rf_band(fe, &freq, NULL); | ||
523 | |||
524 | if (i < 0) | ||
525 | return i; | ||
526 | |||
527 | rf_default[RF1] = 1000 * map[i].rf1_def; | ||
528 | rf_default[RF2] = 1000 * map[i].rf2_def; | ||
529 | rf_default[RF3] = 1000 * map[i].rf3_def; | ||
530 | |||
531 | for (rf = RF1; rf <= RF3; rf++) { | ||
532 | if (0 == rf_default[rf]) | ||
533 | return 0; | ||
534 | tda_cal("freq = %d, rf = %d\n", freq, rf); | ||
535 | |||
536 | /* look for optimized calibration frequency */ | ||
537 | bcal = tda18271_powerscan(fe, &rf_default[rf], &rf_freq[rf]); | ||
538 | |||
539 | tda18271_calc_rf_cal(fe, &rf_freq[rf]); | ||
540 | prog_tab[rf] = regs[R_EB14]; | ||
541 | |||
542 | if (1 == bcal) | ||
543 | prog_cal[rf] = tda18271_calibrate_rf(fe, rf_freq[rf]); | ||
544 | else | ||
545 | prog_cal[rf] = prog_tab[rf]; | ||
546 | |||
547 | switch (rf) { | ||
548 | case RF1: | ||
549 | map[i].rf_a1 = 0; | ||
550 | map[i].rf_b1 = prog_cal[RF1] - prog_tab[RF1]; | ||
551 | map[i].rf1 = rf_freq[RF1] / 1000; | ||
552 | break; | ||
553 | case RF2: | ||
554 | map[i].rf_a1 = (prog_cal[RF2] - prog_tab[RF2] - | ||
555 | prog_cal[RF1] + prog_tab[RF1]) / | ||
556 | ((rf_freq[RF2] - rf_freq[RF1]) / 1000); | ||
557 | map[i].rf2 = rf_freq[RF2] / 1000; | ||
558 | break; | ||
559 | case RF3: | ||
560 | map[i].rf_a2 = (prog_cal[RF3] - prog_tab[RF3] - | ||
561 | prog_cal[RF2] + prog_tab[RF2]) / | ||
562 | ((rf_freq[RF3] - rf_freq[RF2]) / 1000); | ||
563 | map[i].rf_b2 = prog_cal[RF2] - prog_tab[RF2]; | ||
564 | map[i].rf3 = rf_freq[RF3] / 1000; | ||
565 | break; | ||
566 | default: | ||
567 | BUG(); | ||
568 | } | ||
569 | } | ||
570 | |||
571 | return 0; | ||
572 | } | ||
573 | |||
574 | static int tda18271_calc_rf_filter_curve(struct dvb_frontend *fe) | ||
575 | { | ||
576 | struct tda18271_priv *priv = fe->tuner_priv; | ||
577 | unsigned int i; | ||
578 | |||
579 | tda_info("tda18271: performing RF tracking filter calibration\n"); | ||
580 | |||
581 | /* wait for die temperature stabilization */ | ||
582 | msleep(200); | ||
583 | |||
584 | tda18271_powerscan_init(fe); | ||
585 | |||
586 | /* rf band calibration */ | ||
587 | for (i = 0; priv->rf_cal_state[i].rfmax != 0; i++) | ||
588 | tda18271_rf_tracking_filters_init(fe, 1000 * | ||
589 | priv->rf_cal_state[i].rfmax); | ||
590 | |||
591 | priv->tm_rfcal = tda18271_read_thermometer(fe); | ||
592 | |||
593 | return 0; | ||
594 | } | ||
595 | |||
596 | /* ------------------------------------------------------------------ */ | ||
597 | |||
598 | static int tda18271c2_rf_cal_init(struct dvb_frontend *fe) | ||
599 | { | ||
600 | struct tda18271_priv *priv = fe->tuner_priv; | ||
601 | unsigned char *regs = priv->tda18271_regs; | ||
602 | |||
603 | /* test RF_CAL_OK to see if we need init */ | ||
604 | if ((regs[R_EP1] & 0x10) == 0) | ||
605 | priv->cal_initialized = false; | ||
606 | |||
607 | if (priv->cal_initialized) | ||
608 | return 0; | ||
609 | |||
610 | tda18271_calc_rf_filter_curve(fe); | ||
611 | |||
612 | tda18271_por(fe); | ||
613 | |||
614 | tda_info("tda18271: RF tracking filter calibration complete\n"); | ||
615 | |||
616 | priv->cal_initialized = true; | ||
617 | |||
618 | return 0; | ||
619 | } | ||
620 | |||
621 | static int tda18271c1_rf_tracking_filter_calibration(struct dvb_frontend *fe, | ||
622 | u32 freq, u32 bw) | ||
623 | { | ||
624 | struct tda18271_priv *priv = fe->tuner_priv; | ||
625 | unsigned char *regs = priv->tda18271_regs; | ||
626 | u32 N = 0; | ||
627 | |||
628 | /* calculate bp filter */ | ||
629 | tda18271_calc_bp_filter(fe, &freq); | ||
630 | tda18271_write_regs(fe, R_EP1, 1); | ||
631 | |||
632 | regs[R_EB4] &= 0x07; | ||
633 | regs[R_EB4] |= 0x60; | ||
634 | tda18271_write_regs(fe, R_EB4, 1); | ||
635 | |||
636 | regs[R_EB7] = 0x60; | ||
637 | tda18271_write_regs(fe, R_EB7, 1); | ||
638 | |||
639 | regs[R_EB14] = 0x00; | ||
640 | tda18271_write_regs(fe, R_EB14, 1); | ||
641 | |||
642 | regs[R_EB20] = 0xcc; | ||
643 | tda18271_write_regs(fe, R_EB20, 1); | ||
644 | |||
645 | /* set cal mode to RF tracking filter calibration */ | ||
646 | regs[R_EP4] |= 0x03; | ||
647 | |||
648 | /* calculate cal pll */ | ||
649 | |||
650 | switch (priv->mode) { | ||
651 | case TDA18271_ANALOG: | ||
652 | N = freq - 1250000; | ||
653 | break; | ||
654 | case TDA18271_DIGITAL: | ||
655 | N = freq + bw / 2; | ||
656 | break; | ||
657 | } | ||
658 | |||
659 | tda18271_calc_cal_pll(fe, N); | ||
660 | |||
661 | /* calculate main pll */ | ||
662 | |||
663 | switch (priv->mode) { | ||
664 | case TDA18271_ANALOG: | ||
665 | N = freq - 250000; | ||
666 | break; | ||
667 | case TDA18271_DIGITAL: | ||
668 | N = freq + bw / 2 + 1000000; | ||
669 | break; | ||
670 | } | ||
671 | |||
672 | tda18271_calc_main_pll(fe, N); | ||
673 | |||
674 | tda18271_write_regs(fe, R_EP3, 11); | ||
675 | msleep(5); /* RF tracking filter calibration initialization */ | ||
676 | |||
677 | /* search for K,M,CO for RF calibration */ | ||
678 | tda18271_calc_km(fe, &freq); | ||
679 | tda18271_write_regs(fe, R_EB13, 1); | ||
680 | |||
681 | /* search for rf band */ | ||
682 | tda18271_calc_rf_band(fe, &freq); | ||
683 | |||
684 | /* search for gain taper */ | ||
685 | tda18271_calc_gain_taper(fe, &freq); | ||
686 | |||
687 | tda18271_write_regs(fe, R_EP2, 1); | ||
688 | tda18271_write_regs(fe, R_EP1, 1); | ||
689 | tda18271_write_regs(fe, R_EP2, 1); | ||
690 | tda18271_write_regs(fe, R_EP1, 1); | ||
691 | |||
692 | regs[R_EB4] &= 0x07; | ||
693 | regs[R_EB4] |= 0x40; | ||
694 | tda18271_write_regs(fe, R_EB4, 1); | ||
695 | |||
696 | regs[R_EB7] = 0x40; | ||
697 | tda18271_write_regs(fe, R_EB7, 1); | ||
698 | msleep(10); /* pll locking */ | ||
699 | |||
700 | regs[R_EB20] = 0xec; | ||
701 | tda18271_write_regs(fe, R_EB20, 1); | ||
702 | msleep(60); /* RF tracking filter calibration completion */ | ||
703 | |||
704 | regs[R_EP4] &= ~0x03; /* set cal mode to normal */ | ||
705 | tda18271_write_regs(fe, R_EP4, 1); | ||
706 | |||
707 | tda18271_write_regs(fe, R_EP1, 1); | ||
708 | |||
709 | /* RF tracking filter correction for VHF_Low band */ | ||
710 | if (0 == tda18271_calc_rf_cal(fe, &freq)) | ||
711 | tda18271_write_regs(fe, R_EB14, 1); | ||
712 | |||
713 | return 0; | ||
714 | } | ||
715 | |||
716 | /* ------------------------------------------------------------------ */ | ||
717 | |||
718 | static int tda18271_ir_cal_init(struct dvb_frontend *fe) | ||
719 | { | ||
720 | struct tda18271_priv *priv = fe->tuner_priv; | ||
721 | unsigned char *regs = priv->tda18271_regs; | ||
722 | |||
723 | tda18271_read_regs(fe); | ||
724 | |||
725 | /* test IR_CAL_OK to see if we need init */ | ||
726 | if ((regs[R_EP1] & 0x08) == 0) | ||
727 | tda18271_init_regs(fe); | ||
728 | |||
729 | return 0; | ||
730 | } | ||
731 | |||
732 | static int tda18271_init(struct dvb_frontend *fe) | ||
733 | { | ||
734 | struct tda18271_priv *priv = fe->tuner_priv; | ||
735 | |||
736 | mutex_lock(&priv->lock); | ||
737 | |||
738 | /* power up */ | ||
739 | tda18271_set_standby_mode(fe, 0, 0, 0); | ||
740 | |||
741 | /* initialization */ | ||
742 | tda18271_ir_cal_init(fe); | ||
743 | |||
744 | if (priv->id == TDA18271HDC2) | ||
745 | tda18271c2_rf_cal_init(fe); | ||
746 | |||
747 | mutex_unlock(&priv->lock); | ||
748 | |||
749 | return 0; | ||
750 | } | ||
751 | |||
752 | static int tda18271_tune(struct dvb_frontend *fe, | ||
753 | struct tda18271_std_map_item *map, u32 freq, u32 bw) | ||
754 | { | ||
755 | struct tda18271_priv *priv = fe->tuner_priv; | ||
756 | |||
757 | tda_dbg("freq = %d, ifc = %d, bw = %d, agc_mode = %d, std = %d\n", | ||
758 | freq, map->if_freq, bw, map->agc_mode, map->std); | ||
759 | |||
760 | tda18271_init(fe); | ||
761 | |||
762 | mutex_lock(&priv->lock); | ||
763 | |||
764 | switch (priv->id) { | ||
765 | case TDA18271HDC1: | ||
766 | tda18271c1_rf_tracking_filter_calibration(fe, freq, bw); | ||
767 | break; | ||
768 | case TDA18271HDC2: | ||
769 | tda18271c2_rf_tracking_filters_correction(fe, freq); | ||
770 | break; | ||
771 | } | ||
772 | tda18271_channel_configuration(fe, map, freq, bw); | ||
773 | |||
774 | mutex_unlock(&priv->lock); | ||
775 | |||
776 | return 0; | ||
777 | } | ||
778 | |||
779 | /* ------------------------------------------------------------------ */ | ||
780 | |||
781 | static int tda18271_set_params(struct dvb_frontend *fe, | ||
782 | struct dvb_frontend_parameters *params) | ||
783 | { | ||
784 | struct tda18271_priv *priv = fe->tuner_priv; | ||
785 | struct tda18271_std_map *std_map = &priv->std; | ||
786 | struct tda18271_std_map_item *map; | ||
787 | int ret; | ||
788 | u32 bw, freq = params->frequency; | ||
789 | |||
790 | priv->mode = TDA18271_DIGITAL; | ||
791 | |||
792 | if (fe->ops.info.type == FE_ATSC) { | ||
793 | switch (params->u.vsb.modulation) { | ||
794 | case VSB_8: | ||
795 | case VSB_16: | ||
796 | map = &std_map->atsc_6; | ||
797 | break; | ||
798 | case QAM_64: | ||
799 | case QAM_256: | ||
800 | map = &std_map->qam_6; | ||
801 | break; | ||
802 | default: | ||
803 | tda_warn("modulation not set!\n"); | ||
804 | return -EINVAL; | ||
805 | } | ||
806 | #if 0 | ||
807 | /* userspace request is already center adjusted */ | ||
808 | freq += 1750000; /* Adjust to center (+1.75MHZ) */ | ||
809 | #endif | ||
810 | bw = 6000000; | ||
811 | } else if (fe->ops.info.type == FE_OFDM) { | ||
812 | switch (params->u.ofdm.bandwidth) { | ||
813 | case BANDWIDTH_6_MHZ: | ||
814 | bw = 6000000; | ||
815 | map = &std_map->dvbt_6; | ||
816 | break; | ||
817 | case BANDWIDTH_7_MHZ: | ||
818 | bw = 7000000; | ||
819 | map = &std_map->dvbt_7; | ||
820 | break; | ||
821 | case BANDWIDTH_8_MHZ: | ||
822 | bw = 8000000; | ||
823 | map = &std_map->dvbt_8; | ||
824 | break; | ||
825 | default: | ||
826 | tda_warn("bandwidth not set!\n"); | ||
827 | return -EINVAL; | ||
828 | } | ||
829 | } else { | ||
830 | tda_warn("modulation type not supported!\n"); | ||
831 | return -EINVAL; | ||
832 | } | ||
833 | |||
834 | /* When tuning digital, the analog demod must be tri-stated */ | ||
835 | if (fe->ops.analog_ops.standby) | ||
836 | fe->ops.analog_ops.standby(fe); | ||
837 | |||
838 | ret = tda18271_tune(fe, map, freq, bw); | ||
839 | |||
840 | if (ret < 0) | ||
841 | goto fail; | ||
842 | |||
843 | priv->frequency = freq; | ||
844 | priv->bandwidth = (fe->ops.info.type == FE_OFDM) ? | ||
845 | params->u.ofdm.bandwidth : 0; | ||
846 | fail: | ||
847 | return ret; | ||
848 | } | ||
849 | |||
850 | static int tda18271_set_analog_params(struct dvb_frontend *fe, | ||
851 | struct analog_parameters *params) | ||
852 | { | ||
853 | struct tda18271_priv *priv = fe->tuner_priv; | ||
854 | struct tda18271_std_map *std_map = &priv->std; | ||
855 | struct tda18271_std_map_item *map; | ||
856 | char *mode; | ||
857 | int ret; | ||
858 | u32 freq = params->frequency * 62500; | ||
859 | |||
860 | priv->mode = TDA18271_ANALOG; | ||
861 | |||
862 | if (params->mode == V4L2_TUNER_RADIO) { | ||
863 | freq = freq / 1000; | ||
864 | map = &std_map->fm_radio; | ||
865 | mode = "fm"; | ||
866 | } else if (params->std & V4L2_STD_MN) { | ||
867 | map = &std_map->atv_mn; | ||
868 | mode = "MN"; | ||
869 | } else if (params->std & V4L2_STD_B) { | ||
870 | map = &std_map->atv_b; | ||
871 | mode = "B"; | ||
872 | } else if (params->std & V4L2_STD_GH) { | ||
873 | map = &std_map->atv_gh; | ||
874 | mode = "GH"; | ||
875 | } else if (params->std & V4L2_STD_PAL_I) { | ||
876 | map = &std_map->atv_i; | ||
877 | mode = "I"; | ||
878 | } else if (params->std & V4L2_STD_DK) { | ||
879 | map = &std_map->atv_dk; | ||
880 | mode = "DK"; | ||
881 | } else if (params->std & V4L2_STD_SECAM_L) { | ||
882 | map = &std_map->atv_l; | ||
883 | mode = "L"; | ||
884 | } else if (params->std & V4L2_STD_SECAM_LC) { | ||
885 | map = &std_map->atv_lc; | ||
886 | mode = "L'"; | ||
887 | } else { | ||
888 | map = &std_map->atv_i; | ||
889 | mode = "xx"; | ||
890 | } | ||
891 | |||
892 | tda_dbg("setting tda18271 to system %s\n", mode); | ||
893 | |||
894 | ret = tda18271_tune(fe, map, freq, 0); | ||
895 | |||
896 | if (ret < 0) | ||
897 | goto fail; | ||
898 | |||
899 | priv->frequency = freq; | ||
900 | priv->bandwidth = 0; | ||
901 | fail: | ||
902 | return ret; | ||
903 | } | ||
904 | |||
905 | static int tda18271_sleep(struct dvb_frontend *fe) | ||
906 | { | ||
907 | struct tda18271_priv *priv = fe->tuner_priv; | ||
908 | |||
909 | mutex_lock(&priv->lock); | ||
910 | |||
911 | /* standby mode w/ slave tuner output | ||
912 | * & loop thru & xtal oscillator on */ | ||
913 | tda18271_set_standby_mode(fe, 1, 0, 0); | ||
914 | |||
915 | mutex_unlock(&priv->lock); | ||
916 | |||
917 | return 0; | ||
918 | } | ||
919 | |||
920 | static int tda18271_release(struct dvb_frontend *fe) | ||
921 | { | ||
922 | struct tda18271_priv *priv = fe->tuner_priv; | ||
923 | |||
924 | mutex_lock(&tda18271_list_mutex); | ||
925 | |||
926 | if (priv) | ||
927 | hybrid_tuner_release_state(priv); | ||
928 | |||
929 | mutex_unlock(&tda18271_list_mutex); | ||
930 | |||
931 | fe->tuner_priv = NULL; | ||
932 | |||
933 | return 0; | ||
934 | } | ||
935 | |||
936 | static int tda18271_get_frequency(struct dvb_frontend *fe, u32 *frequency) | ||
937 | { | ||
938 | struct tda18271_priv *priv = fe->tuner_priv; | ||
939 | *frequency = priv->frequency; | ||
940 | return 0; | ||
941 | } | ||
942 | |||
943 | static int tda18271_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth) | ||
944 | { | ||
945 | struct tda18271_priv *priv = fe->tuner_priv; | ||
946 | *bandwidth = priv->bandwidth; | ||
947 | return 0; | ||
948 | } | ||
949 | |||
950 | /* ------------------------------------------------------------------ */ | ||
951 | |||
952 | #define tda18271_update_std(std_cfg, name) do { \ | ||
953 | if (map->std_cfg.if_freq + \ | ||
954 | map->std_cfg.agc_mode + map->std_cfg.std + \ | ||
955 | map->std_cfg.if_lvl + map->std_cfg.rfagc_top > 0) { \ | ||
956 | tda_dbg("Using custom std config for %s\n", name); \ | ||
957 | memcpy(&std->std_cfg, &map->std_cfg, \ | ||
958 | sizeof(struct tda18271_std_map_item)); \ | ||
959 | } } while (0) | ||
960 | |||
961 | #define tda18271_dump_std_item(std_cfg, name) do { \ | ||
962 | tda_dbg("(%s) if_freq = %d, agc_mode = %d, std = %d, " \ | ||
963 | "if_lvl = %d, rfagc_top = 0x%02x\n", \ | ||
964 | name, std->std_cfg.if_freq, \ | ||
965 | std->std_cfg.agc_mode, std->std_cfg.std, \ | ||
966 | std->std_cfg.if_lvl, std->std_cfg.rfagc_top); \ | ||
967 | } while (0) | ||
968 | |||
969 | static int tda18271_dump_std_map(struct dvb_frontend *fe) | ||
970 | { | ||
971 | struct tda18271_priv *priv = fe->tuner_priv; | ||
972 | struct tda18271_std_map *std = &priv->std; | ||
973 | |||
974 | tda_dbg("========== STANDARD MAP SETTINGS ==========\n"); | ||
975 | tda18271_dump_std_item(fm_radio, " fm "); | ||
976 | tda18271_dump_std_item(atv_b, "atv b "); | ||
977 | tda18271_dump_std_item(atv_dk, "atv dk"); | ||
978 | tda18271_dump_std_item(atv_gh, "atv gh"); | ||
979 | tda18271_dump_std_item(atv_i, "atv i "); | ||
980 | tda18271_dump_std_item(atv_l, "atv l "); | ||
981 | tda18271_dump_std_item(atv_lc, "atv l'"); | ||
982 | tda18271_dump_std_item(atv_mn, "atv mn"); | ||
983 | tda18271_dump_std_item(atsc_6, "atsc 6"); | ||
984 | tda18271_dump_std_item(dvbt_6, "dvbt 6"); | ||
985 | tda18271_dump_std_item(dvbt_7, "dvbt 7"); | ||
986 | tda18271_dump_std_item(dvbt_8, "dvbt 8"); | ||
987 | tda18271_dump_std_item(qam_6, "qam 6 "); | ||
988 | tda18271_dump_std_item(qam_8, "qam 8 "); | ||
989 | |||
990 | return 0; | ||
991 | } | ||
992 | |||
993 | static int tda18271_update_std_map(struct dvb_frontend *fe, | ||
994 | struct tda18271_std_map *map) | ||
995 | { | ||
996 | struct tda18271_priv *priv = fe->tuner_priv; | ||
997 | struct tda18271_std_map *std = &priv->std; | ||
998 | |||
999 | if (!map) | ||
1000 | return -EINVAL; | ||
1001 | |||
1002 | tda18271_update_std(fm_radio, "fm"); | ||
1003 | tda18271_update_std(atv_b, "atv b"); | ||
1004 | tda18271_update_std(atv_dk, "atv dk"); | ||
1005 | tda18271_update_std(atv_gh, "atv gh"); | ||
1006 | tda18271_update_std(atv_i, "atv i"); | ||
1007 | tda18271_update_std(atv_l, "atv l"); | ||
1008 | tda18271_update_std(atv_lc, "atv l'"); | ||
1009 | tda18271_update_std(atv_mn, "atv mn"); | ||
1010 | tda18271_update_std(atsc_6, "atsc 6"); | ||
1011 | tda18271_update_std(dvbt_6, "dvbt 6"); | ||
1012 | tda18271_update_std(dvbt_7, "dvbt 7"); | ||
1013 | tda18271_update_std(dvbt_8, "dvbt 8"); | ||
1014 | tda18271_update_std(qam_6, "qam 6"); | ||
1015 | tda18271_update_std(qam_8, "qam 8"); | ||
1016 | |||
1017 | return 0; | ||
1018 | } | ||
1019 | |||
1020 | static int tda18271_get_id(struct dvb_frontend *fe) | ||
1021 | { | ||
1022 | struct tda18271_priv *priv = fe->tuner_priv; | ||
1023 | unsigned char *regs = priv->tda18271_regs; | ||
1024 | char *name; | ||
1025 | int ret = 0; | ||
1026 | |||
1027 | mutex_lock(&priv->lock); | ||
1028 | tda18271_read_regs(fe); | ||
1029 | mutex_unlock(&priv->lock); | ||
1030 | |||
1031 | switch (regs[R_ID] & 0x7f) { | ||
1032 | case 3: | ||
1033 | name = "TDA18271HD/C1"; | ||
1034 | priv->id = TDA18271HDC1; | ||
1035 | break; | ||
1036 | case 4: | ||
1037 | name = "TDA18271HD/C2"; | ||
1038 | priv->id = TDA18271HDC2; | ||
1039 | break; | ||
1040 | default: | ||
1041 | name = "Unknown device"; | ||
1042 | ret = -EINVAL; | ||
1043 | break; | ||
1044 | } | ||
1045 | |||
1046 | tda_info("%s detected @ %d-%04x%s\n", name, | ||
1047 | i2c_adapter_id(priv->i2c_props.adap), | ||
1048 | priv->i2c_props.addr, | ||
1049 | (0 == ret) ? "" : ", device not supported."); | ||
1050 | |||
1051 | return ret; | ||
1052 | } | ||
1053 | |||
1054 | static struct dvb_tuner_ops tda18271_tuner_ops = { | ||
1055 | .info = { | ||
1056 | .name = "NXP TDA18271HD", | ||
1057 | .frequency_min = 45000000, | ||
1058 | .frequency_max = 864000000, | ||
1059 | .frequency_step = 62500 | ||
1060 | }, | ||
1061 | .init = tda18271_init, | ||
1062 | .sleep = tda18271_sleep, | ||
1063 | .set_params = tda18271_set_params, | ||
1064 | .set_analog_params = tda18271_set_analog_params, | ||
1065 | .release = tda18271_release, | ||
1066 | .get_frequency = tda18271_get_frequency, | ||
1067 | .get_bandwidth = tda18271_get_bandwidth, | ||
1068 | }; | ||
1069 | |||
1070 | struct dvb_frontend *tda18271_attach(struct dvb_frontend *fe, u8 addr, | ||
1071 | struct i2c_adapter *i2c, | ||
1072 | struct tda18271_config *cfg) | ||
1073 | { | ||
1074 | struct tda18271_priv *priv = NULL; | ||
1075 | int instance; | ||
1076 | |||
1077 | mutex_lock(&tda18271_list_mutex); | ||
1078 | |||
1079 | instance = hybrid_tuner_request_state(struct tda18271_priv, priv, | ||
1080 | hybrid_tuner_instance_list, | ||
1081 | i2c, addr, "tda18271"); | ||
1082 | switch (instance) { | ||
1083 | case 0: | ||
1084 | goto fail; | ||
1085 | break; | ||
1086 | case 1: | ||
1087 | /* new tuner instance */ | ||
1088 | priv->gate = (cfg) ? cfg->gate : TDA18271_GATE_AUTO; | ||
1089 | priv->role = (cfg) ? cfg->role : TDA18271_MASTER; | ||
1090 | priv->cal_initialized = false; | ||
1091 | mutex_init(&priv->lock); | ||
1092 | |||
1093 | fe->tuner_priv = priv; | ||
1094 | |||
1095 | if (cfg) | ||
1096 | priv->small_i2c = cfg->small_i2c; | ||
1097 | |||
1098 | if (tda18271_get_id(fe) < 0) | ||
1099 | goto fail; | ||
1100 | |||
1101 | if (tda18271_assign_map_layout(fe) < 0) | ||
1102 | goto fail; | ||
1103 | |||
1104 | mutex_lock(&priv->lock); | ||
1105 | tda18271_init_regs(fe); | ||
1106 | |||
1107 | if ((tda18271_cal_on_startup) && (priv->id == TDA18271HDC2)) | ||
1108 | tda18271c2_rf_cal_init(fe); | ||
1109 | |||
1110 | mutex_unlock(&priv->lock); | ||
1111 | break; | ||
1112 | default: | ||
1113 | /* existing tuner instance */ | ||
1114 | fe->tuner_priv = priv; | ||
1115 | |||
1116 | /* allow dvb driver to override i2c gate setting */ | ||
1117 | if ((cfg) && (cfg->gate != TDA18271_GATE_ANALOG)) | ||
1118 | priv->gate = cfg->gate; | ||
1119 | break; | ||
1120 | } | ||
1121 | |||
1122 | /* override default std map with values in config struct */ | ||
1123 | if ((cfg) && (cfg->std_map)) | ||
1124 | tda18271_update_std_map(fe, cfg->std_map); | ||
1125 | |||
1126 | mutex_unlock(&tda18271_list_mutex); | ||
1127 | |||
1128 | memcpy(&fe->ops.tuner_ops, &tda18271_tuner_ops, | ||
1129 | sizeof(struct dvb_tuner_ops)); | ||
1130 | |||
1131 | if (tda18271_debug & (DBG_MAP | DBG_ADV)) | ||
1132 | tda18271_dump_std_map(fe); | ||
1133 | |||
1134 | return fe; | ||
1135 | fail: | ||
1136 | mutex_unlock(&tda18271_list_mutex); | ||
1137 | |||
1138 | tda18271_release(fe); | ||
1139 | return NULL; | ||
1140 | } | ||
1141 | EXPORT_SYMBOL_GPL(tda18271_attach); | ||
1142 | MODULE_DESCRIPTION("NXP TDA18271HD analog / digital tuner driver"); | ||
1143 | MODULE_AUTHOR("Michael Krufky <mkrufky@linuxtv.org>"); | ||
1144 | MODULE_LICENSE("GPL"); | ||
1145 | MODULE_VERSION("0.3"); | ||
1146 | |||
1147 | /* | ||
1148 | * Overrides for Emacs so that we follow Linus's tabbing style. | ||
1149 | * --------------------------------------------------------------------------- | ||
1150 | * Local variables: | ||
1151 | * c-basic-offset: 8 | ||
1152 | * End: | ||
1153 | */ | ||