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