diff options
Diffstat (limited to 'drivers/media/dvb/frontends/dib0090.c')
-rw-r--r-- | drivers/media/dvb/frontends/dib0090.c | 1525 |
1 files changed, 1525 insertions, 0 deletions
diff --git a/drivers/media/dvb/frontends/dib0090.c b/drivers/media/dvb/frontends/dib0090.c new file mode 100644 index 000000000000..e37d32dbd5c5 --- /dev/null +++ b/drivers/media/dvb/frontends/dib0090.c | |||
@@ -0,0 +1,1525 @@ | |||
1 | /* | ||
2 | * Linux-DVB Driver for DiBcom's DiB0090 base-band RF Tuner. | ||
3 | * | ||
4 | * Copyright (C) 2005-9 DiBcom (http://www.dibcom.fr/) | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or | ||
7 | * modify it under the terms of the GNU General Public License as | ||
8 | * published by the Free Software Foundation; either version 2 of the | ||
9 | * License, or (at your option) any later version. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, but | ||
12 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * | ||
15 | * GNU General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program; if not, write to the Free Software | ||
19 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
20 | * | ||
21 | * | ||
22 | * This code is more or less generated from another driver, please | ||
23 | * excuse some codingstyle oddities. | ||
24 | * | ||
25 | */ | ||
26 | |||
27 | #include <linux/kernel.h> | ||
28 | #include <linux/i2c.h> | ||
29 | |||
30 | #include "dvb_frontend.h" | ||
31 | |||
32 | #include "dib0090.h" | ||
33 | #include "dibx000_common.h" | ||
34 | |||
35 | static int debug; | ||
36 | module_param(debug, int, 0644); | ||
37 | MODULE_PARM_DESC(debug, "turn on debugging (default: 0)"); | ||
38 | |||
39 | #define dprintk(args...) do { \ | ||
40 | if (debug) { \ | ||
41 | printk(KERN_DEBUG "DiB0090: "); \ | ||
42 | printk(args); \ | ||
43 | printk("\n"); \ | ||
44 | } \ | ||
45 | } while (0) | ||
46 | |||
47 | #define CONFIG_SYS_ISDBT | ||
48 | #define CONFIG_BAND_CBAND | ||
49 | #define CONFIG_BAND_VHF | ||
50 | #define CONFIG_BAND_UHF | ||
51 | #define CONFIG_DIB0090_USE_PWM_AGC | ||
52 | |||
53 | #define EN_LNA0 0x8000 | ||
54 | #define EN_LNA1 0x4000 | ||
55 | #define EN_LNA2 0x2000 | ||
56 | #define EN_LNA3 0x1000 | ||
57 | #define EN_MIX0 0x0800 | ||
58 | #define EN_MIX1 0x0400 | ||
59 | #define EN_MIX2 0x0200 | ||
60 | #define EN_MIX3 0x0100 | ||
61 | #define EN_IQADC 0x0040 | ||
62 | #define EN_PLL 0x0020 | ||
63 | #define EN_TX 0x0010 | ||
64 | #define EN_BB 0x0008 | ||
65 | #define EN_LO 0x0004 | ||
66 | #define EN_BIAS 0x0001 | ||
67 | |||
68 | #define EN_IQANA 0x0002 | ||
69 | #define EN_DIGCLK 0x0080 /* not in the 0x24 reg, only in 0x1b */ | ||
70 | #define EN_CRYSTAL 0x0002 | ||
71 | |||
72 | #define EN_UHF 0x22E9 | ||
73 | #define EN_VHF 0x44E9 | ||
74 | #define EN_LBD 0x11E9 | ||
75 | #define EN_SBD 0x44E9 | ||
76 | #define EN_CAB 0x88E9 | ||
77 | |||
78 | #define pgm_read_word(w) (*w) | ||
79 | |||
80 | struct dc_calibration; | ||
81 | |||
82 | struct dib0090_tuning { | ||
83 | u32 max_freq; /* for every frequency less than or equal to that field: this information is correct */ | ||
84 | u8 switch_trim; | ||
85 | u8 lna_tune; | ||
86 | u8 lna_bias; | ||
87 | u16 v2i; | ||
88 | u16 mix; | ||
89 | u16 load; | ||
90 | u16 tuner_enable; | ||
91 | }; | ||
92 | |||
93 | struct dib0090_pll { | ||
94 | u32 max_freq; /* for every frequency less than or equal to that field: this information is correct */ | ||
95 | u8 vco_band; | ||
96 | u8 hfdiv_code; | ||
97 | u8 hfdiv; | ||
98 | u8 topresc; | ||
99 | }; | ||
100 | |||
101 | struct dib0090_state { | ||
102 | struct i2c_adapter *i2c; | ||
103 | struct dvb_frontend *fe; | ||
104 | const struct dib0090_config *config; | ||
105 | |||
106 | u8 current_band; | ||
107 | u16 revision; | ||
108 | enum frontend_tune_state tune_state; | ||
109 | u32 current_rf; | ||
110 | |||
111 | u16 wbd_offset; | ||
112 | s16 wbd_target; /* in dB */ | ||
113 | |||
114 | s16 rf_gain_limit; /* take-over-point: where to split between bb and rf gain */ | ||
115 | s16 current_gain; /* keeps the currently programmed gain */ | ||
116 | u8 agc_step; /* new binary search */ | ||
117 | |||
118 | u16 gain[2]; /* for channel monitoring */ | ||
119 | |||
120 | const u16 *rf_ramp; | ||
121 | const u16 *bb_ramp; | ||
122 | |||
123 | /* for the software AGC ramps */ | ||
124 | u16 bb_1_def; | ||
125 | u16 rf_lt_def; | ||
126 | u16 gain_reg[4]; | ||
127 | |||
128 | /* for the captrim/dc-offset search */ | ||
129 | s8 step; | ||
130 | s16 adc_diff; | ||
131 | s16 min_adc_diff; | ||
132 | |||
133 | s8 captrim; | ||
134 | s8 fcaptrim; | ||
135 | |||
136 | const struct dc_calibration *dc; | ||
137 | u16 bb6, bb7; | ||
138 | |||
139 | const struct dib0090_tuning *current_tune_table_index; | ||
140 | const struct dib0090_pll *current_pll_table_index; | ||
141 | |||
142 | u8 tuner_is_tuned; | ||
143 | u8 agc_freeze; | ||
144 | |||
145 | u8 reset; | ||
146 | }; | ||
147 | |||
148 | static u16 dib0090_read_reg(struct dib0090_state *state, u8 reg) | ||
149 | { | ||
150 | u8 b[2]; | ||
151 | struct i2c_msg msg[2] = { | ||
152 | {.addr = state->config->i2c_address,.flags = 0,.buf = ®,.len = 1}, | ||
153 | {.addr = state->config->i2c_address,.flags = I2C_M_RD,.buf = b,.len = 2}, | ||
154 | }; | ||
155 | if (i2c_transfer(state->i2c, msg, 2) != 2) { | ||
156 | printk(KERN_WARNING "DiB0090 I2C read failed\n"); | ||
157 | return 0; | ||
158 | } | ||
159 | return (b[0] << 8) | b[1]; | ||
160 | } | ||
161 | |||
162 | static int dib0090_write_reg(struct dib0090_state *state, u32 reg, u16 val) | ||
163 | { | ||
164 | u8 b[3] = { reg & 0xff, val >> 8, val & 0xff }; | ||
165 | struct i2c_msg msg = {.addr = state->config->i2c_address,.flags = 0,.buf = b,.len = 3 }; | ||
166 | if (i2c_transfer(state->i2c, &msg, 1) != 1) { | ||
167 | printk(KERN_WARNING "DiB0090 I2C write failed\n"); | ||
168 | return -EREMOTEIO; | ||
169 | } | ||
170 | return 0; | ||
171 | } | ||
172 | |||
173 | #define HARD_RESET(state) do { if (cfg->reset) { if (cfg->sleep) cfg->sleep(fe, 0); msleep(10); cfg->reset(fe, 1); msleep(10); cfg->reset(fe, 0); msleep(10); } } while (0) | ||
174 | #define ADC_TARGET -220 | ||
175 | #define GAIN_ALPHA 5 | ||
176 | #define WBD_ALPHA 6 | ||
177 | #define LPF 100 | ||
178 | static void dib0090_write_regs(struct dib0090_state *state, u8 r, const u16 * b, u8 c) | ||
179 | { | ||
180 | do { | ||
181 | dib0090_write_reg(state, r++, *b++); | ||
182 | } while (--c); | ||
183 | } | ||
184 | |||
185 | static u16 dib0090_identify(struct dvb_frontend *fe) | ||
186 | { | ||
187 | struct dib0090_state *state = fe->tuner_priv; | ||
188 | u16 v; | ||
189 | |||
190 | v = dib0090_read_reg(state, 0x1a); | ||
191 | |||
192 | #ifdef FIRMWARE_FIREFLY | ||
193 | /* pll is not locked locked */ | ||
194 | if (!(v & 0x800)) | ||
195 | dprintk("FE%d : Identification : pll is not yet locked", fe->id); | ||
196 | #endif | ||
197 | |||
198 | /* without PLL lock info */ | ||
199 | v &= 0x3ff; | ||
200 | dprintk("P/V: %04x:", v); | ||
201 | |||
202 | if ((v >> 8) & 0xf) | ||
203 | dprintk("FE%d : Product ID = 0x%x : KROSUS", fe->id, (v >> 8) & 0xf); | ||
204 | else | ||
205 | return 0xff; | ||
206 | |||
207 | v &= 0xff; | ||
208 | if (((v >> 5) & 0x7) == 0x1) | ||
209 | dprintk("FE%d : MP001 : 9090/8096", fe->id); | ||
210 | else if (((v >> 5) & 0x7) == 0x4) | ||
211 | dprintk("FE%d : MP005 : Single Sband", fe->id); | ||
212 | else if (((v >> 5) & 0x7) == 0x6) | ||
213 | dprintk("FE%d : MP008 : diversity VHF-UHF-LBAND", fe->id); | ||
214 | else if (((v >> 5) & 0x7) == 0x7) | ||
215 | dprintk("FE%d : MP009 : diversity 29098 CBAND-UHF-LBAND-SBAND", fe->id); | ||
216 | else | ||
217 | return 0xff; | ||
218 | |||
219 | /* revision only */ | ||
220 | if ((v & 0x1f) == 0x3) | ||
221 | dprintk("FE%d : P1-D/E/F detected", fe->id); | ||
222 | else if ((v & 0x1f) == 0x1) | ||
223 | dprintk("FE%d : P1C detected", fe->id); | ||
224 | else if ((v & 0x1f) == 0x0) { | ||
225 | #ifdef CONFIG_TUNER_DIB0090_P1B_SUPPORT | ||
226 | dprintk("FE%d : P1-A/B detected: using previous driver - support will be removed soon", fe->id); | ||
227 | dib0090_p1b_register(fe); | ||
228 | #else | ||
229 | dprintk("FE%d : P1-A/B detected: driver is deactivated - not available", fe->id); | ||
230 | return 0xff; | ||
231 | #endif | ||
232 | } | ||
233 | |||
234 | return v; | ||
235 | } | ||
236 | |||
237 | static void dib0090_reset_digital(struct dvb_frontend *fe, const struct dib0090_config *cfg) | ||
238 | { | ||
239 | struct dib0090_state *state = fe->tuner_priv; | ||
240 | |||
241 | HARD_RESET(state); | ||
242 | |||
243 | dib0090_write_reg(state, 0x24, EN_PLL); | ||
244 | dib0090_write_reg(state, 0x1b, EN_DIGCLK | EN_PLL | EN_CRYSTAL); /* PLL, DIG_CLK and CRYSTAL remain */ | ||
245 | |||
246 | /* adcClkOutRatio=8->7, release reset */ | ||
247 | dib0090_write_reg(state, 0x20, ((cfg->io.adc_clock_ratio - 1) << 11) | (0 << 10) | (1 << 9) | (1 << 8) | (0 << 4) | 0); | ||
248 | if (cfg->clkoutdrive != 0) | ||
249 | dib0090_write_reg(state, 0x23, | ||
250 | (0 << 15) | ((!cfg->analog_output) << 14) | (1 << 10) | (1 << 9) | (0 << 8) | (cfg->clkoutdrive << 5) | (cfg-> | ||
251 | clkouttobamse | ||
252 | << 4) | (0 | ||
253 | << | ||
254 | 2) | ||
255 | | (0)); | ||
256 | else | ||
257 | dib0090_write_reg(state, 0x23, | ||
258 | (0 << 15) | ((!cfg->analog_output) << 14) | (1 << 10) | (1 << 9) | (0 << 8) | (7 << 5) | (cfg-> | ||
259 | clkouttobamse << 4) | (0 | ||
260 | << | ||
261 | 2) | ||
262 | | (0)); | ||
263 | |||
264 | /* enable pll, de-activate reset, ratio: 2/1 = 60MHz */ | ||
265 | dib0090_write_reg(state, 0x21, | ||
266 | (cfg->io.pll_bypass << 15) | (1 << 13) | (cfg->io.pll_range << 12) | (cfg->io.pll_loopdiv << 6) | (cfg->io.pll_prediv)); | ||
267 | |||
268 | } | ||
269 | |||
270 | static int dib0090_wakeup(struct dvb_frontend *fe) | ||
271 | { | ||
272 | struct dib0090_state *state = fe->tuner_priv; | ||
273 | if (state->config->sleep) | ||
274 | state->config->sleep(fe, 0); | ||
275 | return 0; | ||
276 | } | ||
277 | |||
278 | static int dib0090_sleep(struct dvb_frontend *fe) | ||
279 | { | ||
280 | struct dib0090_state *state = fe->tuner_priv; | ||
281 | if (state->config->sleep) | ||
282 | state->config->sleep(fe, 1); | ||
283 | return 0; | ||
284 | } | ||
285 | |||
286 | extern void dib0090_dcc_freq(struct dvb_frontend *fe, u8 fast) | ||
287 | { | ||
288 | struct dib0090_state *state = fe->tuner_priv; | ||
289 | if (fast) | ||
290 | dib0090_write_reg(state, 0x04, 0); //1kHz | ||
291 | else | ||
292 | dib0090_write_reg(state, 0x04, 1); //almost frozen | ||
293 | } | ||
294 | |||
295 | EXPORT_SYMBOL(dib0090_dcc_freq); | ||
296 | static const u16 rf_ramp_pwm_cband[] = { | ||
297 | 0, /* max RF gain in 10th of dB */ | ||
298 | 0, /* ramp_slope = 1dB of gain -> clock_ticks_per_db = clk_khz / ramp_slope -> 0x2b */ | ||
299 | 0, /* ramp_max = maximum X used on the ramp */ | ||
300 | (0 << 10) | 0, /* 0x2c, LNA 1 = 0dB */ | ||
301 | (0 << 10) | 0, /* 0x2d, LNA 1 */ | ||
302 | (0 << 10) | 0, /* 0x2e, LNA 2 = 0dB */ | ||
303 | (0 << 10) | 0, /* 0x2f, LNA 2 */ | ||
304 | (0 << 10) | 0, /* 0x30, LNA 3 = 0dB */ | ||
305 | (0 << 10) | 0, /* 0x31, LNA 3 */ | ||
306 | (0 << 10) | 0, /* GAIN_4_1, LNA 4 = 0dB */ | ||
307 | (0 << 10) | 0, /* GAIN_4_2, LNA 4 */ | ||
308 | }; | ||
309 | |||
310 | static const u16 rf_ramp_vhf[] = { | ||
311 | 412, /* max RF gain in 10th of dB */ | ||
312 | 132, 307, 127, /* LNA1, 13.2dB */ | ||
313 | 105, 412, 255, /* LNA2, 10.5dB */ | ||
314 | 50, 50, 127, /* LNA3, 5dB */ | ||
315 | 125, 175, 127, /* LNA4, 12.5dB */ | ||
316 | 0, 0, 127, /* CBAND, 0dB */ | ||
317 | }; | ||
318 | |||
319 | static const u16 rf_ramp_uhf[] = { | ||
320 | 412, /* max RF gain in 10th of dB */ | ||
321 | 132, 307, 127, /* LNA1 : total gain = 13.2dB, point on the ramp where this amp is full gain, value to write to get full gain */ | ||
322 | 105, 412, 255, /* LNA2 : 10.5 dB */ | ||
323 | 50, 50, 127, /* LNA3 : 5.0 dB */ | ||
324 | 125, 175, 127, /* LNA4 : 12.5 dB */ | ||
325 | 0, 0, 127, /* CBAND : 0.0 dB */ | ||
326 | }; | ||
327 | |||
328 | static const u16 rf_ramp_cband[] = { | ||
329 | 332, /* max RF gain in 10th of dB */ | ||
330 | 132, 252, 127, /* LNA1, dB */ | ||
331 | 80, 332, 255, /* LNA2, dB */ | ||
332 | 0, 0, 127, /* LNA3, dB */ | ||
333 | 0, 0, 127, /* LNA4, dB */ | ||
334 | 120, 120, 127, /* LT1 CBAND */ | ||
335 | }; | ||
336 | |||
337 | static const u16 rf_ramp_pwm_vhf[] = { | ||
338 | 404, /* max RF gain in 10th of dB */ | ||
339 | 25, /* ramp_slope = 1dB of gain -> clock_ticks_per_db = clk_khz / ramp_slope -> 0x2b */ | ||
340 | 1011, /* ramp_max = maximum X used on the ramp */ | ||
341 | (6 << 10) | 417, /* 0x2c, LNA 1 = 13.2dB */ | ||
342 | (0 << 10) | 756, /* 0x2d, LNA 1 */ | ||
343 | (16 << 10) | 756, /* 0x2e, LNA 2 = 10.5dB */ | ||
344 | (0 << 10) | 1011, /* 0x2f, LNA 2 */ | ||
345 | (16 << 10) | 290, /* 0x30, LNA 3 = 5dB */ | ||
346 | (0 << 10) | 417, /* 0x31, LNA 3 */ | ||
347 | (7 << 10) | 0, /* GAIN_4_1, LNA 4 = 12.5dB */ | ||
348 | (0 << 10) | 290, /* GAIN_4_2, LNA 4 */ | ||
349 | }; | ||
350 | |||
351 | static const u16 rf_ramp_pwm_uhf[] = { | ||
352 | 404, /* max RF gain in 10th of dB */ | ||
353 | 25, /* ramp_slope = 1dB of gain -> clock_ticks_per_db = clk_khz / ramp_slope -> 0x2b */ | ||
354 | 1011, /* ramp_max = maximum X used on the ramp */ | ||
355 | (6 << 10) | 417, /* 0x2c, LNA 1 = 13.2dB */ | ||
356 | (0 << 10) | 756, /* 0x2d, LNA 1 */ | ||
357 | (16 << 10) | 756, /* 0x2e, LNA 2 = 10.5dB */ | ||
358 | (0 << 10) | 1011, /* 0x2f, LNA 2 */ | ||
359 | (16 << 10) | 0, /* 0x30, LNA 3 = 5dB */ | ||
360 | (0 << 10) | 127, /* 0x31, LNA 3 */ | ||
361 | (7 << 10) | 127, /* GAIN_4_1, LNA 4 = 12.5dB */ | ||
362 | (0 << 10) | 417, /* GAIN_4_2, LNA 4 */ | ||
363 | }; | ||
364 | |||
365 | static const u16 bb_ramp_boost[] = { | ||
366 | 550, /* max BB gain in 10th of dB */ | ||
367 | 260, 260, 26, /* BB1, 26dB */ | ||
368 | 290, 550, 29, /* BB2, 29dB */ | ||
369 | }; | ||
370 | |||
371 | static const u16 bb_ramp_pwm_normal[] = { | ||
372 | 500, /* max RF gain in 10th of dB */ | ||
373 | 8, /* ramp_slope = 1dB of gain -> clock_ticks_per_db = clk_khz / ramp_slope -> 0x34 */ | ||
374 | 400, | ||
375 | (2 << 9) | 0, /* 0x35 = 21dB */ | ||
376 | (0 << 9) | 168, /* 0x36 */ | ||
377 | (2 << 9) | 168, /* 0x37 = 29dB */ | ||
378 | (0 << 9) | 400, /* 0x38 */ | ||
379 | }; | ||
380 | |||
381 | struct slope { | ||
382 | int16_t range; | ||
383 | int16_t slope; | ||
384 | }; | ||
385 | static u16 slopes_to_scale(const struct slope *slopes, u8 num, s16 val) | ||
386 | { | ||
387 | u8 i; | ||
388 | u16 rest; | ||
389 | u16 ret = 0; | ||
390 | for (i = 0; i < num; i++) { | ||
391 | if (val > slopes[i].range) | ||
392 | rest = slopes[i].range; | ||
393 | else | ||
394 | rest = val; | ||
395 | ret += (rest * slopes[i].slope) / slopes[i].range; | ||
396 | val -= rest; | ||
397 | } | ||
398 | return ret; | ||
399 | } | ||
400 | |||
401 | static const struct slope dib0090_wbd_slopes[3] = { | ||
402 | {66, 120}, /* -64,-52: offset - 65 */ | ||
403 | {600, 170}, /* -52,-35: 65 - 665 */ | ||
404 | {170, 250}, /* -45,-10: 665 - 835 */ | ||
405 | }; | ||
406 | |||
407 | static s16 dib0090_wbd_to_db(struct dib0090_state *state, u16 wbd) | ||
408 | { | ||
409 | wbd &= 0x3ff; | ||
410 | if (wbd < state->wbd_offset) | ||
411 | wbd = 0; | ||
412 | else | ||
413 | wbd -= state->wbd_offset; | ||
414 | /* -64dB is the floor */ | ||
415 | return -640 + (s16) slopes_to_scale(dib0090_wbd_slopes, ARRAY_SIZE(dib0090_wbd_slopes), wbd); | ||
416 | } | ||
417 | |||
418 | static void dib0090_wbd_target(struct dib0090_state *state, u32 rf) | ||
419 | { | ||
420 | u16 offset = 250; | ||
421 | |||
422 | /* TODO : DAB digital N+/-1 interferer perfs : offset = 10 */ | ||
423 | |||
424 | if (state->current_band == BAND_VHF) | ||
425 | offset = 650; | ||
426 | #ifndef FIRMWARE_FIREFLY | ||
427 | if (state->current_band == BAND_VHF) | ||
428 | offset = state->config->wbd_vhf_offset; | ||
429 | if (state->current_band == BAND_CBAND) | ||
430 | offset = state->config->wbd_cband_offset; | ||
431 | #endif | ||
432 | |||
433 | state->wbd_target = dib0090_wbd_to_db(state, state->wbd_offset + offset); | ||
434 | dprintk("wbd-target: %d dB", (u32) state->wbd_target); | ||
435 | } | ||
436 | |||
437 | static const int gain_reg_addr[4] = { | ||
438 | 0x08, 0x0a, 0x0f, 0x01 | ||
439 | }; | ||
440 | |||
441 | static void dib0090_gain_apply(struct dib0090_state *state, s16 gain_delta, s16 top_delta, u8 force) | ||
442 | { | ||
443 | u16 rf, bb, ref; | ||
444 | u16 i, v, gain_reg[4] = { 0 }, gain; | ||
445 | const u16 *g; | ||
446 | |||
447 | if (top_delta < -511) | ||
448 | top_delta = -511; | ||
449 | if (top_delta > 511) | ||
450 | top_delta = 511; | ||
451 | |||
452 | if (force) { | ||
453 | top_delta *= (1 << WBD_ALPHA); | ||
454 | gain_delta *= (1 << GAIN_ALPHA); | ||
455 | } | ||
456 | |||
457 | if (top_delta >= ((s16) (state->rf_ramp[0] << WBD_ALPHA) - state->rf_gain_limit)) /* overflow */ | ||
458 | state->rf_gain_limit = state->rf_ramp[0] << WBD_ALPHA; | ||
459 | else | ||
460 | state->rf_gain_limit += top_delta; | ||
461 | |||
462 | if (state->rf_gain_limit < 0) /*underflow */ | ||
463 | state->rf_gain_limit = 0; | ||
464 | |||
465 | /* use gain as a temporary variable and correct current_gain */ | ||
466 | gain = ((state->rf_gain_limit >> WBD_ALPHA) + state->bb_ramp[0]) << GAIN_ALPHA; | ||
467 | if (gain_delta >= ((s16) gain - state->current_gain)) /* overflow */ | ||
468 | state->current_gain = gain; | ||
469 | else | ||
470 | state->current_gain += gain_delta; | ||
471 | /* cannot be less than 0 (only if gain_delta is less than 0 we can have current_gain < 0) */ | ||
472 | if (state->current_gain < 0) | ||
473 | state->current_gain = 0; | ||
474 | |||
475 | /* now split total gain to rf and bb gain */ | ||
476 | gain = state->current_gain >> GAIN_ALPHA; | ||
477 | |||
478 | /* requested gain is bigger than rf gain limit - ACI/WBD adjustment */ | ||
479 | if (gain > (state->rf_gain_limit >> WBD_ALPHA)) { | ||
480 | rf = state->rf_gain_limit >> WBD_ALPHA; | ||
481 | bb = gain - rf; | ||
482 | if (bb > state->bb_ramp[0]) | ||
483 | bb = state->bb_ramp[0]; | ||
484 | } else { /* high signal level -> all gains put on RF */ | ||
485 | rf = gain; | ||
486 | bb = 0; | ||
487 | } | ||
488 | |||
489 | state->gain[0] = rf; | ||
490 | state->gain[1] = bb; | ||
491 | |||
492 | /* software ramp */ | ||
493 | /* Start with RF gains */ | ||
494 | g = state->rf_ramp + 1; /* point on RF LNA1 max gain */ | ||
495 | ref = rf; | ||
496 | for (i = 0; i < 7; i++) { /* Go over all amplifiers => 5RF amps + 2 BB amps = 7 amps */ | ||
497 | if (g[0] == 0 || ref < (g[1] - g[0])) /* if total gain of the current amp is null or this amp is not concerned because it starts to work from an higher gain value */ | ||
498 | v = 0; /* force the gain to write for the current amp to be null */ | ||
499 | else if (ref >= g[1]) /* Gain to set is higher than the high working point of this amp */ | ||
500 | v = g[2]; /* force this amp to be full gain */ | ||
501 | else /* compute the value to set to this amp because we are somewhere in his range */ | ||
502 | v = ((ref - (g[1] - g[0])) * g[2]) / g[0]; | ||
503 | |||
504 | if (i == 0) /* LNA 1 reg mapping */ | ||
505 | gain_reg[0] = v; | ||
506 | else if (i == 1) /* LNA 2 reg mapping */ | ||
507 | gain_reg[0] |= v << 7; | ||
508 | else if (i == 2) /* LNA 3 reg mapping */ | ||
509 | gain_reg[1] = v; | ||
510 | else if (i == 3) /* LNA 4 reg mapping */ | ||
511 | gain_reg[1] |= v << 7; | ||
512 | else if (i == 4) /* CBAND LNA reg mapping */ | ||
513 | gain_reg[2] = v | state->rf_lt_def; | ||
514 | else if (i == 5) /* BB gain 1 reg mapping */ | ||
515 | gain_reg[3] = v << 3; | ||
516 | else if (i == 6) /* BB gain 2 reg mapping */ | ||
517 | gain_reg[3] |= v << 8; | ||
518 | |||
519 | g += 3; /* go to next gain bloc */ | ||
520 | |||
521 | /* When RF is finished, start with BB */ | ||
522 | if (i == 4) { | ||
523 | g = state->bb_ramp + 1; /* point on BB gain 1 max gain */ | ||
524 | ref = bb; | ||
525 | } | ||
526 | } | ||
527 | gain_reg[3] |= state->bb_1_def; | ||
528 | gain_reg[3] |= ((bb % 10) * 100) / 125; | ||
529 | |||
530 | #ifdef DEBUG_AGC | ||
531 | dprintk("GA CALC: DB: %3d(rf) + %3d(bb) = %3d gain_reg[0]=%04x gain_reg[1]=%04x gain_reg[2]=%04x gain_reg[0]=%04x", rf, bb, rf + bb, | ||
532 | gain_reg[0], gain_reg[1], gain_reg[2], gain_reg[3]); | ||
533 | #endif | ||
534 | |||
535 | /* Write the amplifier regs */ | ||
536 | for (i = 0; i < 4; i++) { | ||
537 | v = gain_reg[i]; | ||
538 | if (force || state->gain_reg[i] != v) { | ||
539 | state->gain_reg[i] = v; | ||
540 | dib0090_write_reg(state, gain_reg_addr[i], v); | ||
541 | } | ||
542 | } | ||
543 | } | ||
544 | |||
545 | static void dib0090_set_boost(struct dib0090_state *state, int onoff) | ||
546 | { | ||
547 | state->bb_1_def &= 0xdfff; | ||
548 | state->bb_1_def |= onoff << 13; | ||
549 | } | ||
550 | |||
551 | static void dib0090_set_rframp(struct dib0090_state *state, const u16 * cfg) | ||
552 | { | ||
553 | state->rf_ramp = cfg; | ||
554 | } | ||
555 | |||
556 | static void dib0090_set_rframp_pwm(struct dib0090_state *state, const u16 * cfg) | ||
557 | { | ||
558 | state->rf_ramp = cfg; | ||
559 | |||
560 | dib0090_write_reg(state, 0x2a, 0xffff); | ||
561 | |||
562 | dprintk("total RF gain: %ddB, step: %d", (u32) cfg[0], dib0090_read_reg(state, 0x2a)); | ||
563 | |||
564 | dib0090_write_regs(state, 0x2c, cfg + 3, 6); | ||
565 | dib0090_write_regs(state, 0x3e, cfg + 9, 2); | ||
566 | } | ||
567 | |||
568 | static void dib0090_set_bbramp(struct dib0090_state *state, const u16 * cfg) | ||
569 | { | ||
570 | state->bb_ramp = cfg; | ||
571 | dib0090_set_boost(state, cfg[0] > 500); /* we want the boost if the gain is higher that 50dB */ | ||
572 | } | ||
573 | |||
574 | static void dib0090_set_bbramp_pwm(struct dib0090_state *state, const u16 * cfg) | ||
575 | { | ||
576 | state->bb_ramp = cfg; | ||
577 | |||
578 | dib0090_set_boost(state, cfg[0] > 500); /* we want the boost if the gain is higher that 50dB */ | ||
579 | |||
580 | dib0090_write_reg(state, 0x33, 0xffff); | ||
581 | dprintk("total BB gain: %ddB, step: %d", (u32) cfg[0], dib0090_read_reg(state, 0x33)); | ||
582 | dib0090_write_regs(state, 0x35, cfg + 3, 4); | ||
583 | } | ||
584 | |||
585 | void dib0090_pwm_gain_reset(struct dvb_frontend *fe) | ||
586 | { | ||
587 | struct dib0090_state *state = fe->tuner_priv; | ||
588 | /* reset the AGC */ | ||
589 | |||
590 | if (state->config->use_pwm_agc) { | ||
591 | #ifdef CONFIG_BAND_SBAND | ||
592 | if (state->current_band == BAND_SBAND) { | ||
593 | dib0090_set_rframp_pwm(state, rf_ramp_pwm_sband); | ||
594 | dib0090_set_bbramp_pwm(state, bb_ramp_pwm_boost); | ||
595 | } else | ||
596 | #endif | ||
597 | #ifdef CONFIG_BAND_CBAND | ||
598 | if (state->current_band == BAND_CBAND) { | ||
599 | dib0090_set_rframp_pwm(state, rf_ramp_pwm_cband); | ||
600 | dib0090_set_bbramp_pwm(state, bb_ramp_pwm_normal); | ||
601 | } else | ||
602 | #endif | ||
603 | #ifdef CONFIG_BAND_VHF | ||
604 | if (state->current_band == BAND_VHF) { | ||
605 | dib0090_set_rframp_pwm(state, rf_ramp_pwm_vhf); | ||
606 | dib0090_set_bbramp_pwm(state, bb_ramp_pwm_normal); | ||
607 | } else | ||
608 | #endif | ||
609 | { | ||
610 | dib0090_set_rframp_pwm(state, rf_ramp_pwm_uhf); | ||
611 | dib0090_set_bbramp_pwm(state, bb_ramp_pwm_normal); | ||
612 | } | ||
613 | |||
614 | if (state->rf_ramp[0] != 0) | ||
615 | dib0090_write_reg(state, 0x32, (3 << 11)); | ||
616 | else | ||
617 | dib0090_write_reg(state, 0x32, (0 << 11)); | ||
618 | |||
619 | dib0090_write_reg(state, 0x39, (1 << 10)); // 0 gain by default | ||
620 | } | ||
621 | } | ||
622 | |||
623 | EXPORT_SYMBOL(dib0090_pwm_gain_reset); | ||
624 | int dib0090_gain_control(struct dvb_frontend *fe) | ||
625 | { | ||
626 | struct dib0090_state *state = fe->tuner_priv; | ||
627 | enum frontend_tune_state *tune_state = &state->tune_state; | ||
628 | int ret = 10; | ||
629 | |||
630 | u16 wbd_val = 0; | ||
631 | u8 apply_gain_immediatly = 1; | ||
632 | s16 wbd_error = 0, adc_error = 0; | ||
633 | |||
634 | if (*tune_state == CT_AGC_START) { | ||
635 | state->agc_freeze = 0; | ||
636 | dib0090_write_reg(state, 0x04, 0x0); | ||
637 | |||
638 | #ifdef CONFIG_BAND_SBAND | ||
639 | if (state->current_band == BAND_SBAND) { | ||
640 | dib0090_set_rframp(state, rf_ramp_sband); | ||
641 | dib0090_set_bbramp(state, bb_ramp_boost); | ||
642 | } else | ||
643 | #endif | ||
644 | #ifdef CONFIG_BAND_VHF | ||
645 | if (state->current_band == BAND_VHF) { | ||
646 | dib0090_set_rframp(state, rf_ramp_vhf); | ||
647 | dib0090_set_bbramp(state, bb_ramp_boost); | ||
648 | } else | ||
649 | #endif | ||
650 | #ifdef CONFIG_BAND_CBAND | ||
651 | if (state->current_band == BAND_CBAND) { | ||
652 | dib0090_set_rframp(state, rf_ramp_cband); | ||
653 | dib0090_set_bbramp(state, bb_ramp_boost); | ||
654 | } else | ||
655 | #endif | ||
656 | { | ||
657 | dib0090_set_rframp(state, rf_ramp_uhf); | ||
658 | dib0090_set_bbramp(state, bb_ramp_boost); | ||
659 | } | ||
660 | |||
661 | dib0090_write_reg(state, 0x32, 0); | ||
662 | dib0090_write_reg(state, 0x39, 0); | ||
663 | |||
664 | dib0090_wbd_target(state, state->current_rf); | ||
665 | |||
666 | state->rf_gain_limit = state->rf_ramp[0] << WBD_ALPHA; | ||
667 | state->current_gain = ((state->rf_ramp[0] + state->bb_ramp[0]) / 2) << GAIN_ALPHA; | ||
668 | |||
669 | *tune_state = CT_AGC_STEP_0; | ||
670 | } else if (!state->agc_freeze) { | ||
671 | s16 wbd; | ||
672 | |||
673 | int adc; | ||
674 | wbd_val = dib0090_read_reg(state, 0x1d); | ||
675 | |||
676 | /* read and calc the wbd power */ | ||
677 | wbd = dib0090_wbd_to_db(state, wbd_val); | ||
678 | wbd_error = state->wbd_target - wbd; | ||
679 | |||
680 | if (*tune_state == CT_AGC_STEP_0) { | ||
681 | if (wbd_error < 0 && state->rf_gain_limit > 0) { | ||
682 | #ifdef CONFIG_BAND_CBAND | ||
683 | /* in case of CBAND tune reduce first the lt_gain2 before adjusting the RF gain */ | ||
684 | u8 ltg2 = (state->rf_lt_def >> 10) & 0x7; | ||
685 | if (state->current_band == BAND_CBAND && ltg2) { | ||
686 | ltg2 >>= 1; | ||
687 | state->rf_lt_def &= ltg2 << 10; /* reduce in 3 steps from 7 to 0 */ | ||
688 | } | ||
689 | #endif | ||
690 | } else { | ||
691 | state->agc_step = 0; | ||
692 | *tune_state = CT_AGC_STEP_1; | ||
693 | } | ||
694 | } else { | ||
695 | /* calc the adc power */ | ||
696 | adc = state->config->get_adc_power(fe); | ||
697 | adc = (adc * ((s32) 355774) + (((s32) 1) << 20)) >> 21; /* included in [0:-700] */ | ||
698 | |||
699 | adc_error = (s16) (((s32) ADC_TARGET) - adc); | ||
700 | #ifdef CONFIG_STANDARD_DAB | ||
701 | if (state->fe->dtv_property_cache.delivery_system == STANDARD_DAB) | ||
702 | adc_error += 130; | ||
703 | #endif | ||
704 | #ifdef CONFIG_STANDARD_DVBT | ||
705 | if (state->fe->dtv_property_cache.delivery_system == STANDARD_DVBT && | ||
706 | (state->fe->dtv_property_cache.modulation == QAM_64 || state->fe->dtv_property_cache.modulation == QAM_16)) | ||
707 | adc_error += 60; | ||
708 | #endif | ||
709 | #ifdef CONFIG_SYS_ISDBT | ||
710 | if ((state->fe->dtv_property_cache.delivery_system == SYS_ISDBT) && (((state->fe->dtv_property_cache.layer[0].segment_count > | ||
711 | 0) | ||
712 | && | ||
713 | ((state->fe->dtv_property_cache.layer[0].modulation == | ||
714 | QAM_64) | ||
715 | || (state->fe->dtv_property_cache.layer[0]. | ||
716 | modulation == QAM_16))) | ||
717 | || | ||
718 | ((state->fe->dtv_property_cache.layer[1].segment_count > | ||
719 | 0) | ||
720 | && | ||
721 | ((state->fe->dtv_property_cache.layer[1].modulation == | ||
722 | QAM_64) | ||
723 | || (state->fe->dtv_property_cache.layer[1]. | ||
724 | modulation == QAM_16))) | ||
725 | || | ||
726 | ((state->fe->dtv_property_cache.layer[2].segment_count > | ||
727 | 0) | ||
728 | && | ||
729 | ((state->fe->dtv_property_cache.layer[2].modulation == | ||
730 | QAM_64) | ||
731 | || (state->fe->dtv_property_cache.layer[2]. | ||
732 | modulation == QAM_16))) | ||
733 | ) | ||
734 | ) | ||
735 | adc_error += 60; | ||
736 | #endif | ||
737 | |||
738 | if (*tune_state == CT_AGC_STEP_1) { /* quickly go to the correct range of the ADC power */ | ||
739 | if (ABS(adc_error) < 50 || state->agc_step++ > 5) { | ||
740 | |||
741 | #ifdef CONFIG_STANDARD_DAB | ||
742 | if (state->fe->dtv_property_cache.delivery_system == STANDARD_DAB) { | ||
743 | dib0090_write_reg(state, 0x02, (1 << 15) | (15 << 11) | (31 << 6) | (63)); /* cap value = 63 : narrow BB filter : Fc = 1.8MHz */ | ||
744 | dib0090_write_reg(state, 0x04, 0x0); | ||
745 | } else | ||
746 | #endif | ||
747 | { | ||
748 | dib0090_write_reg(state, 0x02, (1 << 15) | (3 << 11) | (6 << 6) | (32)); | ||
749 | dib0090_write_reg(state, 0x04, 0x01); /*0 = 1KHz ; 1 = 150Hz ; 2 = 50Hz ; 3 = 50KHz ; 4 = servo fast */ | ||
750 | } | ||
751 | |||
752 | *tune_state = CT_AGC_STOP; | ||
753 | } | ||
754 | } else { | ||
755 | /* everything higher than or equal to CT_AGC_STOP means tracking */ | ||
756 | ret = 100; /* 10ms interval */ | ||
757 | apply_gain_immediatly = 0; | ||
758 | } | ||
759 | } | ||
760 | #ifdef DEBUG_AGC | ||
761 | dprintk | ||
762 | ("FE: %d, tune state %d, ADC = %3ddB (ADC err %3d) WBD %3ddB (WBD err %3d, WBD val SADC: %4d), RFGainLimit (TOP): %3d, signal: %3ddBm", | ||
763 | (u32) fe->id, (u32) * tune_state, (u32) adc, (u32) adc_error, (u32) wbd, (u32) wbd_error, (u32) wbd_val, | ||
764 | (u32) state->rf_gain_limit >> WBD_ALPHA, (s32) 200 + adc - (state->current_gain >> GAIN_ALPHA)); | ||
765 | #endif | ||
766 | } | ||
767 | |||
768 | /* apply gain */ | ||
769 | if (!state->agc_freeze) | ||
770 | dib0090_gain_apply(state, adc_error, wbd_error, apply_gain_immediatly); | ||
771 | return ret; | ||
772 | } | ||
773 | |||
774 | EXPORT_SYMBOL(dib0090_gain_control); | ||
775 | void dib0090_get_current_gain(struct dvb_frontend *fe, u16 * rf, u16 * bb, u16 * rf_gain_limit, u16 * rflt) | ||
776 | { | ||
777 | struct dib0090_state *state = fe->tuner_priv; | ||
778 | if (rf) | ||
779 | *rf = state->gain[0]; | ||
780 | if (bb) | ||
781 | *bb = state->gain[1]; | ||
782 | if (rf_gain_limit) | ||
783 | *rf_gain_limit = state->rf_gain_limit; | ||
784 | if (rflt) | ||
785 | *rflt = (state->rf_lt_def >> 10) & 0x7; | ||
786 | } | ||
787 | |||
788 | EXPORT_SYMBOL(dib0090_get_current_gain); | ||
789 | u16 dib0090_get_wbd_offset(struct dvb_frontend *tuner) | ||
790 | { | ||
791 | struct dib0090_state *st = tuner->tuner_priv; | ||
792 | return st->wbd_offset; | ||
793 | } | ||
794 | |||
795 | EXPORT_SYMBOL(dib0090_get_wbd_offset); | ||
796 | static const u16 dib0090_defaults[] = { | ||
797 | |||
798 | 25, 0x01, | ||
799 | 0x0000, | ||
800 | 0x99a0, | ||
801 | 0x6008, | ||
802 | 0x0000, | ||
803 | 0x8acb, | ||
804 | 0x0000, | ||
805 | 0x0405, | ||
806 | 0x0000, | ||
807 | 0x0000, | ||
808 | 0x0000, | ||
809 | 0xb802, | ||
810 | 0x0300, | ||
811 | 0x2d12, | ||
812 | 0xbac0, | ||
813 | 0x7c00, | ||
814 | 0xdbb9, | ||
815 | 0x0954, | ||
816 | 0x0743, | ||
817 | 0x8000, | ||
818 | 0x0001, | ||
819 | 0x0040, | ||
820 | 0x0100, | ||
821 | 0x0000, | ||
822 | 0xe910, | ||
823 | 0x149e, | ||
824 | |||
825 | 1, 0x1c, | ||
826 | 0xff2d, | ||
827 | |||
828 | 1, 0x39, | ||
829 | 0x0000, | ||
830 | |||
831 | 1, 0x1b, | ||
832 | EN_IQADC | EN_BB | EN_BIAS | EN_DIGCLK | EN_PLL | EN_CRYSTAL, | ||
833 | 2, 0x1e, | ||
834 | 0x07FF, | ||
835 | 0x0007, | ||
836 | |||
837 | 1, 0x24, | ||
838 | EN_UHF | EN_CRYSTAL, | ||
839 | |||
840 | 2, 0x3c, | ||
841 | 0x3ff, | ||
842 | 0x111, | ||
843 | 0 | ||
844 | }; | ||
845 | |||
846 | static int dib0090_reset(struct dvb_frontend *fe) | ||
847 | { | ||
848 | struct dib0090_state *state = fe->tuner_priv; | ||
849 | u16 l, r, *n; | ||
850 | |||
851 | dib0090_reset_digital(fe, state->config); | ||
852 | state->revision = dib0090_identify(fe); | ||
853 | |||
854 | /* Revision definition */ | ||
855 | if (state->revision == 0xff) | ||
856 | return -EINVAL; | ||
857 | #ifdef EFUSE | ||
858 | else if ((state->revision & 0x1f) >= 3) /* Update the efuse : Only available for KROSUS > P1C */ | ||
859 | dib0090_set_EFUSE(state); | ||
860 | #endif | ||
861 | |||
862 | #ifdef CONFIG_TUNER_DIB0090_P1B_SUPPORT | ||
863 | if (!(state->revision & 0x1)) /* it is P1B - reset is already done */ | ||
864 | return 0; | ||
865 | #endif | ||
866 | |||
867 | /* Upload the default values */ | ||
868 | n = (u16 *) dib0090_defaults; | ||
869 | l = pgm_read_word(n++); | ||
870 | while (l) { | ||
871 | r = pgm_read_word(n++); | ||
872 | do { | ||
873 | /* DEBUG_TUNER */ | ||
874 | /* dprintk("%d, %d, %d", l, r, pgm_read_word(n)); */ | ||
875 | dib0090_write_reg(state, r, pgm_read_word(n++)); | ||
876 | r++; | ||
877 | } while (--l); | ||
878 | l = pgm_read_word(n++); | ||
879 | } | ||
880 | |||
881 | /* Congigure in function of the crystal */ | ||
882 | if (state->config->io.clock_khz >= 24000) | ||
883 | l = 1; | ||
884 | else | ||
885 | l = 2; | ||
886 | dib0090_write_reg(state, 0x14, l); | ||
887 | dprintk("Pll lock : %d", (dib0090_read_reg(state, 0x1a) >> 11) & 0x1); | ||
888 | |||
889 | state->reset = 3; /* enable iq-offset-calibration and wbd-calibration when tuning next time */ | ||
890 | |||
891 | return 0; | ||
892 | } | ||
893 | |||
894 | #define steps(u) (((u)>15)?((u)-16):(u)) | ||
895 | #define INTERN_WAIT 10 | ||
896 | static int dib0090_get_offset(struct dib0090_state *state, enum frontend_tune_state *tune_state) | ||
897 | { | ||
898 | int ret = INTERN_WAIT * 10; | ||
899 | |||
900 | switch (*tune_state) { | ||
901 | case CT_TUNER_STEP_2: | ||
902 | /* Turns to positive */ | ||
903 | dib0090_write_reg(state, 0x1f, 0x7); | ||
904 | *tune_state = CT_TUNER_STEP_3; | ||
905 | break; | ||
906 | |||
907 | case CT_TUNER_STEP_3: | ||
908 | state->adc_diff = dib0090_read_reg(state, 0x1d); | ||
909 | |||
910 | /* Turns to negative */ | ||
911 | dib0090_write_reg(state, 0x1f, 0x4); | ||
912 | *tune_state = CT_TUNER_STEP_4; | ||
913 | break; | ||
914 | |||
915 | case CT_TUNER_STEP_4: | ||
916 | state->adc_diff -= dib0090_read_reg(state, 0x1d); | ||
917 | *tune_state = CT_TUNER_STEP_5; | ||
918 | ret = 0; | ||
919 | break; | ||
920 | |||
921 | default: | ||
922 | break; | ||
923 | } | ||
924 | |||
925 | return ret; | ||
926 | } | ||
927 | |||
928 | struct dc_calibration { | ||
929 | uint8_t addr; | ||
930 | uint8_t offset; | ||
931 | uint8_t pga:1; | ||
932 | uint16_t bb1; | ||
933 | uint8_t i:1; | ||
934 | }; | ||
935 | |||
936 | static const struct dc_calibration dc_table[] = { | ||
937 | /* Step1 BB gain1= 26 with boost 1, gain 2 = 0 */ | ||
938 | {0x06, 5, 1, (1 << 13) | (0 << 8) | (26 << 3), 1}, | ||
939 | {0x07, 11, 1, (1 << 13) | (0 << 8) | (26 << 3), 0}, | ||
940 | /* Step 2 BB gain 1 = 26 with boost = 1 & gain 2 = 29 */ | ||
941 | {0x06, 0, 0, (1 << 13) | (29 << 8) | (26 << 3), 1}, | ||
942 | {0x06, 10, 0, (1 << 13) | (29 << 8) | (26 << 3), 0}, | ||
943 | {0}, | ||
944 | }; | ||
945 | |||
946 | static void dib0090_set_trim(struct dib0090_state *state) | ||
947 | { | ||
948 | u16 *val; | ||
949 | |||
950 | if (state->dc->addr == 0x07) | ||
951 | val = &state->bb7; | ||
952 | else | ||
953 | val = &state->bb6; | ||
954 | |||
955 | *val &= ~(0x1f << state->dc->offset); | ||
956 | *val |= state->step << state->dc->offset; | ||
957 | |||
958 | dib0090_write_reg(state, state->dc->addr, *val); | ||
959 | } | ||
960 | |||
961 | static int dib0090_dc_offset_calibration(struct dib0090_state *state, enum frontend_tune_state *tune_state) | ||
962 | { | ||
963 | int ret = 0; | ||
964 | |||
965 | switch (*tune_state) { | ||
966 | |||
967 | case CT_TUNER_START: | ||
968 | /* init */ | ||
969 | dprintk("Internal DC calibration"); | ||
970 | |||
971 | /* the LNA is off */ | ||
972 | dib0090_write_reg(state, 0x24, 0x02ed); | ||
973 | |||
974 | /* force vcm2 = 0.8V */ | ||
975 | state->bb6 = 0; | ||
976 | state->bb7 = 0x040d; | ||
977 | |||
978 | state->dc = dc_table; | ||
979 | |||
980 | *tune_state = CT_TUNER_STEP_0; | ||
981 | |||
982 | /* fall through */ | ||
983 | |||
984 | case CT_TUNER_STEP_0: | ||
985 | dib0090_write_reg(state, 0x01, state->dc->bb1); | ||
986 | dib0090_write_reg(state, 0x07, state->bb7 | (state->dc->i << 7)); | ||
987 | |||
988 | state->step = 0; | ||
989 | |||
990 | state->min_adc_diff = 1023; | ||
991 | |||
992 | *tune_state = CT_TUNER_STEP_1; | ||
993 | ret = 50; | ||
994 | break; | ||
995 | |||
996 | case CT_TUNER_STEP_1: | ||
997 | dib0090_set_trim(state); | ||
998 | |||
999 | *tune_state = CT_TUNER_STEP_2; | ||
1000 | break; | ||
1001 | |||
1002 | case CT_TUNER_STEP_2: | ||
1003 | case CT_TUNER_STEP_3: | ||
1004 | case CT_TUNER_STEP_4: | ||
1005 | ret = dib0090_get_offset(state, tune_state); | ||
1006 | break; | ||
1007 | |||
1008 | case CT_TUNER_STEP_5: /* found an offset */ | ||
1009 | dprintk("FE%d: IQC read=%d, current=%x", state->fe->id, (u32) state->adc_diff, state->step); | ||
1010 | |||
1011 | /* first turn for this frequency */ | ||
1012 | if (state->step == 0) { | ||
1013 | if (state->dc->pga && state->adc_diff < 0) | ||
1014 | state->step = 0x10; | ||
1015 | if (state->dc->pga == 0 && state->adc_diff > 0) | ||
1016 | state->step = 0x10; | ||
1017 | } | ||
1018 | |||
1019 | state->adc_diff = ABS(state->adc_diff); | ||
1020 | |||
1021 | if (state->adc_diff < state->min_adc_diff && steps(state->step) < 15) { /* stop search when the delta to 0 is increasing */ | ||
1022 | state->step++; | ||
1023 | state->min_adc_diff = state->adc_diff; | ||
1024 | *tune_state = CT_TUNER_STEP_1; | ||
1025 | } else { | ||
1026 | |||
1027 | /* the minimum was what we have seen in the step before */ | ||
1028 | state->step--; | ||
1029 | dib0090_set_trim(state); | ||
1030 | |||
1031 | dprintk("FE%d: BB Offset Cal, BBreg=%hd,Offset=%hd,Value Set=%hd", state->fe->id, state->dc->addr, state->adc_diff, | ||
1032 | state->step); | ||
1033 | |||
1034 | state->dc++; | ||
1035 | if (state->dc->addr == 0) /* done */ | ||
1036 | *tune_state = CT_TUNER_STEP_6; | ||
1037 | else | ||
1038 | *tune_state = CT_TUNER_STEP_0; | ||
1039 | |||
1040 | } | ||
1041 | break; | ||
1042 | |||
1043 | case CT_TUNER_STEP_6: | ||
1044 | dib0090_write_reg(state, 0x07, state->bb7 & ~0x0008); | ||
1045 | dib0090_write_reg(state, 0x1f, 0x7); | ||
1046 | *tune_state = CT_TUNER_START; /* reset done -> real tuning can now begin */ | ||
1047 | state->reset &= ~0x1; | ||
1048 | default: | ||
1049 | break; | ||
1050 | } | ||
1051 | return ret; | ||
1052 | } | ||
1053 | |||
1054 | static int dib0090_wbd_calibration(struct dib0090_state *state, enum frontend_tune_state *tune_state) | ||
1055 | { | ||
1056 | switch (*tune_state) { | ||
1057 | case CT_TUNER_START: | ||
1058 | /* WBD-mode=log, Bias=2, Gain=6, Testmode=1, en=1, WBDMUX=1 */ | ||
1059 | dib0090_write_reg(state, 0x10, 0xdb09 | (1 << 10)); | ||
1060 | dib0090_write_reg(state, 0x24, EN_UHF & 0x0fff); | ||
1061 | |||
1062 | *tune_state = CT_TUNER_STEP_0; | ||
1063 | return 90; /* wait for the WBDMUX to switch and for the ADC to sample */ | ||
1064 | case CT_TUNER_STEP_0: | ||
1065 | state->wbd_offset = dib0090_read_reg(state, 0x1d); | ||
1066 | dprintk("WBD calibration offset = %d", state->wbd_offset); | ||
1067 | |||
1068 | *tune_state = CT_TUNER_START; /* reset done -> real tuning can now begin */ | ||
1069 | state->reset &= ~0x2; | ||
1070 | break; | ||
1071 | default: | ||
1072 | break; | ||
1073 | } | ||
1074 | return 0; | ||
1075 | } | ||
1076 | |||
1077 | static void dib0090_set_bandwidth(struct dib0090_state *state) | ||
1078 | { | ||
1079 | u16 tmp; | ||
1080 | |||
1081 | if (state->fe->dtv_property_cache.bandwidth_hz / 1000 <= 5000) | ||
1082 | tmp = (3 << 14); | ||
1083 | else if (state->fe->dtv_property_cache.bandwidth_hz / 1000 <= 6000) | ||
1084 | tmp = (2 << 14); | ||
1085 | else if (state->fe->dtv_property_cache.bandwidth_hz / 1000 <= 7000) | ||
1086 | tmp = (1 << 14); | ||
1087 | else | ||
1088 | tmp = (0 << 14); | ||
1089 | |||
1090 | state->bb_1_def &= 0x3fff; | ||
1091 | state->bb_1_def |= tmp; | ||
1092 | |||
1093 | dib0090_write_reg(state, 0x01, state->bb_1_def); /* be sure that we have the right bb-filter */ | ||
1094 | } | ||
1095 | |||
1096 | static const struct dib0090_pll dib0090_pll_table[] = { | ||
1097 | #ifdef CONFIG_BAND_CBAND | ||
1098 | {56000, 0, 9, 48, 6}, | ||
1099 | {70000, 1, 9, 48, 6}, | ||
1100 | {87000, 0, 8, 32, 4}, | ||
1101 | {105000, 1, 8, 32, 4}, | ||
1102 | {115000, 0, 7, 24, 6}, | ||
1103 | {140000, 1, 7, 24, 6}, | ||
1104 | {170000, 0, 6, 16, 4}, | ||
1105 | #endif | ||
1106 | #ifdef CONFIG_BAND_VHF | ||
1107 | {200000, 1, 6, 16, 4}, | ||
1108 | {230000, 0, 5, 12, 6}, | ||
1109 | {280000, 1, 5, 12, 6}, | ||
1110 | {340000, 0, 4, 8, 4}, | ||
1111 | {380000, 1, 4, 8, 4}, | ||
1112 | {450000, 0, 3, 6, 6}, | ||
1113 | #endif | ||
1114 | #ifdef CONFIG_BAND_UHF | ||
1115 | {580000, 1, 3, 6, 6}, | ||
1116 | {700000, 0, 2, 4, 4}, | ||
1117 | {860000, 1, 2, 4, 4}, | ||
1118 | #endif | ||
1119 | #ifdef CONFIG_BAND_LBAND | ||
1120 | {1800000, 1, 0, 2, 4}, | ||
1121 | #endif | ||
1122 | #ifdef CONFIG_BAND_SBAND | ||
1123 | {2900000, 0, 14, 1, 4}, | ||
1124 | #endif | ||
1125 | }; | ||
1126 | |||
1127 | static const struct dib0090_tuning dib0090_tuning_table_fm_vhf_on_cband[] = { | ||
1128 | |||
1129 | #ifdef CONFIG_BAND_CBAND | ||
1130 | {184000, 4, 1, 15, 0x280, 0x2912, 0xb94e, EN_CAB}, | ||
1131 | {227000, 4, 3, 15, 0x280, 0x2912, 0xb94e, EN_CAB}, | ||
1132 | {380000, 4, 7, 15, 0x280, 0x2912, 0xb94e, EN_CAB}, | ||
1133 | #endif | ||
1134 | #ifdef CONFIG_BAND_UHF | ||
1135 | {520000, 2, 0, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF}, | ||
1136 | {550000, 2, 2, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF}, | ||
1137 | {650000, 2, 3, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF}, | ||
1138 | {750000, 2, 5, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF}, | ||
1139 | {850000, 2, 6, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF}, | ||
1140 | {900000, 2, 7, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF}, | ||
1141 | #endif | ||
1142 | #ifdef CONFIG_BAND_LBAND | ||
1143 | {1500000, 4, 0, 20, 0x300, 0x1912, 0x82c9, EN_LBD}, | ||
1144 | {1600000, 4, 1, 20, 0x300, 0x1912, 0x82c9, EN_LBD}, | ||
1145 | {1800000, 4, 3, 20, 0x300, 0x1912, 0x82c9, EN_LBD}, | ||
1146 | #endif | ||
1147 | #ifdef CONFIG_BAND_SBAND | ||
1148 | {2300000, 1, 4, 20, 0x300, 0x2d2A, 0x82c7, EN_SBD}, | ||
1149 | {2900000, 1, 7, 20, 0x280, 0x2deb, 0x8347, EN_SBD}, | ||
1150 | #endif | ||
1151 | }; | ||
1152 | |||
1153 | static const struct dib0090_tuning dib0090_tuning_table[] = { | ||
1154 | |||
1155 | #ifdef CONFIG_BAND_CBAND | ||
1156 | {170000, 4, 1, 15, 0x280, 0x2912, 0xb94e, EN_CAB}, | ||
1157 | #endif | ||
1158 | #ifdef CONFIG_BAND_VHF | ||
1159 | {184000, 1, 1, 15, 0x300, 0x4d12, 0xb94e, EN_VHF}, | ||
1160 | {227000, 1, 3, 15, 0x300, 0x4d12, 0xb94e, EN_VHF}, | ||
1161 | {380000, 1, 7, 15, 0x300, 0x4d12, 0xb94e, EN_VHF}, | ||
1162 | #endif | ||
1163 | #ifdef CONFIG_BAND_UHF | ||
1164 | {520000, 2, 0, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF}, | ||
1165 | {550000, 2, 2, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF}, | ||
1166 | {650000, 2, 3, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF}, | ||
1167 | {750000, 2, 5, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF}, | ||
1168 | {850000, 2, 6, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF}, | ||
1169 | {900000, 2, 7, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF}, | ||
1170 | #endif | ||
1171 | #ifdef CONFIG_BAND_LBAND | ||
1172 | {1500000, 4, 0, 20, 0x300, 0x1912, 0x82c9, EN_LBD}, | ||
1173 | {1600000, 4, 1, 20, 0x300, 0x1912, 0x82c9, EN_LBD}, | ||
1174 | {1800000, 4, 3, 20, 0x300, 0x1912, 0x82c9, EN_LBD}, | ||
1175 | #endif | ||
1176 | #ifdef CONFIG_BAND_SBAND | ||
1177 | {2300000, 1, 4, 20, 0x300, 0x2d2A, 0x82c7, EN_SBD}, | ||
1178 | {2900000, 1, 7, 20, 0x280, 0x2deb, 0x8347, EN_SBD}, | ||
1179 | #endif | ||
1180 | }; | ||
1181 | |||
1182 | #define WBD 0x781 /* 1 1 1 1 0000 0 0 1 */ | ||
1183 | static int dib0090_tune(struct dvb_frontend *fe) | ||
1184 | { | ||
1185 | struct dib0090_state *state = fe->tuner_priv; | ||
1186 | const struct dib0090_tuning *tune = state->current_tune_table_index; | ||
1187 | const struct dib0090_pll *pll = state->current_pll_table_index; | ||
1188 | enum frontend_tune_state *tune_state = &state->tune_state; | ||
1189 | |||
1190 | u32 rf; | ||
1191 | u16 lo4 = 0xe900, lo5, lo6, Den; | ||
1192 | u32 FBDiv, Rest, FREF, VCOF_kHz = 0; | ||
1193 | u16 tmp, adc; | ||
1194 | int8_t step_sign; | ||
1195 | int ret = 10; /* 1ms is the default delay most of the time */ | ||
1196 | u8 c, i; | ||
1197 | |||
1198 | state->current_band = (u8) BAND_OF_FREQUENCY(fe->dtv_property_cache.frequency / 1000); | ||
1199 | rf = fe->dtv_property_cache.frequency / 1000 + (state->current_band == | ||
1200 | BAND_UHF ? state->config->freq_offset_khz_uhf : state->config->freq_offset_khz_vhf); | ||
1201 | /* in any case we first need to do a reset if needed */ | ||
1202 | if (state->reset & 0x1) | ||
1203 | return dib0090_dc_offset_calibration(state, tune_state); | ||
1204 | else if (state->reset & 0x2) | ||
1205 | return dib0090_wbd_calibration(state, tune_state); | ||
1206 | |||
1207 | /************************* VCO ***************************/ | ||
1208 | /* Default values for FG */ | ||
1209 | /* from these are needed : */ | ||
1210 | /* Cp,HFdiv,VCOband,SD,Num,Den,FB and REFDiv */ | ||
1211 | |||
1212 | #ifdef CONFIG_SYS_ISDBT | ||
1213 | if (state->fe->dtv_property_cache.delivery_system == SYS_ISDBT && state->fe->dtv_property_cache.isdbt_sb_mode == 1) | ||
1214 | rf += 850; | ||
1215 | #endif | ||
1216 | |||
1217 | if (state->current_rf != rf) { | ||
1218 | state->tuner_is_tuned = 0; | ||
1219 | |||
1220 | tune = dib0090_tuning_table; | ||
1221 | |||
1222 | tmp = (state->revision >> 5) & 0x7; | ||
1223 | if (tmp == 0x4 || tmp == 0x7) { | ||
1224 | /* CBAND tuner version for VHF */ | ||
1225 | if (state->current_band == BAND_FM || state->current_band == BAND_VHF) { | ||
1226 | /* Force CBAND */ | ||
1227 | state->current_band = BAND_CBAND; | ||
1228 | tune = dib0090_tuning_table_fm_vhf_on_cband; | ||
1229 | } | ||
1230 | } | ||
1231 | |||
1232 | pll = dib0090_pll_table; | ||
1233 | /* Look for the interval */ | ||
1234 | while (rf > tune->max_freq) | ||
1235 | tune++; | ||
1236 | while (rf > pll->max_freq) | ||
1237 | pll++; | ||
1238 | state->current_tune_table_index = tune; | ||
1239 | state->current_pll_table_index = pll; | ||
1240 | } | ||
1241 | |||
1242 | if (*tune_state == CT_TUNER_START) { | ||
1243 | |||
1244 | if (state->tuner_is_tuned == 0) | ||
1245 | state->current_rf = 0; | ||
1246 | |||
1247 | if (state->current_rf != rf) { | ||
1248 | |||
1249 | dib0090_write_reg(state, 0x0b, 0xb800 | (tune->switch_trim)); | ||
1250 | |||
1251 | /* external loop filter, otherwise: | ||
1252 | * lo5 = (0 << 15) | (0 << 12) | (0 << 11) | (3 << 9) | (4 << 6) | (3 << 4) | 4; | ||
1253 | * lo6 = 0x0e34 */ | ||
1254 | if (pll->vco_band) | ||
1255 | lo5 = 0x049e; | ||
1256 | else if (state->config->analog_output) | ||
1257 | lo5 = 0x041d; | ||
1258 | else | ||
1259 | lo5 = 0x041c; | ||
1260 | |||
1261 | lo5 |= (pll->hfdiv_code << 11) | (pll->vco_band << 7); /* bit 15 is the split to the slave, we do not do it here */ | ||
1262 | |||
1263 | if (!state->config->io.pll_int_loop_filt) | ||
1264 | lo6 = 0xff28; | ||
1265 | else | ||
1266 | lo6 = (state->config->io.pll_int_loop_filt << 3); | ||
1267 | |||
1268 | VCOF_kHz = (pll->hfdiv * rf) * 2; | ||
1269 | |||
1270 | FREF = state->config->io.clock_khz; | ||
1271 | |||
1272 | FBDiv = (VCOF_kHz / pll->topresc / FREF); | ||
1273 | Rest = (VCOF_kHz / pll->topresc) - FBDiv * FREF; | ||
1274 | |||
1275 | if (Rest < LPF) | ||
1276 | Rest = 0; | ||
1277 | else if (Rest < 2 * LPF) | ||
1278 | Rest = 2 * LPF; | ||
1279 | else if (Rest > (FREF - LPF)) { | ||
1280 | Rest = 0; | ||
1281 | FBDiv += 1; | ||
1282 | } else if (Rest > (FREF - 2 * LPF)) | ||
1283 | Rest = FREF - 2 * LPF; | ||
1284 | Rest = (Rest * 6528) / (FREF / 10); | ||
1285 | |||
1286 | Den = 1; | ||
1287 | |||
1288 | dprintk(" ***** ******* Rest value = %d", Rest); | ||
1289 | |||
1290 | if (Rest > 0) { | ||
1291 | if (state->config->analog_output) | ||
1292 | lo6 |= (1 << 2) | 2; | ||
1293 | else | ||
1294 | lo6 |= (1 << 2) | 1; | ||
1295 | Den = 255; | ||
1296 | } | ||
1297 | #ifdef CONFIG_BAND_SBAND | ||
1298 | if (state->current_band == BAND_SBAND) | ||
1299 | lo6 &= 0xfffb; | ||
1300 | #endif | ||
1301 | |||
1302 | dib0090_write_reg(state, 0x15, (u16) FBDiv); | ||
1303 | |||
1304 | dib0090_write_reg(state, 0x16, (Den << 8) | 1); | ||
1305 | |||
1306 | dib0090_write_reg(state, 0x17, (u16) Rest); | ||
1307 | |||
1308 | dib0090_write_reg(state, 0x19, lo5); | ||
1309 | |||
1310 | dib0090_write_reg(state, 0x1c, lo6); | ||
1311 | |||
1312 | lo6 = tune->tuner_enable; | ||
1313 | if (state->config->analog_output) | ||
1314 | lo6 = (lo6 & 0xff9f) | 0x2; | ||
1315 | |||
1316 | dib0090_write_reg(state, 0x24, lo6 | EN_LO | ||
1317 | #ifdef CONFIG_DIB0090_USE_PWM_AGC | ||
1318 | | state->config->use_pwm_agc * EN_CRYSTAL | ||
1319 | #endif | ||
1320 | ); | ||
1321 | |||
1322 | state->current_rf = rf; | ||
1323 | |||
1324 | /* prepare a complete captrim */ | ||
1325 | state->step = state->captrim = state->fcaptrim = 64; | ||
1326 | |||
1327 | } else { /* we are already tuned to this frequency - the configuration is correct */ | ||
1328 | |||
1329 | /* do a minimal captrim even if the frequency has not changed */ | ||
1330 | state->step = 4; | ||
1331 | state->captrim = state->fcaptrim = dib0090_read_reg(state, 0x18) & 0x7f; | ||
1332 | } | ||
1333 | state->adc_diff = 3000; | ||
1334 | |||
1335 | dib0090_write_reg(state, 0x10, 0x2B1); | ||
1336 | |||
1337 | dib0090_write_reg(state, 0x1e, 0x0032); | ||
1338 | |||
1339 | ret = 20; | ||
1340 | *tune_state = CT_TUNER_STEP_1; | ||
1341 | } else if (*tune_state == CT_TUNER_STEP_0) { | ||
1342 | /* nothing */ | ||
1343 | } else if (*tune_state == CT_TUNER_STEP_1) { | ||
1344 | state->step /= 2; | ||
1345 | dib0090_write_reg(state, 0x18, lo4 | state->captrim); | ||
1346 | *tune_state = CT_TUNER_STEP_2; | ||
1347 | } else if (*tune_state == CT_TUNER_STEP_2) { | ||
1348 | |||
1349 | adc = dib0090_read_reg(state, 0x1d); | ||
1350 | dprintk("FE %d CAPTRIM=%d; ADC = %d (ADC) & %dmV", (u32) fe->id, (u32) state->captrim, (u32) adc, | ||
1351 | (u32) (adc) * (u32) 1800 / (u32) 1024); | ||
1352 | |||
1353 | if (adc >= 400) { | ||
1354 | adc -= 400; | ||
1355 | step_sign = -1; | ||
1356 | } else { | ||
1357 | adc = 400 - adc; | ||
1358 | step_sign = 1; | ||
1359 | } | ||
1360 | |||
1361 | if (adc < state->adc_diff) { | ||
1362 | dprintk("FE %d CAPTRIM=%d is closer to target (%d/%d)", (u32) fe->id, (u32) state->captrim, (u32) adc, (u32) state->adc_diff); | ||
1363 | state->adc_diff = adc; | ||
1364 | state->fcaptrim = state->captrim; | ||
1365 | |||
1366 | } | ||
1367 | |||
1368 | state->captrim += step_sign * state->step; | ||
1369 | if (state->step >= 1) | ||
1370 | *tune_state = CT_TUNER_STEP_1; | ||
1371 | else | ||
1372 | *tune_state = CT_TUNER_STEP_3; | ||
1373 | |||
1374 | ret = 15; | ||
1375 | } else if (*tune_state == CT_TUNER_STEP_3) { | ||
1376 | /*write the final cptrim config */ | ||
1377 | dib0090_write_reg(state, 0x18, lo4 | state->fcaptrim); | ||
1378 | |||
1379 | #ifdef CONFIG_TUNER_DIB0090_CAPTRIM_MEMORY | ||
1380 | state->memory[state->memory_index].cap = state->fcaptrim; | ||
1381 | #endif | ||
1382 | |||
1383 | *tune_state = CT_TUNER_STEP_4; | ||
1384 | } else if (*tune_state == CT_TUNER_STEP_4) { | ||
1385 | dib0090_write_reg(state, 0x1e, 0x07ff); | ||
1386 | |||
1387 | dprintk("FE %d Final Captrim: %d", (u32) fe->id, (u32) state->fcaptrim); | ||
1388 | dprintk("FE %d HFDIV code: %d", (u32) fe->id, (u32) pll->hfdiv_code); | ||
1389 | dprintk("FE %d VCO = %d", (u32) fe->id, (u32) pll->vco_band); | ||
1390 | dprintk("FE %d VCOF in kHz: %d ((%d*%d) << 1))", (u32) fe->id, (u32) ((pll->hfdiv * rf) * 2), (u32) pll->hfdiv, (u32) rf); | ||
1391 | dprintk("FE %d REFDIV: %d, FREF: %d", (u32) fe->id, (u32) 1, (u32) state->config->io.clock_khz); | ||
1392 | dprintk("FE %d FBDIV: %d, Rest: %d", (u32) fe->id, (u32) dib0090_read_reg(state, 0x15), (u32) dib0090_read_reg(state, 0x17)); | ||
1393 | dprintk("FE %d Num: %d, Den: %d, SD: %d", (u32) fe->id, (u32) dib0090_read_reg(state, 0x17), | ||
1394 | (u32) (dib0090_read_reg(state, 0x16) >> 8), (u32) dib0090_read_reg(state, 0x1c) & 0x3); | ||
1395 | |||
1396 | c = 4; | ||
1397 | i = 3; | ||
1398 | #if defined(CONFIG_BAND_LBAND) || defined(CONFIG_BAND_SBAND) | ||
1399 | if ((state->current_band == BAND_LBAND) || (state->current_band == BAND_SBAND)) { | ||
1400 | c = 2; | ||
1401 | i = 2; | ||
1402 | } | ||
1403 | #endif | ||
1404 | dib0090_write_reg(state, 0x10, (c << 13) | (i << 11) | (WBD | ||
1405 | #ifdef CONFIG_DIB0090_USE_PWM_AGC | ||
1406 | | (state->config->use_pwm_agc << 1) | ||
1407 | #endif | ||
1408 | )); | ||
1409 | dib0090_write_reg(state, 0x09, (tune->lna_tune << 5) | (tune->lna_bias << 0)); | ||
1410 | dib0090_write_reg(state, 0x0c, tune->v2i); | ||
1411 | dib0090_write_reg(state, 0x0d, tune->mix); | ||
1412 | dib0090_write_reg(state, 0x0e, tune->load); | ||
1413 | |||
1414 | *tune_state = CT_TUNER_STEP_5; | ||
1415 | } else if (*tune_state == CT_TUNER_STEP_5) { | ||
1416 | |||
1417 | /* initialize the lt gain register */ | ||
1418 | state->rf_lt_def = 0x7c00; | ||
1419 | dib0090_write_reg(state, 0x0f, state->rf_lt_def); | ||
1420 | |||
1421 | dib0090_set_bandwidth(state); | ||
1422 | state->tuner_is_tuned = 1; | ||
1423 | *tune_state = CT_TUNER_STOP; | ||
1424 | } else | ||
1425 | ret = FE_CALLBACK_TIME_NEVER; | ||
1426 | return ret; | ||
1427 | } | ||
1428 | |||
1429 | static int dib0090_release(struct dvb_frontend *fe) | ||
1430 | { | ||
1431 | kfree(fe->tuner_priv); | ||
1432 | fe->tuner_priv = NULL; | ||
1433 | return 0; | ||
1434 | } | ||
1435 | |||
1436 | enum frontend_tune_state dib0090_get_tune_state(struct dvb_frontend *fe) | ||
1437 | { | ||
1438 | struct dib0090_state *state = fe->tuner_priv; | ||
1439 | |||
1440 | return state->tune_state; | ||
1441 | } | ||
1442 | |||
1443 | EXPORT_SYMBOL(dib0090_get_tune_state); | ||
1444 | |||
1445 | int dib0090_set_tune_state(struct dvb_frontend *fe, enum frontend_tune_state tune_state) | ||
1446 | { | ||
1447 | struct dib0090_state *state = fe->tuner_priv; | ||
1448 | |||
1449 | state->tune_state = tune_state; | ||
1450 | return 0; | ||
1451 | } | ||
1452 | |||
1453 | EXPORT_SYMBOL(dib0090_set_tune_state); | ||
1454 | |||
1455 | static int dib0090_get_frequency(struct dvb_frontend *fe, u32 * frequency) | ||
1456 | { | ||
1457 | struct dib0090_state *state = fe->tuner_priv; | ||
1458 | |||
1459 | *frequency = 1000 * state->current_rf; | ||
1460 | return 0; | ||
1461 | } | ||
1462 | |||
1463 | static int dib0090_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *p) | ||
1464 | { | ||
1465 | struct dib0090_state *state = fe->tuner_priv; | ||
1466 | uint32_t ret; | ||
1467 | |||
1468 | state->tune_state = CT_TUNER_START; | ||
1469 | |||
1470 | do { | ||
1471 | ret = dib0090_tune(fe); | ||
1472 | if (ret != FE_CALLBACK_TIME_NEVER) | ||
1473 | msleep(ret / 10); | ||
1474 | else | ||
1475 | break; | ||
1476 | } while (state->tune_state != CT_TUNER_STOP); | ||
1477 | |||
1478 | return 0; | ||
1479 | } | ||
1480 | |||
1481 | static const struct dvb_tuner_ops dib0090_ops = { | ||
1482 | .info = { | ||
1483 | .name = "DiBcom DiB0090", | ||
1484 | .frequency_min = 45000000, | ||
1485 | .frequency_max = 860000000, | ||
1486 | .frequency_step = 1000, | ||
1487 | }, | ||
1488 | .release = dib0090_release, | ||
1489 | |||
1490 | .init = dib0090_wakeup, | ||
1491 | .sleep = dib0090_sleep, | ||
1492 | .set_params = dib0090_set_params, | ||
1493 | .get_frequency = dib0090_get_frequency, | ||
1494 | }; | ||
1495 | |||
1496 | struct dvb_frontend *dib0090_register(struct dvb_frontend *fe, struct i2c_adapter *i2c, const struct dib0090_config *config) | ||
1497 | { | ||
1498 | struct dib0090_state *st = kzalloc(sizeof(struct dib0090_state), GFP_KERNEL); | ||
1499 | if (st == NULL) | ||
1500 | return NULL; | ||
1501 | |||
1502 | st->config = config; | ||
1503 | st->i2c = i2c; | ||
1504 | st->fe = fe; | ||
1505 | fe->tuner_priv = st; | ||
1506 | |||
1507 | if (dib0090_reset(fe) != 0) | ||
1508 | goto free_mem; | ||
1509 | |||
1510 | printk(KERN_INFO "DiB0090: successfully identified\n"); | ||
1511 | memcpy(&fe->ops.tuner_ops, &dib0090_ops, sizeof(struct dvb_tuner_ops)); | ||
1512 | |||
1513 | return fe; | ||
1514 | free_mem: | ||
1515 | kfree(st); | ||
1516 | fe->tuner_priv = NULL; | ||
1517 | return NULL; | ||
1518 | } | ||
1519 | |||
1520 | EXPORT_SYMBOL(dib0090_register); | ||
1521 | |||
1522 | MODULE_AUTHOR("Patrick Boettcher <pboettcher@dibcom.fr>"); | ||
1523 | MODULE_AUTHOR("Olivier Grenie <olivier.grenie@dibcom.fr>"); | ||
1524 | MODULE_DESCRIPTION("Driver for the DiBcom 0090 base-band RF Tuner"); | ||
1525 | MODULE_LICENSE("GPL"); | ||