[media] DiBxxxx: Codingstype updates
[linux-2.6/linux-acpi-2.6/ibm-acpi-2.6.git] / drivers / media / dvb / frontends / dib0090.c
blob52ff1a252a907186e4086a6bf9b0f606f215bfa7
1 /*
2 * Linux-DVB Driver for DiBcom's DiB0090 base-band RF Tuner.
4 * Copyright (C) 2005-9 DiBcom (http://www.dibcom.fr/)
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.
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
15 * GNU General Public License for more details.
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.
22 * This code is more or less generated from another driver, please
23 * excuse some codingstyle oddities.
27 #include <linux/kernel.h>
28 #include <linux/slab.h>
29 #include <linux/i2c.h>
31 #include "dvb_frontend.h"
33 #include "dib0090.h"
34 #include "dibx000_common.h"
36 static int debug;
37 module_param(debug, int, 0644);
38 MODULE_PARM_DESC(debug, "turn on debugging (default: 0)");
40 #define dprintk(args...) do { \
41 if (debug) { \
42 printk(KERN_DEBUG "DiB0090: "); \
43 printk(args); \
44 printk("\n"); \
45 } \
46 } while (0)
48 #define CONFIG_SYS_DVBT
49 #define CONFIG_SYS_ISDBT
50 #define CONFIG_BAND_CBAND
51 #define CONFIG_BAND_VHF
52 #define CONFIG_BAND_UHF
53 #define CONFIG_DIB0090_USE_PWM_AGC
55 #define EN_LNA0 0x8000
56 #define EN_LNA1 0x4000
57 #define EN_LNA2 0x2000
58 #define EN_LNA3 0x1000
59 #define EN_MIX0 0x0800
60 #define EN_MIX1 0x0400
61 #define EN_MIX2 0x0200
62 #define EN_MIX3 0x0100
63 #define EN_IQADC 0x0040
64 #define EN_PLL 0x0020
65 #define EN_TX 0x0010
66 #define EN_BB 0x0008
67 #define EN_LO 0x0004
68 #define EN_BIAS 0x0001
70 #define EN_IQANA 0x0002
71 #define EN_DIGCLK 0x0080 /* not in the 0x24 reg, only in 0x1b */
72 #define EN_CRYSTAL 0x0002
74 #define EN_UHF 0x22E9
75 #define EN_VHF 0x44E9
76 #define EN_LBD 0x11E9
77 #define EN_SBD 0x44E9
78 #define EN_CAB 0x88E9
80 /* Calibration defines */
81 #define DC_CAL 0x1
82 #define WBD_CAL 0x2
83 #define TEMP_CAL 0x4
84 #define CAPTRIM_CAL 0x8
86 #define KROSUS_PLL_LOCKED 0x800
87 #define KROSUS 0x2
89 /* Use those defines to identify SOC version */
90 #define SOC 0x02
91 #define SOC_7090_P1G_11R1 0x82
92 #define SOC_7090_P1G_21R1 0x8a
93 #define SOC_8090_P1G_11R1 0x86
94 #define SOC_8090_P1G_21R1 0x8e
96 /* else use thos ones to check */
97 #define P1A_B 0x0
98 #define P1C 0x1
99 #define P1D_E_F 0x3
100 #define P1G 0x7
101 #define P1G_21R2 0xf
103 #define MP001 0x1 /* Single 9090/8096 */
104 #define MP005 0x4 /* Single Sband */
105 #define MP008 0x6 /* Dual diversity VHF-UHF-LBAND */
106 #define MP009 0x7 /* Dual diversity 29098 CBAND-UHF-LBAND-SBAND */
108 #define pgm_read_word(w) (*w)
110 struct dc_calibration;
112 struct dib0090_tuning {
113 u32 max_freq; /* for every frequency less than or equal to that field: this information is correct */
114 u8 switch_trim;
115 u8 lna_tune;
116 u16 lna_bias;
117 u16 v2i;
118 u16 mix;
119 u16 load;
120 u16 tuner_enable;
123 struct dib0090_pll {
124 u32 max_freq; /* for every frequency less than or equal to that field: this information is correct */
125 u8 vco_band;
126 u8 hfdiv_code;
127 u8 hfdiv;
128 u8 topresc;
131 struct dib0090_identity {
132 u8 version;
133 u8 product;
134 u8 p1g;
135 u8 in_soc;
138 struct dib0090_state {
139 struct i2c_adapter *i2c;
140 struct dvb_frontend *fe;
141 const struct dib0090_config *config;
143 u8 current_band;
144 enum frontend_tune_state tune_state;
145 u32 current_rf;
147 u16 wbd_offset;
148 s16 wbd_target; /* in dB */
150 s16 rf_gain_limit; /* take-over-point: where to split between bb and rf gain */
151 s16 current_gain; /* keeps the currently programmed gain */
152 u8 agc_step; /* new binary search */
154 u16 gain[2]; /* for channel monitoring */
156 const u16 *rf_ramp;
157 const u16 *bb_ramp;
159 /* for the software AGC ramps */
160 u16 bb_1_def;
161 u16 rf_lt_def;
162 u16 gain_reg[4];
164 /* for the captrim/dc-offset search */
165 s8 step;
166 s16 adc_diff;
167 s16 min_adc_diff;
169 s8 captrim;
170 s8 fcaptrim;
172 const struct dc_calibration *dc;
173 u16 bb6, bb7;
175 const struct dib0090_tuning *current_tune_table_index;
176 const struct dib0090_pll *current_pll_table_index;
178 u8 tuner_is_tuned;
179 u8 agc_freeze;
181 struct dib0090_identity identity;
183 u32 rf_request;
184 u8 current_standard;
186 u8 calibrate;
187 u32 rest;
188 u16 bias;
189 s16 temperature;
191 u8 wbd_calibration_gain;
192 const struct dib0090_wbd_slope *current_wbd_table;
193 u16 wbdmux;
196 struct dib0090_fw_state {
197 struct i2c_adapter *i2c;
198 struct dvb_frontend *fe;
199 struct dib0090_identity identity;
200 const struct dib0090_config *config;
203 static u16 dib0090_read_reg(struct dib0090_state *state, u8 reg)
205 u8 b[2];
206 struct i2c_msg msg[2] = {
207 {.addr = state->config->i2c_address, .flags = 0, .buf = &reg, .len = 1},
208 {.addr = state->config->i2c_address, .flags = I2C_M_RD, .buf = b, .len = 2},
210 if (i2c_transfer(state->i2c, msg, 2) != 2) {
211 printk(KERN_WARNING "DiB0090 I2C read failed\n");
212 return 0;
214 return (b[0] << 8) | b[1];
217 static int dib0090_write_reg(struct dib0090_state *state, u32 reg, u16 val)
219 u8 b[3] = { reg & 0xff, val >> 8, val & 0xff };
220 struct i2c_msg msg = {.addr = state->config->i2c_address, .flags = 0, .buf = b, .len = 3 };
221 if (i2c_transfer(state->i2c, &msg, 1) != 1) {
222 printk(KERN_WARNING "DiB0090 I2C write failed\n");
223 return -EREMOTEIO;
225 return 0;
228 static u16 dib0090_fw_read_reg(struct dib0090_fw_state *state, u8 reg)
230 u8 b[2];
231 struct i2c_msg msg = {.addr = reg, .flags = I2C_M_RD, .buf = b, .len = 2 };
232 if (i2c_transfer(state->i2c, &msg, 1) != 1) {
233 printk(KERN_WARNING "DiB0090 I2C read failed\n");
234 return 0;
236 return (b[0] << 8) | b[1];
239 static int dib0090_fw_write_reg(struct dib0090_fw_state *state, u8 reg, u16 val)
241 u8 b[2] = { val >> 8, val & 0xff };
242 struct i2c_msg msg = {.addr = reg, .flags = 0, .buf = b, .len = 2 };
243 if (i2c_transfer(state->i2c, &msg, 1) != 1) {
244 printk(KERN_WARNING "DiB0090 I2C write failed\n");
245 return -EREMOTEIO;
247 return 0;
250 #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)
251 #define ADC_TARGET -220
252 #define GAIN_ALPHA 5
253 #define WBD_ALPHA 6
254 #define LPF 100
255 static void dib0090_write_regs(struct dib0090_state *state, u8 r, const u16 * b, u8 c)
257 do {
258 dib0090_write_reg(state, r++, *b++);
259 } while (--c);
262 static int dib0090_identify(struct dvb_frontend *fe)
264 struct dib0090_state *state = fe->tuner_priv;
265 u16 v;
266 struct dib0090_identity *identity = &state->identity;
268 v = dib0090_read_reg(state, 0x1a);
270 identity->p1g = 0;
271 identity->in_soc = 0;
273 dprintk("Tuner identification (Version = 0x%04x)", v);
275 /* without PLL lock info */
276 v &= ~KROSUS_PLL_LOCKED;
278 identity->version = v & 0xff;
279 identity->product = (v >> 8) & 0xf;
281 if (identity->product != KROSUS)
282 goto identification_error;
284 if ((identity->version & 0x3) == SOC) {
285 identity->in_soc = 1;
286 switch (identity->version) {
287 case SOC_8090_P1G_11R1:
288 dprintk("SOC 8090 P1-G11R1 Has been detected");
289 identity->p1g = 1;
290 break;
291 case SOC_8090_P1G_21R1:
292 dprintk("SOC 8090 P1-G21R1 Has been detected");
293 identity->p1g = 1;
294 break;
295 case SOC_7090_P1G_11R1:
296 dprintk("SOC 7090 P1-G11R1 Has been detected");
297 identity->p1g = 1;
298 break;
299 case SOC_7090_P1G_21R1:
300 dprintk("SOC 7090 P1-G21R1 Has been detected");
301 identity->p1g = 1;
302 break;
303 default:
304 goto identification_error;
306 } else {
307 switch ((identity->version >> 5) & 0x7) {
308 case MP001:
309 dprintk("MP001 : 9090/8096");
310 break;
311 case MP005:
312 dprintk("MP005 : Single Sband");
313 break;
314 case MP008:
315 dprintk("MP008 : diversity VHF-UHF-LBAND");
316 break;
317 case MP009:
318 dprintk("MP009 : diversity 29098 CBAND-UHF-LBAND-SBAND");
319 break;
320 default:
321 goto identification_error;
324 switch (identity->version & 0x1f) {
325 case P1G_21R2:
326 dprintk("P1G_21R2 detected");
327 identity->p1g = 1;
328 break;
329 case P1G:
330 dprintk("P1G detected");
331 identity->p1g = 1;
332 break;
333 case P1D_E_F:
334 dprintk("P1D/E/F detected");
335 break;
336 case P1C:
337 dprintk("P1C detected");
338 break;
339 case P1A_B:
340 dprintk("P1-A/B detected: driver is deactivated - not available");
341 goto identification_error;
342 break;
343 default:
344 goto identification_error;
348 return 0;
350 identification_error:
351 return -EIO;
354 static int dib0090_fw_identify(struct dvb_frontend *fe)
356 struct dib0090_fw_state *state = fe->tuner_priv;
357 struct dib0090_identity *identity = &state->identity;
359 u16 v = dib0090_fw_read_reg(state, 0x1a);
360 identity->p1g = 0;
361 identity->in_soc = 0;
363 dprintk("FE: Tuner identification (Version = 0x%04x)", v);
365 /* without PLL lock info */
366 v &= ~KROSUS_PLL_LOCKED;
368 identity->version = v & 0xff;
369 identity->product = (v >> 8) & 0xf;
371 if (identity->product != KROSUS)
372 goto identification_error;
374 if ((identity->version & 0x3) == SOC) {
375 identity->in_soc = 1;
376 switch (identity->version) {
377 case SOC_8090_P1G_11R1:
378 dprintk("SOC 8090 P1-G11R1 Has been detected");
379 identity->p1g = 1;
380 break;
381 case SOC_8090_P1G_21R1:
382 dprintk("SOC 8090 P1-G21R1 Has been detected");
383 identity->p1g = 1;
384 break;
385 case SOC_7090_P1G_11R1:
386 dprintk("SOC 7090 P1-G11R1 Has been detected");
387 identity->p1g = 1;
388 break;
389 case SOC_7090_P1G_21R1:
390 dprintk("SOC 7090 P1-G21R1 Has been detected");
391 identity->p1g = 1;
392 break;
393 default:
394 goto identification_error;
396 } else {
397 switch ((identity->version >> 5) & 0x7) {
398 case MP001:
399 dprintk("MP001 : 9090/8096");
400 break;
401 case MP005:
402 dprintk("MP005 : Single Sband");
403 break;
404 case MP008:
405 dprintk("MP008 : diversity VHF-UHF-LBAND");
406 break;
407 case MP009:
408 dprintk("MP009 : diversity 29098 CBAND-UHF-LBAND-SBAND");
409 break;
410 default:
411 goto identification_error;
414 switch (identity->version & 0x1f) {
415 case P1G_21R2:
416 dprintk("P1G_21R2 detected");
417 identity->p1g = 1;
418 break;
419 case P1G:
420 dprintk("P1G detected");
421 identity->p1g = 1;
422 break;
423 case P1D_E_F:
424 dprintk("P1D/E/F detected");
425 break;
426 case P1C:
427 dprintk("P1C detected");
428 break;
429 case P1A_B:
430 dprintk("P1-A/B detected: driver is deactivated - not available");
431 goto identification_error;
432 break;
433 default:
434 goto identification_error;
438 return 0;
440 identification_error:
441 return -EIO;;
444 static void dib0090_reset_digital(struct dvb_frontend *fe, const struct dib0090_config *cfg)
446 struct dib0090_state *state = fe->tuner_priv;
447 u16 PllCfg, i, v;
449 HARD_RESET(state);
451 dib0090_write_reg(state, 0x24, EN_PLL | EN_CRYSTAL);
452 dib0090_write_reg(state, 0x1b, EN_DIGCLK | EN_PLL | EN_CRYSTAL); /* PLL, DIG_CLK and CRYSTAL remain */
454 if (!cfg->in_soc) {
455 /* adcClkOutRatio=8->7, release reset */
456 dib0090_write_reg(state, 0x20, ((cfg->io.adc_clock_ratio - 1) << 11) | (0 << 10) | (1 << 9) | (1 << 8) | (0 << 4) | 0);
457 if (cfg->clkoutdrive != 0)
458 dib0090_write_reg(state, 0x23, (0 << 15) | ((!cfg->analog_output) << 14) | (2 << 10) | (1 << 9) | (0 << 8)
459 | (cfg->clkoutdrive << 5) | (cfg->clkouttobamse << 4) | (0 << 2) | (0));
460 else
461 dib0090_write_reg(state, 0x23, (0 << 15) | ((!cfg->analog_output) << 14) | (2 << 10) | (1 << 9) | (0 << 8)
462 | (7 << 5) | (cfg->clkouttobamse << 4) | (0 << 2) | (0));
465 /* Read Pll current config * */
466 PllCfg = dib0090_read_reg(state, 0x21);
468 /** Reconfigure PLL if current setting is different from default setting **/
469 if ((PllCfg & 0x1FFF) != ((cfg->io.pll_range << 12) | (cfg->io.pll_loopdiv << 6) | (cfg->io.pll_prediv)) && (!cfg->in_soc)
470 && !cfg->io.pll_bypass) {
472 /* Set Bypass mode */
473 PllCfg |= (1 << 15);
474 dib0090_write_reg(state, 0x21, PllCfg);
476 /* Set Reset Pll */
477 PllCfg &= ~(1 << 13);
478 dib0090_write_reg(state, 0x21, PllCfg);
480 /*** Set new Pll configuration in bypass and reset state ***/
481 PllCfg = (1 << 15) | (0 << 13) | (cfg->io.pll_range << 12) | (cfg->io.pll_loopdiv << 6) | (cfg->io.pll_prediv);
482 dib0090_write_reg(state, 0x21, PllCfg);
484 /* Remove Reset Pll */
485 PllCfg |= (1 << 13);
486 dib0090_write_reg(state, 0x21, PllCfg);
488 /*** Wait for PLL lock ***/
489 i = 100;
490 do {
491 v = !!(dib0090_read_reg(state, 0x1a) & 0x800);
492 if (v)
493 break;
494 } while (--i);
496 if (i == 0) {
497 dprintk("Pll: Unable to lock Pll");
498 return;
501 /* Finally Remove Bypass mode */
502 PllCfg &= ~(1 << 15);
503 dib0090_write_reg(state, 0x21, PllCfg);
506 if (cfg->io.pll_bypass) {
507 PllCfg |= (cfg->io.pll_bypass << 15);
508 dib0090_write_reg(state, 0x21, PllCfg);
512 static int dib0090_fw_reset_digital(struct dvb_frontend *fe, const struct dib0090_config *cfg)
514 struct dib0090_fw_state *state = fe->tuner_priv;
515 u16 PllCfg;
516 u16 v;
517 int i;
519 dprintk("fw reset digital");
520 HARD_RESET(state);
522 dib0090_fw_write_reg(state, 0x24, EN_PLL | EN_CRYSTAL);
523 dib0090_fw_write_reg(state, 0x1b, EN_DIGCLK | EN_PLL | EN_CRYSTAL); /* PLL, DIG_CLK and CRYSTAL remain */
525 dib0090_fw_write_reg(state, 0x20,
526 ((cfg->io.adc_clock_ratio - 1) << 11) | (0 << 10) | (1 << 9) | (1 << 8) | (cfg->data_tx_drv << 4) | cfg->ls_cfg_pad_drv);
528 v = (0 << 15) | ((!cfg->analog_output) << 14) | (1 << 9) | (0 << 8) | (cfg->clkouttobamse << 4) | (0 << 2) | (0);
529 if (cfg->clkoutdrive != 0)
530 v |= cfg->clkoutdrive << 5;
531 else
532 v |= 7 << 5;
534 v |= 2 << 10;
535 dib0090_fw_write_reg(state, 0x23, v);
537 /* Read Pll current config * */
538 PllCfg = dib0090_fw_read_reg(state, 0x21);
540 /** Reconfigure PLL if current setting is different from default setting **/
541 if ((PllCfg & 0x1FFF) != ((cfg->io.pll_range << 12) | (cfg->io.pll_loopdiv << 6) | (cfg->io.pll_prediv)) && !cfg->io.pll_bypass) {
543 /* Set Bypass mode */
544 PllCfg |= (1 << 15);
545 dib0090_fw_write_reg(state, 0x21, PllCfg);
547 /* Set Reset Pll */
548 PllCfg &= ~(1 << 13);
549 dib0090_fw_write_reg(state, 0x21, PllCfg);
551 /*** Set new Pll configuration in bypass and reset state ***/
552 PllCfg = (1 << 15) | (0 << 13) | (cfg->io.pll_range << 12) | (cfg->io.pll_loopdiv << 6) | (cfg->io.pll_prediv);
553 dib0090_fw_write_reg(state, 0x21, PllCfg);
555 /* Remove Reset Pll */
556 PllCfg |= (1 << 13);
557 dib0090_fw_write_reg(state, 0x21, PllCfg);
559 /*** Wait for PLL lock ***/
560 i = 100;
561 do {
562 v = !!(dib0090_fw_read_reg(state, 0x1a) & 0x800);
563 if (v)
564 break;
565 } while (--i);
567 if (i == 0) {
568 dprintk("Pll: Unable to lock Pll");
569 return -EIO;
572 /* Finally Remove Bypass mode */
573 PllCfg &= ~(1 << 15);
574 dib0090_fw_write_reg(state, 0x21, PllCfg);
577 if (cfg->io.pll_bypass) {
578 PllCfg |= (cfg->io.pll_bypass << 15);
579 dib0090_fw_write_reg(state, 0x21, PllCfg);
582 return dib0090_fw_identify(fe);
585 static int dib0090_wakeup(struct dvb_frontend *fe)
587 struct dib0090_state *state = fe->tuner_priv;
588 if (state->config->sleep)
589 state->config->sleep(fe, 0);
591 /* enable dataTX in case we have been restarted in the wrong moment */
592 dib0090_write_reg(state, 0x23, dib0090_read_reg(state, 0x23) | (1 << 14));
593 return 0;
596 static int dib0090_sleep(struct dvb_frontend *fe)
598 struct dib0090_state *state = fe->tuner_priv;
599 if (state->config->sleep)
600 state->config->sleep(fe, 1);
601 return 0;
604 void dib0090_dcc_freq(struct dvb_frontend *fe, u8 fast)
606 struct dib0090_state *state = fe->tuner_priv;
607 if (fast)
608 dib0090_write_reg(state, 0x04, 0);
609 else
610 dib0090_write_reg(state, 0x04, 1);
613 EXPORT_SYMBOL(dib0090_dcc_freq);
615 static const u16 bb_ramp_pwm_normal_socs[] = {
616 550, /* max BB gain in 10th of dB */
617 (1 << 9) | 8, /* ramp_slope = 1dB of gain -> clock_ticks_per_db = clk_khz / ramp_slope -> BB_RAMP2 */
618 440,
619 (4 << 9) | 0, /* BB_RAMP3 = 26dB */
620 (0 << 9) | 208, /* BB_RAMP4 */
621 (4 << 9) | 208, /* BB_RAMP5 = 29dB */
622 (0 << 9) | 440, /* BB_RAMP6 */
625 static const u16 rf_ramp_pwm_cband_7090[] = {
626 280, /* max RF gain in 10th of dB */
627 18, /* ramp_slope = 1dB of gain -> clock_ticks_per_db = clk_khz / ramp_slope -> RF_RAMP2 */
628 504, /* ramp_max = maximum X used on the ramp */
629 (29 << 10) | 364, /* RF_RAMP5, LNA 1 = 8dB */
630 (0 << 10) | 504, /* RF_RAMP6, LNA 1 */
631 (60 << 10) | 228, /* RF_RAMP7, LNA 2 = 7.7dB */
632 (0 << 10) | 364, /* RF_RAMP8, LNA 2 */
633 (34 << 10) | 109, /* GAIN_4_1, LNA 3 = 6.8dB */
634 (0 << 10) | 228, /* GAIN_4_2, LNA 3 */
635 (37 << 10) | 0, /* RF_RAMP3, LNA 4 = 6.2dB */
636 (0 << 10) | 109, /* RF_RAMP4, LNA 4 */
639 static const u16 rf_ramp_pwm_cband_8090[] = {
640 345, /* max RF gain in 10th of dB */
641 29, /* ramp_slope = 1dB of gain -> clock_ticks_per_db = clk_khz / ramp_slope -> RF_RAMP2 */
642 1000, /* ramp_max = maximum X used on the ramp */
643 (35 << 10) | 772, /* RF_RAMP3, LNA 1 = 8dB */
644 (0 << 10) | 1000, /* RF_RAMP4, LNA 1 */
645 (58 << 10) | 496, /* RF_RAMP5, LNA 2 = 9.5dB */
646 (0 << 10) | 772, /* RF_RAMP6, LNA 2 */
647 (27 << 10) | 200, /* RF_RAMP7, LNA 3 = 10.5dB */
648 (0 << 10) | 496, /* RF_RAMP8, LNA 3 */
649 (40 << 10) | 0, /* GAIN_4_1, LNA 4 = 7dB */
650 (0 << 10) | 200, /* GAIN_4_2, LNA 4 */
653 static const u16 rf_ramp_pwm_uhf_7090[] = {
654 407, /* max RF gain in 10th of dB */
655 13, /* ramp_slope = 1dB of gain -> clock_ticks_per_db = clk_khz / ramp_slope -> RF_RAMP2 */
656 529, /* ramp_max = maximum X used on the ramp */
657 (23 << 10) | 0, /* RF_RAMP3, LNA 1 = 14.7dB */
658 (0 << 10) | 176, /* RF_RAMP4, LNA 1 */
659 (63 << 10) | 400, /* RF_RAMP5, LNA 2 = 8dB */
660 (0 << 10) | 529, /* RF_RAMP6, LNA 2 */
661 (48 << 10) | 316, /* RF_RAMP7, LNA 3 = 6.8dB */
662 (0 << 10) | 400, /* RF_RAMP8, LNA 3 */
663 (29 << 10) | 176, /* GAIN_4_1, LNA 4 = 11.5dB */
664 (0 << 10) | 316, /* GAIN_4_2, LNA 4 */
667 static const u16 rf_ramp_pwm_uhf_8090[] = {
668 388, /* max RF gain in 10th of dB */
669 26, /* ramp_slope = 1dB of gain -> clock_ticks_per_db = clk_khz / ramp_slope -> RF_RAMP2 */
670 1008, /* ramp_max = maximum X used on the ramp */
671 (11 << 10) | 0, /* RF_RAMP3, LNA 1 = 14.7dB */
672 (0 << 10) | 369, /* RF_RAMP4, LNA 1 */
673 (41 << 10) | 809, /* RF_RAMP5, LNA 2 = 8dB */
674 (0 << 10) | 1008, /* RF_RAMP6, LNA 2 */
675 (27 << 10) | 659, /* RF_RAMP7, LNA 3 = 6dB */
676 (0 << 10) | 809, /* RF_RAMP8, LNA 3 */
677 (14 << 10) | 369, /* GAIN_4_1, LNA 4 = 11.5dB */
678 (0 << 10) | 659, /* GAIN_4_2, LNA 4 */
681 static const u16 rf_ramp_pwm_cband[] = {
682 0, /* max RF gain in 10th of dB */
683 0, /* ramp_slope = 1dB of gain -> clock_ticks_per_db = clk_khz / ramp_slope -> 0x2b */
684 0, /* ramp_max = maximum X used on the ramp */
685 (0 << 10) | 0, /* 0x2c, LNA 1 = 0dB */
686 (0 << 10) | 0, /* 0x2d, LNA 1 */
687 (0 << 10) | 0, /* 0x2e, LNA 2 = 0dB */
688 (0 << 10) | 0, /* 0x2f, LNA 2 */
689 (0 << 10) | 0, /* 0x30, LNA 3 = 0dB */
690 (0 << 10) | 0, /* 0x31, LNA 3 */
691 (0 << 10) | 0, /* GAIN_4_1, LNA 4 = 0dB */
692 (0 << 10) | 0, /* GAIN_4_2, LNA 4 */
695 static const u16 rf_ramp_vhf[] = {
696 412, /* max RF gain in 10th of dB */
697 132, 307, 127, /* LNA1, 13.2dB */
698 105, 412, 255, /* LNA2, 10.5dB */
699 50, 50, 127, /* LNA3, 5dB */
700 125, 175, 127, /* LNA4, 12.5dB */
701 0, 0, 127, /* CBAND, 0dB */
704 static const u16 rf_ramp_uhf[] = {
705 412, /* max RF gain in 10th of dB */
706 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 */
707 105, 412, 255, /* LNA2 : 10.5 dB */
708 50, 50, 127, /* LNA3 : 5.0 dB */
709 125, 175, 127, /* LNA4 : 12.5 dB */
710 0, 0, 127, /* CBAND : 0.0 dB */
713 static const u16 rf_ramp_cband_broadmatching[] = /* for p1G only */
715 314, /* Calibrated at 200MHz order has been changed g4-g3-g2-g1 */
716 84, 314, 127, /* LNA1 */
717 80, 230, 255, /* LNA2 */
718 80, 150, 127, /* LNA3 It was measured 12dB, do not lock if 120 */
719 70, 70, 127, /* LNA4 */
720 0, 0, 127, /* CBAND */
723 static const u16 rf_ramp_cband[] = {
724 332, /* max RF gain in 10th of dB */
725 132, 252, 127, /* LNA1, dB */
726 80, 332, 255, /* LNA2, dB */
727 0, 0, 127, /* LNA3, dB */
728 0, 0, 127, /* LNA4, dB */
729 120, 120, 127, /* LT1 CBAND */
732 static const u16 rf_ramp_pwm_vhf[] = {
733 404, /* max RF gain in 10th of dB */
734 25, /* ramp_slope = 1dB of gain -> clock_ticks_per_db = clk_khz / ramp_slope -> 0x2b */
735 1011, /* ramp_max = maximum X used on the ramp */
736 (6 << 10) | 417, /* 0x2c, LNA 1 = 13.2dB */
737 (0 << 10) | 756, /* 0x2d, LNA 1 */
738 (16 << 10) | 756, /* 0x2e, LNA 2 = 10.5dB */
739 (0 << 10) | 1011, /* 0x2f, LNA 2 */
740 (16 << 10) | 290, /* 0x30, LNA 3 = 5dB */
741 (0 << 10) | 417, /* 0x31, LNA 3 */
742 (7 << 10) | 0, /* GAIN_4_1, LNA 4 = 12.5dB */
743 (0 << 10) | 290, /* GAIN_4_2, LNA 4 */
746 static const u16 rf_ramp_pwm_uhf[] = {
747 404, /* max RF gain in 10th of dB */
748 25, /* ramp_slope = 1dB of gain -> clock_ticks_per_db = clk_khz / ramp_slope -> 0x2b */
749 1011, /* ramp_max = maximum X used on the ramp */
750 (6 << 10) | 417, /* 0x2c, LNA 1 = 13.2dB */
751 (0 << 10) | 756, /* 0x2d, LNA 1 */
752 (16 << 10) | 756, /* 0x2e, LNA 2 = 10.5dB */
753 (0 << 10) | 1011, /* 0x2f, LNA 2 */
754 (16 << 10) | 0, /* 0x30, LNA 3 = 5dB */
755 (0 << 10) | 127, /* 0x31, LNA 3 */
756 (7 << 10) | 127, /* GAIN_4_1, LNA 4 = 12.5dB */
757 (0 << 10) | 417, /* GAIN_4_2, LNA 4 */
760 static const u16 bb_ramp_boost[] = {
761 550, /* max BB gain in 10th of dB */
762 260, 260, 26, /* BB1, 26dB */
763 290, 550, 29, /* BB2, 29dB */
766 static const u16 bb_ramp_pwm_normal[] = {
767 500, /* max RF gain in 10th of dB */
768 8, /* ramp_slope = 1dB of gain -> clock_ticks_per_db = clk_khz / ramp_slope -> 0x34 */
769 400,
770 (2 << 9) | 0, /* 0x35 = 21dB */
771 (0 << 9) | 168, /* 0x36 */
772 (2 << 9) | 168, /* 0x37 = 29dB */
773 (0 << 9) | 400, /* 0x38 */
776 struct slope {
777 s16 range;
778 s16 slope;
780 static u16 slopes_to_scale(const struct slope *slopes, u8 num, s16 val)
782 u8 i;
783 u16 rest;
784 u16 ret = 0;
785 for (i = 0; i < num; i++) {
786 if (val > slopes[i].range)
787 rest = slopes[i].range;
788 else
789 rest = val;
790 ret += (rest * slopes[i].slope) / slopes[i].range;
791 val -= rest;
793 return ret;
796 static const struct slope dib0090_wbd_slopes[3] = {
797 {66, 120}, /* -64,-52: offset - 65 */
798 {600, 170}, /* -52,-35: 65 - 665 */
799 {170, 250}, /* -45,-10: 665 - 835 */
802 static s16 dib0090_wbd_to_db(struct dib0090_state *state, u16 wbd)
804 wbd &= 0x3ff;
805 if (wbd < state->wbd_offset)
806 wbd = 0;
807 else
808 wbd -= state->wbd_offset;
809 /* -64dB is the floor */
810 return -640 + (s16) slopes_to_scale(dib0090_wbd_slopes, ARRAY_SIZE(dib0090_wbd_slopes), wbd);
813 static void dib0090_wbd_target(struct dib0090_state *state, u32 rf)
815 u16 offset = 250;
817 /* TODO : DAB digital N+/-1 interferer perfs : offset = 10 */
819 if (state->current_band == BAND_VHF)
820 offset = 650;
821 #ifndef FIRMWARE_FIREFLY
822 if (state->current_band == BAND_VHF)
823 offset = state->config->wbd_vhf_offset;
824 if (state->current_band == BAND_CBAND)
825 offset = state->config->wbd_cband_offset;
826 #endif
828 state->wbd_target = dib0090_wbd_to_db(state, state->wbd_offset + offset);
829 dprintk("wbd-target: %d dB", (u32) state->wbd_target);
832 static const int gain_reg_addr[4] = {
833 0x08, 0x0a, 0x0f, 0x01
836 static void dib0090_gain_apply(struct dib0090_state *state, s16 gain_delta, s16 top_delta, u8 force)
838 u16 rf, bb, ref;
839 u16 i, v, gain_reg[4] = { 0 }, gain;
840 const u16 *g;
842 if (top_delta < -511)
843 top_delta = -511;
844 if (top_delta > 511)
845 top_delta = 511;
847 if (force) {
848 top_delta *= (1 << WBD_ALPHA);
849 gain_delta *= (1 << GAIN_ALPHA);
852 if (top_delta >= ((s16) (state->rf_ramp[0] << WBD_ALPHA) - state->rf_gain_limit)) /* overflow */
853 state->rf_gain_limit = state->rf_ramp[0] << WBD_ALPHA;
854 else
855 state->rf_gain_limit += top_delta;
857 if (state->rf_gain_limit < 0) /*underflow */
858 state->rf_gain_limit = 0;
860 /* use gain as a temporary variable and correct current_gain */
861 gain = ((state->rf_gain_limit >> WBD_ALPHA) + state->bb_ramp[0]) << GAIN_ALPHA;
862 if (gain_delta >= ((s16) gain - state->current_gain)) /* overflow */
863 state->current_gain = gain;
864 else
865 state->current_gain += gain_delta;
866 /* cannot be less than 0 (only if gain_delta is less than 0 we can have current_gain < 0) */
867 if (state->current_gain < 0)
868 state->current_gain = 0;
870 /* now split total gain to rf and bb gain */
871 gain = state->current_gain >> GAIN_ALPHA;
873 /* requested gain is bigger than rf gain limit - ACI/WBD adjustment */
874 if (gain > (state->rf_gain_limit >> WBD_ALPHA)) {
875 rf = state->rf_gain_limit >> WBD_ALPHA;
876 bb = gain - rf;
877 if (bb > state->bb_ramp[0])
878 bb = state->bb_ramp[0];
879 } else { /* high signal level -> all gains put on RF */
880 rf = gain;
881 bb = 0;
884 state->gain[0] = rf;
885 state->gain[1] = bb;
887 /* software ramp */
888 /* Start with RF gains */
889 g = state->rf_ramp + 1; /* point on RF LNA1 max gain */
890 ref = rf;
891 for (i = 0; i < 7; i++) { /* Go over all amplifiers => 5RF amps + 2 BB amps = 7 amps */
892 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 */
893 v = 0; /* force the gain to write for the current amp to be null */
894 else if (ref >= g[1]) /* Gain to set is higher than the high working point of this amp */
895 v = g[2]; /* force this amp to be full gain */
896 else /* compute the value to set to this amp because we are somewhere in his range */
897 v = ((ref - (g[1] - g[0])) * g[2]) / g[0];
899 if (i == 0) /* LNA 1 reg mapping */
900 gain_reg[0] = v;
901 else if (i == 1) /* LNA 2 reg mapping */
902 gain_reg[0] |= v << 7;
903 else if (i == 2) /* LNA 3 reg mapping */
904 gain_reg[1] = v;
905 else if (i == 3) /* LNA 4 reg mapping */
906 gain_reg[1] |= v << 7;
907 else if (i == 4) /* CBAND LNA reg mapping */
908 gain_reg[2] = v | state->rf_lt_def;
909 else if (i == 5) /* BB gain 1 reg mapping */
910 gain_reg[3] = v << 3;
911 else if (i == 6) /* BB gain 2 reg mapping */
912 gain_reg[3] |= v << 8;
914 g += 3; /* go to next gain bloc */
916 /* When RF is finished, start with BB */
917 if (i == 4) {
918 g = state->bb_ramp + 1; /* point on BB gain 1 max gain */
919 ref = bb;
922 gain_reg[3] |= state->bb_1_def;
923 gain_reg[3] |= ((bb % 10) * 100) / 125;
925 #ifdef DEBUG_AGC
926 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,
927 gain_reg[0], gain_reg[1], gain_reg[2], gain_reg[3]);
928 #endif
930 /* Write the amplifier regs */
931 for (i = 0; i < 4; i++) {
932 v = gain_reg[i];
933 if (force || state->gain_reg[i] != v) {
934 state->gain_reg[i] = v;
935 dib0090_write_reg(state, gain_reg_addr[i], v);
940 static void dib0090_set_boost(struct dib0090_state *state, int onoff)
942 state->bb_1_def &= 0xdfff;
943 state->bb_1_def |= onoff << 13;
946 static void dib0090_set_rframp(struct dib0090_state *state, const u16 * cfg)
948 state->rf_ramp = cfg;
951 static void dib0090_set_rframp_pwm(struct dib0090_state *state, const u16 * cfg)
953 state->rf_ramp = cfg;
955 dib0090_write_reg(state, 0x2a, 0xffff);
957 dprintk("total RF gain: %ddB, step: %d", (u32) cfg[0], dib0090_read_reg(state, 0x2a));
959 dib0090_write_regs(state, 0x2c, cfg + 3, 6);
960 dib0090_write_regs(state, 0x3e, cfg + 9, 2);
963 static void dib0090_set_bbramp(struct dib0090_state *state, const u16 * cfg)
965 state->bb_ramp = cfg;
966 dib0090_set_boost(state, cfg[0] > 500); /* we want the boost if the gain is higher that 50dB */
969 static void dib0090_set_bbramp_pwm(struct dib0090_state *state, const u16 * cfg)
971 state->bb_ramp = cfg;
973 dib0090_set_boost(state, cfg[0] > 500); /* we want the boost if the gain is higher that 50dB */
975 dib0090_write_reg(state, 0x33, 0xffff);
976 dprintk("total BB gain: %ddB, step: %d", (u32) cfg[0], dib0090_read_reg(state, 0x33));
977 dib0090_write_regs(state, 0x35, cfg + 3, 4);
980 void dib0090_pwm_gain_reset(struct dvb_frontend *fe)
982 struct dib0090_state *state = fe->tuner_priv;
983 /* reset the AGC */
985 if (state->config->use_pwm_agc) {
986 #ifdef CONFIG_BAND_SBAND
987 if (state->current_band == BAND_SBAND) {
988 dib0090_set_rframp_pwm(state, rf_ramp_pwm_sband);
989 dib0090_set_bbramp_pwm(state, bb_ramp_pwm_boost);
990 } else
991 #endif
992 #ifdef CONFIG_BAND_CBAND
993 if (state->current_band == BAND_CBAND) {
994 if (state->identity.in_soc) {
995 dib0090_set_bbramp_pwm(state, bb_ramp_pwm_normal_socs);
996 if (state->identity.version == SOC_8090_P1G_11R1 || state->identity.version == SOC_8090_P1G_21R1)
997 dib0090_set_rframp_pwm(state, rf_ramp_pwm_cband_8090);
998 else if (state->identity.version == SOC_7090_P1G_11R1 || state->identity.version == SOC_7090_P1G_21R1)
999 dib0090_set_rframp_pwm(state, rf_ramp_pwm_cband_7090);
1000 } else {
1001 dib0090_set_rframp_pwm(state, rf_ramp_pwm_cband);
1002 dib0090_set_bbramp_pwm(state, bb_ramp_pwm_normal);
1004 } else
1005 #endif
1006 #ifdef CONFIG_BAND_VHF
1007 if (state->current_band == BAND_VHF) {
1008 if (state->identity.in_soc) {
1009 dib0090_set_bbramp_pwm(state, bb_ramp_pwm_normal_socs);
1010 } else {
1011 dib0090_set_rframp_pwm(state, rf_ramp_pwm_vhf);
1012 dib0090_set_bbramp_pwm(state, bb_ramp_pwm_normal);
1014 } else
1015 #endif
1017 if (state->identity.in_soc) {
1018 if (state->identity.version == SOC_8090_P1G_11R1 || state->identity.version == SOC_8090_P1G_21R1)
1019 dib0090_set_rframp_pwm(state, rf_ramp_pwm_uhf_8090);
1020 else if (state->identity.version == SOC_7090_P1G_11R1 || state->identity.version == SOC_7090_P1G_21R1)
1021 dib0090_set_rframp_pwm(state, rf_ramp_pwm_uhf_7090);
1022 dib0090_set_bbramp_pwm(state, bb_ramp_pwm_normal_socs);
1023 } else {
1024 dib0090_set_rframp_pwm(state, rf_ramp_pwm_uhf);
1025 dib0090_set_bbramp_pwm(state, bb_ramp_pwm_normal);
1029 if (state->rf_ramp[0] != 0)
1030 dib0090_write_reg(state, 0x32, (3 << 11));
1031 else
1032 dib0090_write_reg(state, 0x32, (0 << 11));
1034 dib0090_write_reg(state, 0x04, 0x01);
1035 dib0090_write_reg(state, 0x39, (1 << 10));
1039 EXPORT_SYMBOL(dib0090_pwm_gain_reset);
1041 static u32 dib0090_get_slow_adc_val(struct dib0090_state *state)
1043 u16 adc_val = dib0090_read_reg(state, 0x1d);
1044 if (state->identity.in_soc)
1045 adc_val >>= 2;
1046 return adc_val;
1049 int dib0090_gain_control(struct dvb_frontend *fe)
1051 struct dib0090_state *state = fe->tuner_priv;
1052 enum frontend_tune_state *tune_state = &state->tune_state;
1053 int ret = 10;
1055 u16 wbd_val = 0;
1056 u8 apply_gain_immediatly = 1;
1057 s16 wbd_error = 0, adc_error = 0;
1059 if (*tune_state == CT_AGC_START) {
1060 state->agc_freeze = 0;
1061 dib0090_write_reg(state, 0x04, 0x0);
1063 #ifdef CONFIG_BAND_SBAND
1064 if (state->current_band == BAND_SBAND) {
1065 dib0090_set_rframp(state, rf_ramp_sband);
1066 dib0090_set_bbramp(state, bb_ramp_boost);
1067 } else
1068 #endif
1069 #ifdef CONFIG_BAND_VHF
1070 if (state->current_band == BAND_VHF && !state->identity.p1g) {
1071 dib0090_set_rframp(state, rf_ramp_vhf);
1072 dib0090_set_bbramp(state, bb_ramp_boost);
1073 } else
1074 #endif
1075 #ifdef CONFIG_BAND_CBAND
1076 if (state->current_band == BAND_CBAND && !state->identity.p1g) {
1077 dib0090_set_rframp(state, rf_ramp_cband);
1078 dib0090_set_bbramp(state, bb_ramp_boost);
1079 } else
1080 #endif
1081 if ((state->current_band == BAND_CBAND || state->current_band == BAND_VHF) && state->identity.p1g) {
1082 dib0090_set_rframp(state, rf_ramp_cband_broadmatching);
1083 dib0090_set_bbramp(state, bb_ramp_boost);
1084 } else {
1085 dib0090_set_rframp(state, rf_ramp_uhf);
1086 dib0090_set_bbramp(state, bb_ramp_boost);
1089 dib0090_write_reg(state, 0x32, 0);
1090 dib0090_write_reg(state, 0x39, 0);
1092 dib0090_wbd_target(state, state->current_rf);
1094 state->rf_gain_limit = state->rf_ramp[0] << WBD_ALPHA;
1095 state->current_gain = ((state->rf_ramp[0] + state->bb_ramp[0]) / 2) << GAIN_ALPHA;
1097 *tune_state = CT_AGC_STEP_0;
1098 } else if (!state->agc_freeze) {
1099 s16 wbd = 0, i, cnt;
1101 int adc;
1102 wbd_val = dib0090_get_slow_adc_val(state);
1104 if (*tune_state == CT_AGC_STEP_0)
1105 cnt = 5;
1106 else
1107 cnt = 1;
1109 for (i = 0; i < cnt; i++) {
1110 wbd_val = dib0090_get_slow_adc_val(state);
1111 wbd += dib0090_wbd_to_db(state, wbd_val);
1113 wbd /= cnt;
1114 wbd_error = state->wbd_target - wbd;
1116 if (*tune_state == CT_AGC_STEP_0) {
1117 if (wbd_error < 0 && state->rf_gain_limit > 0 && !state->identity.p1g) {
1118 #ifdef CONFIG_BAND_CBAND
1119 /* in case of CBAND tune reduce first the lt_gain2 before adjusting the RF gain */
1120 u8 ltg2 = (state->rf_lt_def >> 10) & 0x7;
1121 if (state->current_band == BAND_CBAND && ltg2) {
1122 ltg2 >>= 1;
1123 state->rf_lt_def &= ltg2 << 10; /* reduce in 3 steps from 7 to 0 */
1125 #endif
1126 } else {
1127 state->agc_step = 0;
1128 *tune_state = CT_AGC_STEP_1;
1130 } else {
1131 /* calc the adc power */
1132 adc = state->config->get_adc_power(fe);
1133 adc = (adc * ((s32) 355774) + (((s32) 1) << 20)) >> 21; /* included in [0:-700] */
1135 adc_error = (s16) (((s32) ADC_TARGET) - adc);
1136 #ifdef CONFIG_STANDARD_DAB
1137 if (state->fe->dtv_property_cache.delivery_system == STANDARD_DAB)
1138 adc_error -= 10;
1139 #endif
1140 #ifdef CONFIG_STANDARD_DVBT
1141 if (state->fe->dtv_property_cache.delivery_system == STANDARD_DVBT &&
1142 (state->fe->dtv_property_cache.modulation == QAM_64 || state->fe->dtv_property_cache.modulation == QAM_16))
1143 adc_error += 60;
1144 #endif
1145 #ifdef CONFIG_SYS_ISDBT
1146 if ((state->fe->dtv_property_cache.delivery_system == SYS_ISDBT) && (((state->fe->dtv_property_cache.layer[0].segment_count >
1149 ((state->fe->dtv_property_cache.layer[0].modulation ==
1150 QAM_64)
1151 || (state->fe->dtv_property_cache.
1152 layer[0].modulation == QAM_16)))
1154 ((state->fe->dtv_property_cache.layer[1].segment_count >
1157 ((state->fe->dtv_property_cache.layer[1].modulation ==
1158 QAM_64)
1159 || (state->fe->dtv_property_cache.
1160 layer[1].modulation == QAM_16)))
1162 ((state->fe->dtv_property_cache.layer[2].segment_count >
1165 ((state->fe->dtv_property_cache.layer[2].modulation ==
1166 QAM_64)
1167 || (state->fe->dtv_property_cache.
1168 layer[2].modulation == QAM_16)))
1171 adc_error += 60;
1172 #endif
1174 if (*tune_state == CT_AGC_STEP_1) { /* quickly go to the correct range of the ADC power */
1175 if (ABS(adc_error) < 50 || state->agc_step++ > 5) {
1177 #ifdef CONFIG_STANDARD_DAB
1178 if (state->fe->dtv_property_cache.delivery_system == STANDARD_DAB) {
1179 dib0090_write_reg(state, 0x02, (1 << 15) | (15 << 11) | (31 << 6) | (63)); /* cap value = 63 : narrow BB filter : Fc = 1.8MHz */
1180 dib0090_write_reg(state, 0x04, 0x0);
1181 } else
1182 #endif
1184 dib0090_write_reg(state, 0x02, (1 << 15) | (3 << 11) | (6 << 6) | (32));
1185 dib0090_write_reg(state, 0x04, 0x01); /*0 = 1KHz ; 1 = 150Hz ; 2 = 50Hz ; 3 = 50KHz ; 4 = servo fast */
1188 *tune_state = CT_AGC_STOP;
1190 } else {
1191 /* everything higher than or equal to CT_AGC_STOP means tracking */
1192 ret = 100; /* 10ms interval */
1193 apply_gain_immediatly = 0;
1196 #ifdef DEBUG_AGC
1197 dprintk
1198 ("tune state %d, ADC = %3ddB (ADC err %3d) WBD %3ddB (WBD err %3d, WBD val SADC: %4d), RFGainLimit (TOP): %3d, signal: %3ddBm",
1199 (u32) *tune_state, (u32) adc, (u32) adc_error, (u32) wbd, (u32) wbd_error, (u32) wbd_val,
1200 (u32) state->rf_gain_limit >> WBD_ALPHA, (s32) 200 + adc - (state->current_gain >> GAIN_ALPHA));
1201 #endif
1204 /* apply gain */
1205 if (!state->agc_freeze)
1206 dib0090_gain_apply(state, adc_error, wbd_error, apply_gain_immediatly);
1207 return ret;
1210 EXPORT_SYMBOL(dib0090_gain_control);
1212 void dib0090_get_current_gain(struct dvb_frontend *fe, u16 * rf, u16 * bb, u16 * rf_gain_limit, u16 * rflt)
1214 struct dib0090_state *state = fe->tuner_priv;
1215 if (rf)
1216 *rf = state->gain[0];
1217 if (bb)
1218 *bb = state->gain[1];
1219 if (rf_gain_limit)
1220 *rf_gain_limit = state->rf_gain_limit;
1221 if (rflt)
1222 *rflt = (state->rf_lt_def >> 10) & 0x7;
1225 EXPORT_SYMBOL(dib0090_get_current_gain);
1227 u16 dib0090_get_wbd_offset(struct dvb_frontend *fe)
1229 struct dib0090_state *state = fe->tuner_priv;
1230 u32 f_MHz = state->fe->dtv_property_cache.frequency / 1000000;
1231 s32 current_temp = state->temperature;
1232 s32 wbd_thot, wbd_tcold;
1233 const struct dib0090_wbd_slope *wbd = state->current_wbd_table;
1235 while (f_MHz > wbd->max_freq)
1236 wbd++;
1238 dprintk("using wbd-table-entry with max freq %d", wbd->max_freq);
1240 if (current_temp < 0)
1241 current_temp = 0;
1242 if (current_temp > 128)
1243 current_temp = 128;
1245 state->wbdmux &= ~(7 << 13);
1246 if (wbd->wbd_gain != 0)
1247 state->wbdmux |= (wbd->wbd_gain << 13);
1248 else
1249 state->wbdmux |= (4 << 13);
1251 dib0090_write_reg(state, 0x10, state->wbdmux);
1253 wbd_thot = wbd->offset_hot - (((u32) wbd->slope_hot * f_MHz) >> 6);
1254 wbd_tcold = wbd->offset_cold - (((u32) wbd->slope_cold * f_MHz) >> 6);
1256 wbd_tcold += ((wbd_thot - wbd_tcold) * current_temp) >> 7;
1258 state->wbd_target = dib0090_wbd_to_db(state, state->wbd_offset + wbd_tcold);
1259 dprintk("wbd-target: %d dB", (u32) state->wbd_target);
1260 dprintk("wbd offset applied is %d", wbd_tcold);
1262 return state->wbd_offset + wbd_tcold;
1265 EXPORT_SYMBOL(dib0090_get_wbd_offset);
1267 static const u16 dib0090_defaults[] = {
1269 25, 0x01,
1270 0x0000,
1271 0x99a0,
1272 0x6008,
1273 0x0000,
1274 0x8bcb,
1275 0x0000,
1276 0x0405,
1277 0x0000,
1278 0x0000,
1279 0x0000,
1280 0xb802,
1281 0x0300,
1282 0x2d12,
1283 0xbac0,
1284 0x7c00,
1285 0xdbb9,
1286 0x0954,
1287 0x0743,
1288 0x8000,
1289 0x0001,
1290 0x0040,
1291 0x0100,
1292 0x0000,
1293 0xe910,
1294 0x149e,
1296 1, 0x1c,
1297 0xff2d,
1299 1, 0x39,
1300 0x0000,
1302 2, 0x1e,
1303 0x07FF,
1304 0x0007,
1306 1, 0x24,
1307 EN_UHF | EN_CRYSTAL,
1309 2, 0x3c,
1310 0x3ff,
1311 0x111,
1315 static const u16 dib0090_p1g_additionnal_defaults[] = {
1316 1, 0x05,
1317 0xabcd,
1319 1, 0x11,
1320 0x00b4,
1322 1, 0x1c,
1323 0xfffd,
1325 1, 0x40,
1326 0x108,
1330 static void dib0090_set_default_config(struct dib0090_state *state, const u16 * n)
1332 u16 l, r;
1334 l = pgm_read_word(n++);
1335 while (l) {
1336 r = pgm_read_word(n++);
1337 do {
1338 dib0090_write_reg(state, r, pgm_read_word(n++));
1339 r++;
1340 } while (--l);
1341 l = pgm_read_word(n++);
1345 #define CAP_VALUE_MIN (u8) 9
1346 #define CAP_VALUE_MAX (u8) 40
1347 #define HR_MIN (u8) 25
1348 #define HR_MAX (u8) 40
1349 #define POLY_MIN (u8) 0
1350 #define POLY_MAX (u8) 8
1352 void dib0090_set_EFUSE(struct dib0090_state *state)
1354 u8 c, h, n;
1355 u16 e2, e4;
1356 u16 cal;
1358 e2 = dib0090_read_reg(state, 0x26);
1359 e4 = dib0090_read_reg(state, 0x28);
1361 if ((state->identity.version == P1D_E_F) ||
1362 (state->identity.version == P1G) || (e2 == 0xffff)) {
1364 dib0090_write_reg(state, 0x22, 0x10);
1365 cal = (dib0090_read_reg(state, 0x22) >> 6) & 0x3ff;
1367 if ((cal < 670) || (cal == 1023))
1368 cal = 850;
1369 n = 165 - ((cal * 10)>>6) ;
1370 e2 = e4 = (3<<12) | (34<<6) | (n);
1373 if (e2 != e4)
1374 e2 &= e4; /* Remove the redundancy */
1376 if (e2 != 0xffff) {
1377 c = e2 & 0x3f;
1378 n = (e2 >> 12) & 0xf;
1379 h = (e2 >> 6) & 0x3f;
1381 if ((c >= CAP_VALUE_MAX) || (c <= CAP_VALUE_MIN))
1382 c = 32;
1383 if ((h >= HR_MAX) || (h <= HR_MIN))
1384 h = 34;
1385 if ((n >= POLY_MAX) || (n <= POLY_MIN))
1386 n = 3;
1388 dib0090_write_reg(state, 0x13, (h << 10)) ;
1389 e2 = (n<<11) | ((h>>2)<<6) | (c);
1390 dib0090_write_reg(state, 0x2, e2) ; /* Load the BB_2 */
1394 static int dib0090_reset(struct dvb_frontend *fe)
1396 struct dib0090_state *state = fe->tuner_priv;
1398 dib0090_reset_digital(fe, state->config);
1399 if (dib0090_identify(fe) < 0)
1400 return -EIO;
1402 #ifdef CONFIG_TUNER_DIB0090_P1B_SUPPORT
1403 if (!(state->identity.version & 0x1)) /* it is P1B - reset is already done */
1404 return 0;
1405 #endif
1407 if (!state->identity.in_soc) {
1408 if ((dib0090_read_reg(state, 0x1a) >> 5) & 0x2)
1409 dib0090_write_reg(state, 0x1b, (EN_IQADC | EN_BB | EN_BIAS | EN_DIGCLK | EN_PLL | EN_CRYSTAL));
1410 else
1411 dib0090_write_reg(state, 0x1b, (EN_DIGCLK | EN_PLL | EN_CRYSTAL));
1414 dib0090_set_default_config(state, dib0090_defaults);
1416 if (state->identity.in_soc)
1417 dib0090_write_reg(state, 0x18, 0x2910); /* charge pump current = 0 */
1419 if (state->identity.p1g)
1420 dib0090_set_default_config(state, dib0090_p1g_additionnal_defaults);
1422 /* Update the efuse : Only available for KROSUS > P1C and SOC as well*/
1423 if (((state->identity.version & 0x1f) >= P1D_E_F) || (state->identity.in_soc))
1424 dib0090_set_EFUSE(state);
1426 /* Congigure in function of the crystal */
1427 if (state->config->io.clock_khz >= 24000)
1428 dib0090_write_reg(state, 0x14, 1);
1429 else
1430 dib0090_write_reg(state, 0x14, 2);
1431 dprintk("Pll lock : %d", (dib0090_read_reg(state, 0x1a) >> 11) & 0x1);
1433 state->calibrate = DC_CAL | WBD_CAL | TEMP_CAL; /* enable iq-offset-calibration and wbd-calibration when tuning next time */
1435 return 0;
1438 #define steps(u) (((u) > 15) ? ((u)-16) : (u))
1439 #define INTERN_WAIT 10
1440 static int dib0090_get_offset(struct dib0090_state *state, enum frontend_tune_state *tune_state)
1442 int ret = INTERN_WAIT * 10;
1444 switch (*tune_state) {
1445 case CT_TUNER_STEP_2:
1446 /* Turns to positive */
1447 dib0090_write_reg(state, 0x1f, 0x7);
1448 *tune_state = CT_TUNER_STEP_3;
1449 break;
1451 case CT_TUNER_STEP_3:
1452 state->adc_diff = dib0090_read_reg(state, 0x1d);
1454 /* Turns to negative */
1455 dib0090_write_reg(state, 0x1f, 0x4);
1456 *tune_state = CT_TUNER_STEP_4;
1457 break;
1459 case CT_TUNER_STEP_4:
1460 state->adc_diff -= dib0090_read_reg(state, 0x1d);
1461 *tune_state = CT_TUNER_STEP_5;
1462 ret = 0;
1463 break;
1465 default:
1466 break;
1469 return ret;
1472 struct dc_calibration {
1473 u8 addr;
1474 u8 offset;
1475 u8 pga:1;
1476 u16 bb1;
1477 u8 i:1;
1480 static const struct dc_calibration dc_table[] = {
1481 /* Step1 BB gain1= 26 with boost 1, gain 2 = 0 */
1482 {0x06, 5, 1, (1 << 13) | (0 << 8) | (26 << 3), 1},
1483 {0x07, 11, 1, (1 << 13) | (0 << 8) | (26 << 3), 0},
1484 /* Step 2 BB gain 1 = 26 with boost = 1 & gain 2 = 29 */
1485 {0x06, 0, 0, (1 << 13) | (29 << 8) | (26 << 3), 1},
1486 {0x06, 10, 0, (1 << 13) | (29 << 8) | (26 << 3), 0},
1487 {0},
1490 static const struct dc_calibration dc_p1g_table[] = {
1491 /* Step1 BB gain1= 26 with boost 1, gain 2 = 0 */
1492 /* addr ; trim reg offset ; pga ; CTRL_BB1 value ; i or q */
1493 {0x06, 5, 1, (1 << 13) | (0 << 8) | (15 << 3), 1},
1494 {0x07, 11, 1, (1 << 13) | (0 << 8) | (15 << 3), 0},
1495 /* Step 2 BB gain 1 = 26 with boost = 1 & gain 2 = 29 */
1496 {0x06, 0, 0, (1 << 13) | (29 << 8) | (15 << 3), 1},
1497 {0x06, 10, 0, (1 << 13) | (29 << 8) | (15 << 3), 0},
1498 {0},
1501 static void dib0090_set_trim(struct dib0090_state *state)
1503 u16 *val;
1505 if (state->dc->addr == 0x07)
1506 val = &state->bb7;
1507 else
1508 val = &state->bb6;
1510 *val &= ~(0x1f << state->dc->offset);
1511 *val |= state->step << state->dc->offset;
1513 dib0090_write_reg(state, state->dc->addr, *val);
1516 static int dib0090_dc_offset_calibration(struct dib0090_state *state, enum frontend_tune_state *tune_state)
1518 int ret = 0;
1519 u16 reg;
1521 switch (*tune_state) {
1522 case CT_TUNER_START:
1523 dprintk("Start DC offset calibration");
1525 /* force vcm2 = 0.8V */
1526 state->bb6 = 0;
1527 state->bb7 = 0x040d;
1529 /* the LNA AND LO are off */
1530 reg = dib0090_read_reg(state, 0x24) & 0x0ffb; /* shutdown lna and lo */
1531 dib0090_write_reg(state, 0x24, reg);
1533 state->wbdmux = dib0090_read_reg(state, 0x10);
1534 dib0090_write_reg(state, 0x10, (state->wbdmux & ~(0xff << 3)) | (0x7 << 3) | 0x3);
1535 dib0090_write_reg(state, 0x23, dib0090_read_reg(state, 0x23) & ~(1 << 14));
1537 state->dc = dc_table;
1539 if (state->identity.p1g)
1540 state->dc = dc_p1g_table;
1541 *tune_state = CT_TUNER_STEP_0;
1543 /* fall through */
1545 case CT_TUNER_STEP_0:
1546 dprintk("Sart/continue DC calibration for %s path", (state->dc->i == 1) ? "I" : "Q");
1547 dib0090_write_reg(state, 0x01, state->dc->bb1);
1548 dib0090_write_reg(state, 0x07, state->bb7 | (state->dc->i << 7));
1550 state->step = 0;
1551 state->min_adc_diff = 1023;
1552 *tune_state = CT_TUNER_STEP_1;
1553 ret = 50;
1554 break;
1556 case CT_TUNER_STEP_1:
1557 dib0090_set_trim(state);
1558 *tune_state = CT_TUNER_STEP_2;
1559 break;
1561 case CT_TUNER_STEP_2:
1562 case CT_TUNER_STEP_3:
1563 case CT_TUNER_STEP_4:
1564 ret = dib0090_get_offset(state, tune_state);
1565 break;
1567 case CT_TUNER_STEP_5: /* found an offset */
1568 dprintk("adc_diff = %d, current step= %d", (u32) state->adc_diff, state->step);
1569 if (state->step == 0 && state->adc_diff < 0) {
1570 state->min_adc_diff = -1023;
1571 dprintk("Change of sign of the minimum adc diff");
1574 dprintk("adc_diff = %d, min_adc_diff = %d current_step = %d", state->adc_diff, state->min_adc_diff, state->step);
1576 /* first turn for this frequency */
1577 if (state->step == 0) {
1578 if (state->dc->pga && state->adc_diff < 0)
1579 state->step = 0x10;
1580 if (state->dc->pga == 0 && state->adc_diff > 0)
1581 state->step = 0x10;
1584 /* Look for a change of Sign in the Adc_diff.min_adc_diff is used to STORE the setp N-1 */
1585 if ((state->adc_diff & 0x8000) == (state->min_adc_diff & 0x8000) && steps(state->step) < 15) {
1586 /* stop search when the delta the sign is changing and Steps =15 and Step=0 is force for continuance */
1587 state->step++;
1588 state->min_adc_diff = state->adc_diff;
1589 *tune_state = CT_TUNER_STEP_1;
1590 } else {
1591 /* the minimum was what we have seen in the step before */
1592 if (ABS(state->adc_diff) > ABS(state->min_adc_diff)) {
1593 dprintk("Since adc_diff N = %d > adc_diff step N-1 = %d, Come back one step", state->adc_diff, state->min_adc_diff);
1594 state->step--;
1597 dib0090_set_trim(state);
1598 dprintk("BB Offset Cal, BBreg=%hd,Offset=%hd,Value Set=%hd", state->dc->addr, state->adc_diff, state->step);
1600 state->dc++;
1601 if (state->dc->addr == 0) /* done */
1602 *tune_state = CT_TUNER_STEP_6;
1603 else
1604 *tune_state = CT_TUNER_STEP_0;
1607 break;
1609 case CT_TUNER_STEP_6:
1610 dib0090_write_reg(state, 0x07, state->bb7 & ~0x0008);
1611 dib0090_write_reg(state, 0x1f, 0x7);
1612 *tune_state = CT_TUNER_START; /* reset done -> real tuning can now begin */
1613 state->calibrate &= ~DC_CAL;
1614 default:
1615 break;
1617 return ret;
1620 static int dib0090_wbd_calibration(struct dib0090_state *state, enum frontend_tune_state *tune_state)
1622 u8 wbd_gain;
1623 const struct dib0090_wbd_slope *wbd = state->current_wbd_table;
1625 switch (*tune_state) {
1626 case CT_TUNER_START:
1627 while (state->current_rf / 1000 > wbd->max_freq)
1628 wbd++;
1629 if (wbd->wbd_gain != 0)
1630 wbd_gain = wbd->wbd_gain;
1631 else {
1632 wbd_gain = 4;
1633 #if defined(CONFIG_BAND_LBAND) || defined(CONFIG_BAND_SBAND)
1634 if ((state->current_band == BAND_LBAND) || (state->current_band == BAND_SBAND))
1635 wbd_gain = 2;
1636 #endif
1639 if (wbd_gain == state->wbd_calibration_gain) { /* the WBD calibration has already been done */
1640 *tune_state = CT_TUNER_START;
1641 state->calibrate &= ~WBD_CAL;
1642 return 0;
1645 dib0090_write_reg(state, 0x10, 0x1b81 | (1 << 10) | (wbd_gain << 13) | (1 << 3));
1647 dib0090_write_reg(state, 0x24, ((EN_UHF & 0x0fff) | (1 << 1)));
1648 *tune_state = CT_TUNER_STEP_0;
1649 state->wbd_calibration_gain = wbd_gain;
1650 return 90; /* wait for the WBDMUX to switch and for the ADC to sample */
1652 case CT_TUNER_STEP_0:
1653 state->wbd_offset = dib0090_get_slow_adc_val(state);
1654 dprintk("WBD calibration offset = %d", state->wbd_offset);
1655 *tune_state = CT_TUNER_START; /* reset done -> real tuning can now begin */
1656 state->calibrate &= ~WBD_CAL;
1657 break;
1659 default:
1660 break;
1662 return 0;
1665 static void dib0090_set_bandwidth(struct dib0090_state *state)
1667 u16 tmp;
1669 if (state->fe->dtv_property_cache.bandwidth_hz / 1000 <= 5000)
1670 tmp = (3 << 14);
1671 else if (state->fe->dtv_property_cache.bandwidth_hz / 1000 <= 6000)
1672 tmp = (2 << 14);
1673 else if (state->fe->dtv_property_cache.bandwidth_hz / 1000 <= 7000)
1674 tmp = (1 << 14);
1675 else
1676 tmp = (0 << 14);
1678 state->bb_1_def &= 0x3fff;
1679 state->bb_1_def |= tmp;
1681 dib0090_write_reg(state, 0x01, state->bb_1_def); /* be sure that we have the right bb-filter */
1683 dib0090_write_reg(state, 0x03, 0x6008); /* = 0x6008 : vcm3_trim = 1 ; filter2_gm1_trim = 8 ; filter2_cutoff_freq = 0 */
1684 dib0090_write_reg(state, 0x04, 0x1); /* 0 = 1KHz ; 1 = 50Hz ; 2 = 150Hz ; 3 = 50KHz ; 4 = servo fast */
1685 if (state->identity.in_soc) {
1686 dib0090_write_reg(state, 0x05, 0x9bcf); /* attenuator_ibias_tri = 2 ; input_stage_ibias_tr = 1 ; nc = 11 ; ext_gm_trim = 1 ; obuf_ibias_trim = 4 ; filter13_gm2_ibias_t = 15 */
1687 } else {
1688 dib0090_write_reg(state, 0x02, (5 << 11) | (8 << 6) | (22 & 0x3f)); /* 22 = cap_value */
1689 dib0090_write_reg(state, 0x05, 0xabcd); /* = 0xabcd : attenuator_ibias_tri = 2 ; input_stage_ibias_tr = 2 ; nc = 11 ; ext_gm_trim = 1 ; obuf_ibias_trim = 4 ; filter13_gm2_ibias_t = 13 */
1693 static const struct dib0090_pll dib0090_pll_table[] = {
1694 #ifdef CONFIG_BAND_CBAND
1695 {56000, 0, 9, 48, 6},
1696 {70000, 1, 9, 48, 6},
1697 {87000, 0, 8, 32, 4},
1698 {105000, 1, 8, 32, 4},
1699 {115000, 0, 7, 24, 6},
1700 {140000, 1, 7, 24, 6},
1701 {170000, 0, 6, 16, 4},
1702 #endif
1703 #ifdef CONFIG_BAND_VHF
1704 {200000, 1, 6, 16, 4},
1705 {230000, 0, 5, 12, 6},
1706 {280000, 1, 5, 12, 6},
1707 {340000, 0, 4, 8, 4},
1708 {380000, 1, 4, 8, 4},
1709 {450000, 0, 3, 6, 6},
1710 #endif
1711 #ifdef CONFIG_BAND_UHF
1712 {580000, 1, 3, 6, 6},
1713 {700000, 0, 2, 4, 4},
1714 {860000, 1, 2, 4, 4},
1715 #endif
1716 #ifdef CONFIG_BAND_LBAND
1717 {1800000, 1, 0, 2, 4},
1718 #endif
1719 #ifdef CONFIG_BAND_SBAND
1720 {2900000, 0, 14, 1, 4},
1721 #endif
1724 static const struct dib0090_tuning dib0090_tuning_table_fm_vhf_on_cband[] = {
1726 #ifdef CONFIG_BAND_CBAND
1727 {184000, 4, 1, 15, 0x280, 0x2912, 0xb94e, EN_CAB},
1728 {227000, 4, 3, 15, 0x280, 0x2912, 0xb94e, EN_CAB},
1729 {380000, 4, 7, 15, 0x280, 0x2912, 0xb94e, EN_CAB},
1730 #endif
1731 #ifdef CONFIG_BAND_UHF
1732 {520000, 2, 0, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},
1733 {550000, 2, 2, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},
1734 {650000, 2, 3, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},
1735 {750000, 2, 5, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},
1736 {850000, 2, 6, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},
1737 {900000, 2, 7, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},
1738 #endif
1739 #ifdef CONFIG_BAND_LBAND
1740 {1500000, 4, 0, 20, 0x300, 0x1912, 0x82c9, EN_LBD},
1741 {1600000, 4, 1, 20, 0x300, 0x1912, 0x82c9, EN_LBD},
1742 {1800000, 4, 3, 20, 0x300, 0x1912, 0x82c9, EN_LBD},
1743 #endif
1744 #ifdef CONFIG_BAND_SBAND
1745 {2300000, 1, 4, 20, 0x300, 0x2d2A, 0x82c7, EN_SBD},
1746 {2900000, 1, 7, 20, 0x280, 0x2deb, 0x8347, EN_SBD},
1747 #endif
1750 static const struct dib0090_tuning dib0090_tuning_table[] = {
1752 #ifdef CONFIG_BAND_CBAND
1753 {170000, 4, 1, 15, 0x280, 0x2912, 0xb94e, EN_CAB},
1754 #endif
1755 #ifdef CONFIG_BAND_VHF
1756 {184000, 1, 1, 15, 0x300, 0x4d12, 0xb94e, EN_VHF},
1757 {227000, 1, 3, 15, 0x300, 0x4d12, 0xb94e, EN_VHF},
1758 {380000, 1, 7, 15, 0x300, 0x4d12, 0xb94e, EN_VHF},
1759 #endif
1760 #ifdef CONFIG_BAND_UHF
1761 {520000, 2, 0, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},
1762 {550000, 2, 2, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},
1763 {650000, 2, 3, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},
1764 {750000, 2, 5, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},
1765 {850000, 2, 6, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},
1766 {900000, 2, 7, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},
1767 #endif
1768 #ifdef CONFIG_BAND_LBAND
1769 {1500000, 4, 0, 20, 0x300, 0x1912, 0x82c9, EN_LBD},
1770 {1600000, 4, 1, 20, 0x300, 0x1912, 0x82c9, EN_LBD},
1771 {1800000, 4, 3, 20, 0x300, 0x1912, 0x82c9, EN_LBD},
1772 #endif
1773 #ifdef CONFIG_BAND_SBAND
1774 {2300000, 1, 4, 20, 0x300, 0x2d2A, 0x82c7, EN_SBD},
1775 {2900000, 1, 7, 20, 0x280, 0x2deb, 0x8347, EN_SBD},
1776 #endif
1779 static const struct dib0090_tuning dib0090_p1g_tuning_table[] = {
1780 #ifdef CONFIG_BAND_CBAND
1781 {170000, 4, 1, 0x820f, 0x300, 0x2d22, 0x82cb, EN_CAB},
1782 #endif
1783 #ifdef CONFIG_BAND_VHF
1784 {184000, 1, 1, 15, 0x300, 0x4d12, 0xb94e, EN_VHF},
1785 {227000, 1, 3, 15, 0x300, 0x4d12, 0xb94e, EN_VHF},
1786 {380000, 1, 7, 15, 0x300, 0x4d12, 0xb94e, EN_VHF},
1787 #endif
1788 #ifdef CONFIG_BAND_UHF
1789 {510000, 2, 0, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},
1790 {540000, 2, 1, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},
1791 {600000, 2, 3, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},
1792 {630000, 2, 4, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},
1793 {680000, 2, 5, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},
1794 {720000, 2, 6, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},
1795 {900000, 2, 7, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},
1796 #endif
1797 #ifdef CONFIG_BAND_LBAND
1798 {1500000, 4, 0, 20, 0x300, 0x1912, 0x82c9, EN_LBD},
1799 {1600000, 4, 1, 20, 0x300, 0x1912, 0x82c9, EN_LBD},
1800 {1800000, 4, 3, 20, 0x300, 0x1912, 0x82c9, EN_LBD},
1801 #endif
1802 #ifdef CONFIG_BAND_SBAND
1803 {2300000, 1, 4, 20, 0x300, 0x2d2A, 0x82c7, EN_SBD},
1804 {2900000, 1, 7, 20, 0x280, 0x2deb, 0x8347, EN_SBD},
1805 #endif
1808 static const struct dib0090_pll dib0090_p1g_pll_table[] = {
1809 #ifdef CONFIG_BAND_CBAND
1810 {57000, 0, 11, 48, 6},
1811 {70000, 1, 11, 48, 6},
1812 {86000, 0, 10, 32, 4},
1813 {105000, 1, 10, 32, 4},
1814 {115000, 0, 9, 24, 6},
1815 {140000, 1, 9, 24, 6},
1816 {170000, 0, 8, 16, 4},
1817 #endif
1818 #ifdef CONFIG_BAND_VHF
1819 {200000, 1, 8, 16, 4},
1820 {230000, 0, 7, 12, 6},
1821 {280000, 1, 7, 12, 6},
1822 {340000, 0, 6, 8, 4},
1823 {380000, 1, 6, 8, 4},
1824 {455000, 0, 5, 6, 6},
1825 #endif
1826 #ifdef CONFIG_BAND_UHF
1827 {580000, 1, 5, 6, 6},
1828 {680000, 0, 4, 4, 4},
1829 {860000, 1, 4, 4, 4},
1830 #endif
1831 #ifdef CONFIG_BAND_LBAND
1832 {1800000, 1, 2, 2, 4},
1833 #endif
1834 #ifdef CONFIG_BAND_SBAND
1835 {2900000, 0, 1, 1, 6},
1836 #endif
1839 static const struct dib0090_tuning dib0090_p1g_tuning_table_fm_vhf_on_cband[] = {
1840 #ifdef CONFIG_BAND_CBAND
1841 {184000, 4, 3, 0x4187, 0x2c0, 0x2d22, 0x81cb, EN_CAB},
1842 {227000, 4, 3, 0x4187, 0x2c0, 0x2d22, 0x81cb, EN_CAB},
1843 {380000, 4, 3, 0x4187, 0x2c0, 0x2d22, 0x81cb, EN_CAB},
1844 #endif
1845 #ifdef CONFIG_BAND_UHF
1846 {520000, 2, 0, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},
1847 {550000, 2, 2, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},
1848 {650000, 2, 3, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},
1849 {750000, 2, 5, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},
1850 {850000, 2, 6, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},
1851 {900000, 2, 7, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},
1852 #endif
1853 #ifdef CONFIG_BAND_LBAND
1854 {1500000, 4, 0, 20, 0x300, 0x1912, 0x82c9, EN_LBD},
1855 {1600000, 4, 1, 20, 0x300, 0x1912, 0x82c9, EN_LBD},
1856 {1800000, 4, 3, 20, 0x300, 0x1912, 0x82c9, EN_LBD},
1857 #endif
1858 #ifdef CONFIG_BAND_SBAND
1859 {2300000, 1, 4, 20, 0x300, 0x2d2A, 0x82c7, EN_SBD},
1860 {2900000, 1, 7, 20, 0x280, 0x2deb, 0x8347, EN_SBD},
1861 #endif
1864 static const struct dib0090_tuning dib0090_tuning_table_cband_7090[] = {
1865 #ifdef CONFIG_BAND_CBAND
1866 {300000, 4, 3, 0x018F, 0x2c0, 0x2d22, 0xb9ce, EN_CAB},
1867 {380000, 4, 10, 0x018F, 0x2c0, 0x2d22, 0xb9ce, EN_CAB},
1868 {570000, 4, 10, 0x8190, 0x2c0, 0x2d22, 0xb9ce, EN_CAB},
1869 {858000, 4, 5, 0x8190, 0x2c0, 0x2d22, 0xb9ce, EN_CAB},
1870 #endif
1873 static int dib0090_captrim_search(struct dib0090_state *state, enum frontend_tune_state *tune_state)
1875 int ret = 0;
1876 u16 lo4 = 0xe900;
1878 s16 adc_target;
1879 u16 adc;
1880 s8 step_sign;
1881 u8 force_soft_search = 0;
1883 if (state->identity.version == SOC_8090_P1G_11R1 || state->identity.version == SOC_8090_P1G_21R1)
1884 force_soft_search = 1;
1886 if (*tune_state == CT_TUNER_START) {
1887 dprintk("Start Captrim search : %s", (force_soft_search == 1) ? "FORCE SOFT SEARCH" : "AUTO");
1888 dib0090_write_reg(state, 0x10, 0x2B1);
1889 dib0090_write_reg(state, 0x1e, 0x0032);
1891 if (!state->tuner_is_tuned) {
1892 /* prepare a complete captrim */
1893 if (!state->identity.p1g || force_soft_search)
1894 state->step = state->captrim = state->fcaptrim = 64;
1896 state->current_rf = state->rf_request;
1897 } else { /* we are already tuned to this frequency - the configuration is correct */
1898 if (!state->identity.p1g || force_soft_search) {
1899 /* do a minimal captrim even if the frequency has not changed */
1900 state->step = 4;
1901 state->captrim = state->fcaptrim = dib0090_read_reg(state, 0x18) & 0x7f;
1904 state->adc_diff = 3000;
1905 *tune_state = CT_TUNER_STEP_0;
1907 } else if (*tune_state == CT_TUNER_STEP_0) {
1908 if (state->identity.p1g && !force_soft_search) {
1909 u8 ratio = 31;
1911 dib0090_write_reg(state, 0x40, (3 << 7) | (ratio << 2) | (1 << 1) | 1);
1912 dib0090_read_reg(state, 0x40);
1913 ret = 50;
1914 } else {
1915 state->step /= 2;
1916 dib0090_write_reg(state, 0x18, lo4 | state->captrim);
1918 if (state->identity.in_soc)
1919 ret = 25;
1921 *tune_state = CT_TUNER_STEP_1;
1923 } else if (*tune_state == CT_TUNER_STEP_1) {
1924 if (state->identity.p1g && !force_soft_search) {
1925 dib0090_write_reg(state, 0x40, 0x18c | (0 << 1) | 0);
1926 dib0090_read_reg(state, 0x40);
1928 state->fcaptrim = dib0090_read_reg(state, 0x18) & 0x7F;
1929 dprintk("***Final Captrim= 0x%x", state->fcaptrim);
1930 *tune_state = CT_TUNER_STEP_3;
1932 } else {
1933 /* MERGE for all krosus before P1G */
1934 adc = dib0090_get_slow_adc_val(state);
1935 dprintk("CAPTRIM=%d; ADC = %d (ADC) & %dmV", (u32) state->captrim, (u32) adc, (u32) (adc) * (u32) 1800 / (u32) 1024);
1937 if (state->rest == 0 || state->identity.in_soc) { /* Just for 8090P SOCS where auto captrim HW bug : TO CHECK IN ACI for SOCS !!! if 400 for 8090p SOC => tune issue !!! */
1938 adc_target = 200;
1939 } else
1940 adc_target = 400;
1942 if (adc >= adc_target) {
1943 adc -= adc_target;
1944 step_sign = -1;
1945 } else {
1946 adc = adc_target - adc;
1947 step_sign = 1;
1950 if (adc < state->adc_diff) {
1951 dprintk("CAPTRIM=%d is closer to target (%d/%d)", (u32) state->captrim, (u32) adc, (u32) state->adc_diff);
1952 state->adc_diff = adc;
1953 state->fcaptrim = state->captrim;
1956 state->captrim += step_sign * state->step;
1957 if (state->step >= 1)
1958 *tune_state = CT_TUNER_STEP_0;
1959 else
1960 *tune_state = CT_TUNER_STEP_2;
1962 ret = 25;
1964 } else if (*tune_state == CT_TUNER_STEP_2) { /* this step is only used by krosus < P1G */
1965 /*write the final cptrim config */
1966 dib0090_write_reg(state, 0x18, lo4 | state->fcaptrim);
1968 *tune_state = CT_TUNER_STEP_3;
1970 } else if (*tune_state == CT_TUNER_STEP_3) {
1971 state->calibrate &= ~CAPTRIM_CAL;
1972 *tune_state = CT_TUNER_STEP_0;
1975 return ret;
1978 static int dib0090_get_temperature(struct dib0090_state *state, enum frontend_tune_state *tune_state)
1980 int ret = 15;
1981 s16 val;
1983 switch (*tune_state) {
1984 case CT_TUNER_START:
1985 state->wbdmux = dib0090_read_reg(state, 0x10);
1986 dib0090_write_reg(state, 0x10, (state->wbdmux & ~(0xff << 3)) | (0x8 << 3));
1988 state->bias = dib0090_read_reg(state, 0x13);
1989 dib0090_write_reg(state, 0x13, state->bias | (0x3 << 8));
1991 *tune_state = CT_TUNER_STEP_0;
1992 /* wait for the WBDMUX to switch and for the ADC to sample */
1993 break;
1995 case CT_TUNER_STEP_0:
1996 state->adc_diff = dib0090_get_slow_adc_val(state);
1997 dib0090_write_reg(state, 0x13, (state->bias & ~(0x3 << 8)) | (0x2 << 8));
1998 *tune_state = CT_TUNER_STEP_1;
1999 break;
2001 case CT_TUNER_STEP_1:
2002 val = dib0090_get_slow_adc_val(state);
2003 state->temperature = ((s16) ((val - state->adc_diff) * 180) >> 8) + 55;
2005 dprintk("temperature: %d C", state->temperature - 30);
2007 *tune_state = CT_TUNER_STEP_2;
2008 break;
2010 case CT_TUNER_STEP_2:
2011 dib0090_write_reg(state, 0x13, state->bias);
2012 dib0090_write_reg(state, 0x10, state->wbdmux); /* write back original WBDMUX */
2014 *tune_state = CT_TUNER_START;
2015 state->calibrate &= ~TEMP_CAL;
2016 if (state->config->analog_output == 0)
2017 dib0090_write_reg(state, 0x23, dib0090_read_reg(state, 0x23) | (1 << 14));
2019 break;
2021 default:
2022 ret = 0;
2023 break;
2025 return ret;
2028 #define WBD 0x781 /* 1 1 1 1 0000 0 0 1 */
2029 static int dib0090_tune(struct dvb_frontend *fe)
2031 struct dib0090_state *state = fe->tuner_priv;
2032 const struct dib0090_tuning *tune = state->current_tune_table_index;
2033 const struct dib0090_pll *pll = state->current_pll_table_index;
2034 enum frontend_tune_state *tune_state = &state->tune_state;
2036 u16 lo5, lo6, Den, tmp;
2037 u32 FBDiv, Rest, FREF, VCOF_kHz = 0;
2038 int ret = 10; /* 1ms is the default delay most of the time */
2039 u8 c, i;
2041 /************************* VCO ***************************/
2042 /* Default values for FG */
2043 /* from these are needed : */
2044 /* Cp,HFdiv,VCOband,SD,Num,Den,FB and REFDiv */
2046 /* in any case we first need to do a calibration if needed */
2047 if (*tune_state == CT_TUNER_START) {
2048 /* deactivate DataTX before some calibrations */
2049 if (state->calibrate & (DC_CAL | TEMP_CAL | WBD_CAL))
2050 dib0090_write_reg(state, 0x23, dib0090_read_reg(state, 0x23) & ~(1 << 14));
2051 else
2052 /* Activate DataTX in case a calibration has been done before */
2053 if (state->config->analog_output == 0)
2054 dib0090_write_reg(state, 0x23, dib0090_read_reg(state, 0x23) | (1 << 14));
2057 if (state->calibrate & DC_CAL)
2058 return dib0090_dc_offset_calibration(state, tune_state);
2059 else if (state->calibrate & WBD_CAL) {
2060 if (state->current_rf == 0)
2061 state->current_rf = state->fe->dtv_property_cache.frequency / 1000;
2062 return dib0090_wbd_calibration(state, tune_state);
2063 } else if (state->calibrate & TEMP_CAL)
2064 return dib0090_get_temperature(state, tune_state);
2065 else if (state->calibrate & CAPTRIM_CAL)
2066 return dib0090_captrim_search(state, tune_state);
2068 if (*tune_state == CT_TUNER_START) {
2069 /* if soc and AGC pwm control, disengage mux to be able to R/W access to 0x01 register to set the right filter (cutoff_freq_select) during the tune sequence, otherwise, SOC SERPAR error when accessing to 0x01 */
2070 if (state->config->use_pwm_agc && state->identity.in_soc) {
2071 tmp = dib0090_read_reg(state, 0x39);
2072 if ((tmp >> 10) & 0x1)
2073 dib0090_write_reg(state, 0x39, tmp & ~(1 << 10));
2076 state->current_band = (u8) BAND_OF_FREQUENCY(state->fe->dtv_property_cache.frequency / 1000);
2077 state->rf_request =
2078 state->fe->dtv_property_cache.frequency / 1000 + (state->current_band ==
2079 BAND_UHF ? state->config->freq_offset_khz_uhf : state->config->
2080 freq_offset_khz_vhf);
2082 /* in ISDB-T 1seg we shift tuning frequency */
2083 if ((state->fe->dtv_property_cache.delivery_system == SYS_ISDBT && state->fe->dtv_property_cache.isdbt_sb_mode == 1
2084 && state->fe->dtv_property_cache.isdbt_partial_reception == 0)) {
2085 const struct dib0090_low_if_offset_table *LUT_offset = state->config->low_if;
2086 u8 found_offset = 0;
2087 u32 margin_khz = 100;
2089 if (LUT_offset != NULL) {
2090 while (LUT_offset->RF_freq != 0xffff) {
2091 if (((state->rf_request > (LUT_offset->RF_freq - margin_khz))
2092 && (state->rf_request < (LUT_offset->RF_freq + margin_khz)))
2093 && LUT_offset->std == state->fe->dtv_property_cache.delivery_system) {
2094 state->rf_request += LUT_offset->offset_khz;
2095 found_offset = 1;
2096 break;
2098 LUT_offset++;
2102 if (found_offset == 0)
2103 state->rf_request += 400;
2105 if (state->current_rf != state->rf_request || (state->current_standard != state->fe->dtv_property_cache.delivery_system)) {
2106 state->tuner_is_tuned = 0;
2107 state->current_rf = 0;
2108 state->current_standard = 0;
2110 tune = dib0090_tuning_table;
2111 if (state->identity.p1g)
2112 tune = dib0090_p1g_tuning_table;
2114 tmp = (state->identity.version >> 5) & 0x7;
2116 if (state->identity.in_soc) {
2117 if (state->config->force_cband_input) { /* Use the CBAND input for all band */
2118 if (state->current_band & BAND_CBAND || state->current_band & BAND_FM || state->current_band & BAND_VHF
2119 || state->current_band & BAND_UHF) {
2120 state->current_band = BAND_CBAND;
2121 tune = dib0090_tuning_table_cband_7090;
2123 } else { /* Use the CBAND input for all band under UHF */
2124 if (state->current_band & BAND_CBAND || state->current_band & BAND_FM || state->current_band & BAND_VHF) {
2125 state->current_band = BAND_CBAND;
2126 tune = dib0090_tuning_table_cband_7090;
2129 } else
2130 if (tmp == 0x4 || tmp == 0x7) {
2131 /* CBAND tuner version for VHF */
2132 if (state->current_band == BAND_FM || state->current_band == BAND_CBAND || state->current_band == BAND_VHF) {
2133 state->current_band = BAND_CBAND; /* Force CBAND */
2135 tune = dib0090_tuning_table_fm_vhf_on_cband;
2136 if (state->identity.p1g)
2137 tune = dib0090_p1g_tuning_table_fm_vhf_on_cband;
2141 pll = dib0090_pll_table;
2142 if (state->identity.p1g)
2143 pll = dib0090_p1g_pll_table;
2145 /* Look for the interval */
2146 while (state->rf_request > tune->max_freq)
2147 tune++;
2148 while (state->rf_request > pll->max_freq)
2149 pll++;
2151 state->current_tune_table_index = tune;
2152 state->current_pll_table_index = pll;
2154 dib0090_write_reg(state, 0x0b, 0xb800 | (tune->switch_trim));
2156 VCOF_kHz = (pll->hfdiv * state->rf_request) * 2;
2158 FREF = state->config->io.clock_khz;
2159 if (state->config->fref_clock_ratio != 0)
2160 FREF /= state->config->fref_clock_ratio;
2162 FBDiv = (VCOF_kHz / pll->topresc / FREF);
2163 Rest = (VCOF_kHz / pll->topresc) - FBDiv * FREF;
2165 if (Rest < LPF)
2166 Rest = 0;
2167 else if (Rest < 2 * LPF)
2168 Rest = 2 * LPF;
2169 else if (Rest > (FREF - LPF)) {
2170 Rest = 0;
2171 FBDiv += 1;
2172 } else if (Rest > (FREF - 2 * LPF))
2173 Rest = FREF - 2 * LPF;
2174 Rest = (Rest * 6528) / (FREF / 10);
2175 state->rest = Rest;
2177 /* external loop filter, otherwise:
2178 * lo5 = (0 << 15) | (0 << 12) | (0 << 11) | (3 << 9) | (4 << 6) | (3 << 4) | 4;
2179 * lo6 = 0x0e34 */
2181 if (Rest == 0) {
2182 if (pll->vco_band)
2183 lo5 = 0x049f;
2184 else
2185 lo5 = 0x041f;
2186 } else {
2187 if (pll->vco_band)
2188 lo5 = 0x049e;
2189 else if (state->config->analog_output)
2190 lo5 = 0x041d;
2191 else
2192 lo5 = 0x041c;
2195 if (state->identity.p1g) { /* Bias is done automatically in P1G */
2196 if (state->identity.in_soc) {
2197 if (state->identity.version == SOC_8090_P1G_11R1)
2198 lo5 = 0x46f;
2199 else
2200 lo5 = 0x42f;
2201 } else
2202 lo5 = 0x42c;
2205 lo5 |= (pll->hfdiv_code << 11) | (pll->vco_band << 7); /* bit 15 is the split to the slave, we do not do it here */
2207 if (!state->config->io.pll_int_loop_filt) {
2208 if (state->identity.in_soc)
2209 lo6 = 0xff98;
2210 else if (state->identity.p1g || (Rest == 0))
2211 lo6 = 0xfff8;
2212 else
2213 lo6 = 0xff28;
2214 } else
2215 lo6 = (state->config->io.pll_int_loop_filt << 3);
2217 Den = 1;
2219 if (Rest > 0) {
2220 if (state->config->analog_output)
2221 lo6 |= (1 << 2) | 2;
2222 else {
2223 if (state->identity.in_soc)
2224 lo6 |= (1 << 2) | 2;
2225 else
2226 lo6 |= (1 << 2) | 2;
2228 Den = 255;
2230 dib0090_write_reg(state, 0x15, (u16) FBDiv);
2231 if (state->config->fref_clock_ratio != 0)
2232 dib0090_write_reg(state, 0x16, (Den << 8) | state->config->fref_clock_ratio);
2233 else
2234 dib0090_write_reg(state, 0x16, (Den << 8) | 1);
2235 dib0090_write_reg(state, 0x17, (u16) Rest);
2236 dib0090_write_reg(state, 0x19, lo5);
2237 dib0090_write_reg(state, 0x1c, lo6);
2239 lo6 = tune->tuner_enable;
2240 if (state->config->analog_output)
2241 lo6 = (lo6 & 0xff9f) | 0x2;
2243 dib0090_write_reg(state, 0x24, lo6 | EN_LO | state->config->use_pwm_agc * EN_CRYSTAL);
2247 state->current_rf = state->rf_request;
2248 state->current_standard = state->fe->dtv_property_cache.delivery_system;
2250 ret = 20;
2251 state->calibrate = CAPTRIM_CAL; /* captrim serach now */
2254 else if (*tune_state == CT_TUNER_STEP_0) { /* Warning : because of captrim cal, if you change this step, change it also in _cal.c file because it is the step following captrim cal state machine */
2255 const struct dib0090_wbd_slope *wbd = state->current_wbd_table;
2257 while (state->current_rf / 1000 > wbd->max_freq)
2258 wbd++;
2260 dib0090_write_reg(state, 0x1e, 0x07ff);
2261 dprintk("Final Captrim: %d", (u32) state->fcaptrim);
2262 dprintk("HFDIV code: %d", (u32) pll->hfdiv_code);
2263 dprintk("VCO = %d", (u32) pll->vco_band);
2264 dprintk("VCOF in kHz: %d ((%d*%d) << 1))", (u32) ((pll->hfdiv * state->rf_request) * 2), (u32) pll->hfdiv, (u32) state->rf_request);
2265 dprintk("REFDIV: %d, FREF: %d", (u32) 1, (u32) state->config->io.clock_khz);
2266 dprintk("FBDIV: %d, Rest: %d", (u32) dib0090_read_reg(state, 0x15), (u32) dib0090_read_reg(state, 0x17));
2267 dprintk("Num: %d, Den: %d, SD: %d", (u32) dib0090_read_reg(state, 0x17), (u32) (dib0090_read_reg(state, 0x16) >> 8),
2268 (u32) dib0090_read_reg(state, 0x1c) & 0x3);
2270 #define WBD 0x781 /* 1 1 1 1 0000 0 0 1 */
2271 c = 4;
2272 i = 3;
2274 if (wbd->wbd_gain != 0)
2275 c = wbd->wbd_gain;
2277 state->wbdmux = (c << 13) | (i << 11) | (WBD | (state->config->use_pwm_agc << 1));
2278 dib0090_write_reg(state, 0x10, state->wbdmux);
2280 if ((tune->tuner_enable == EN_CAB) && state->identity.p1g) {
2281 dprintk("P1G : The cable band is selected and lna_tune = %d", tune->lna_tune);
2282 dib0090_write_reg(state, 0x09, tune->lna_bias);
2283 dib0090_write_reg(state, 0x0b, 0xb800 | (tune->lna_tune << 6) | (tune->switch_trim));
2284 } else
2285 dib0090_write_reg(state, 0x09, (tune->lna_tune << 5) | tune->lna_bias);
2287 dib0090_write_reg(state, 0x0c, tune->v2i);
2288 dib0090_write_reg(state, 0x0d, tune->mix);
2289 dib0090_write_reg(state, 0x0e, tune->load);
2290 *tune_state = CT_TUNER_STEP_1;
2292 } else if (*tune_state == CT_TUNER_STEP_1) {
2293 /* initialize the lt gain register */
2294 state->rf_lt_def = 0x7c00;
2296 dib0090_set_bandwidth(state);
2297 state->tuner_is_tuned = 1;
2299 state->calibrate |= WBD_CAL;
2300 state->calibrate |= TEMP_CAL;
2301 *tune_state = CT_TUNER_STOP;
2302 } else
2303 ret = FE_CALLBACK_TIME_NEVER;
2304 return ret;
2307 static int dib0090_release(struct dvb_frontend *fe)
2309 kfree(fe->tuner_priv);
2310 fe->tuner_priv = NULL;
2311 return 0;
2314 enum frontend_tune_state dib0090_get_tune_state(struct dvb_frontend *fe)
2316 struct dib0090_state *state = fe->tuner_priv;
2318 return state->tune_state;
2321 EXPORT_SYMBOL(dib0090_get_tune_state);
2323 int dib0090_set_tune_state(struct dvb_frontend *fe, enum frontend_tune_state tune_state)
2325 struct dib0090_state *state = fe->tuner_priv;
2327 state->tune_state = tune_state;
2328 return 0;
2331 EXPORT_SYMBOL(dib0090_set_tune_state);
2333 static int dib0090_get_frequency(struct dvb_frontend *fe, u32 * frequency)
2335 struct dib0090_state *state = fe->tuner_priv;
2337 *frequency = 1000 * state->current_rf;
2338 return 0;
2341 static int dib0090_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *p)
2343 struct dib0090_state *state = fe->tuner_priv;
2344 u32 ret;
2346 state->tune_state = CT_TUNER_START;
2348 do {
2349 ret = dib0090_tune(fe);
2350 if (ret != FE_CALLBACK_TIME_NEVER)
2351 msleep(ret / 10);
2352 else
2353 break;
2354 } while (state->tune_state != CT_TUNER_STOP);
2356 return 0;
2359 static const struct dvb_tuner_ops dib0090_ops = {
2360 .info = {
2361 .name = "DiBcom DiB0090",
2362 .frequency_min = 45000000,
2363 .frequency_max = 860000000,
2364 .frequency_step = 1000,
2366 .release = dib0090_release,
2368 .init = dib0090_wakeup,
2369 .sleep = dib0090_sleep,
2370 .set_params = dib0090_set_params,
2371 .get_frequency = dib0090_get_frequency,
2374 static const struct dvb_tuner_ops dib0090_fw_ops = {
2375 .info = {
2376 .name = "DiBcom DiB0090",
2377 .frequency_min = 45000000,
2378 .frequency_max = 860000000,
2379 .frequency_step = 1000,
2381 .release = dib0090_release,
2383 .init = NULL,
2384 .sleep = NULL,
2385 .set_params = NULL,
2386 .get_frequency = NULL,
2389 static const struct dib0090_wbd_slope dib0090_wbd_table_default[] = {
2390 {470, 0, 250, 0, 100, 4},
2391 {860, 51, 866, 21, 375, 4},
2392 {1700, 0, 800, 0, 850, 4},
2393 {2900, 0, 250, 0, 100, 6},
2394 {0xFFFF, 0, 0, 0, 0, 0},
2397 struct dvb_frontend *dib0090_register(struct dvb_frontend *fe, struct i2c_adapter *i2c, const struct dib0090_config *config)
2399 struct dib0090_state *st = kzalloc(sizeof(struct dib0090_state), GFP_KERNEL);
2400 if (st == NULL)
2401 return NULL;
2403 st->config = config;
2404 st->i2c = i2c;
2405 st->fe = fe;
2406 fe->tuner_priv = st;
2408 if (config->wbd == NULL)
2409 st->current_wbd_table = dib0090_wbd_table_default;
2410 else
2411 st->current_wbd_table = config->wbd;
2413 if (dib0090_reset(fe) != 0)
2414 goto free_mem;
2416 printk(KERN_INFO "DiB0090: successfully identified\n");
2417 memcpy(&fe->ops.tuner_ops, &dib0090_ops, sizeof(struct dvb_tuner_ops));
2419 return fe;
2420 free_mem:
2421 kfree(st);
2422 fe->tuner_priv = NULL;
2423 return NULL;
2426 EXPORT_SYMBOL(dib0090_register);
2428 struct dvb_frontend *dib0090_fw_register(struct dvb_frontend *fe, struct i2c_adapter *i2c, const struct dib0090_config *config)
2430 struct dib0090_fw_state *st = kzalloc(sizeof(struct dib0090_fw_state), GFP_KERNEL);
2431 if (st == NULL)
2432 return NULL;
2434 st->config = config;
2435 st->i2c = i2c;
2436 st->fe = fe;
2437 fe->tuner_priv = st;
2439 if (dib0090_fw_reset_digital(fe, st->config) != 0)
2440 goto free_mem;
2442 dprintk("DiB0090 FW: successfully identified");
2443 memcpy(&fe->ops.tuner_ops, &dib0090_fw_ops, sizeof(struct dvb_tuner_ops));
2445 return fe;
2446 free_mem:
2447 kfree(st);
2448 fe->tuner_priv = NULL;
2449 return NULL;
2451 EXPORT_SYMBOL(dib0090_fw_register);
2453 MODULE_AUTHOR("Patrick Boettcher <pboettcher@dibcom.fr>");
2454 MODULE_AUTHOR("Olivier Grenie <olivier.grenie@dibcom.fr>");
2455 MODULE_DESCRIPTION("Driver for the DiBcom 0090 base-band RF Tuner");
2456 MODULE_LICENSE("GPL");