[media] DiB0090: misc improvements
[linux-2.6/linux-acpi-2.6/ibm-acpi-2.6.git] / drivers / media / dvb / frontends / dib0090.c
blob0e87a0bdf7ab8951718a6dcc0ffa75529c93941f
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 //From the SOC the version definition has changed
376 if ((identity->version & 0x3) == SOC) {
377 identity->in_soc = 1;
378 switch (identity->version) {
379 case SOC_8090_P1G_11R1:
380 dprintk("SOC 8090 P1-G11R1 Has been detected");
381 identity->p1g = 1;
382 break;
383 case SOC_8090_P1G_21R1:
384 dprintk("SOC 8090 P1-G21R1 Has been detected");
385 identity->p1g = 1;
386 break;
387 case SOC_7090_P1G_11R1:
388 dprintk("SOC 7090 P1-G11R1 Has been detected");
389 identity->p1g = 1;
390 break;
391 case SOC_7090_P1G_21R1:
392 dprintk("SOC 7090 P1-G21R1 Has been detected");
393 identity->p1g = 1;
394 break;
395 default:
396 goto identification_error;
398 } else {
399 switch ((identity->version >> 5) & 0x7) {
400 case MP001:
401 dprintk("MP001 : 9090/8096");
402 break;
403 case MP005:
404 dprintk("MP005 : Single Sband");
405 break;
406 case MP008:
407 dprintk("MP008 : diversity VHF-UHF-LBAND");
408 break;
409 case MP009:
410 dprintk("MP009 : diversity 29098 CBAND-UHF-LBAND-SBAND");
411 break;
412 default:
413 goto identification_error;
416 switch (identity->version & 0x1f) {
417 case P1G_21R2:
418 dprintk("P1G_21R2 detected");
419 identity->p1g = 1;
420 break;
421 case P1G:
422 dprintk("P1G detected");
423 identity->p1g = 1;
424 break;
425 case P1D_E_F:
426 dprintk("P1D/E/F detected");
427 break;
428 case P1C:
429 dprintk("P1C detected");
430 break;
431 case P1A_B:
432 dprintk("P1-A/B detected: driver is deactivated - not available");
433 goto identification_error;
434 break;
435 default:
436 goto identification_error;
440 return 0;
442 identification_error:
443 return -EIO;;
446 static void dib0090_reset_digital(struct dvb_frontend *fe, const struct dib0090_config *cfg)
448 struct dib0090_state *state = fe->tuner_priv;
449 u16 PllCfg, i, v;
451 HARD_RESET(state);
453 dib0090_write_reg(state, 0x24, EN_PLL | EN_CRYSTAL);
454 dib0090_write_reg(state, 0x1b, EN_DIGCLK | EN_PLL | EN_CRYSTAL); /* PLL, DIG_CLK and CRYSTAL remain */
456 if (!cfg->in_soc) {
457 /* adcClkOutRatio=8->7, release reset */
458 dib0090_write_reg(state, 0x20, ((cfg->io.adc_clock_ratio - 1) << 11) | (0 << 10) | (1 << 9) | (1 << 8) | (0 << 4) | 0);
459 if (cfg->clkoutdrive != 0)
460 dib0090_write_reg(state, 0x23, (0 << 15) | ((!cfg->analog_output) << 14) | (2 << 10) | (1 << 9) | (0 << 8)
461 | (cfg->clkoutdrive << 5) | (cfg->clkouttobamse << 4) | (0 << 2) | (0));
462 else
463 dib0090_write_reg(state, 0x23, (0 << 15) | ((!cfg->analog_output) << 14) | (2 << 10) | (1 << 9) | (0 << 8)
464 | (7 << 5) | (cfg->clkouttobamse << 4) | (0 << 2) | (0));
467 /* Read Pll current config * */
468 PllCfg = dib0090_read_reg(state, 0x21);
470 /** Reconfigure PLL if current setting is different from default setting **/
471 if ((PllCfg & 0x1FFF) != ((cfg->io.pll_range << 12) | (cfg->io.pll_loopdiv << 6) | (cfg->io.pll_prediv)) && (!cfg->in_soc)
472 && !cfg->io.pll_bypass) {
474 /* Set Bypass mode */
475 PllCfg |= (1 << 15);
476 dib0090_write_reg(state, 0x21, PllCfg);
478 /* Set Reset Pll */
479 PllCfg &= ~(1 << 13);
480 dib0090_write_reg(state, 0x21, PllCfg);
482 /*** Set new Pll configuration in bypass and reset state ***/
483 PllCfg = (1 << 15) | (0 << 13) | (cfg->io.pll_range << 12) | (cfg->io.pll_loopdiv << 6) | (cfg->io.pll_prediv);
484 dib0090_write_reg(state, 0x21, PllCfg);
486 /* Remove Reset Pll */
487 PllCfg |= (1 << 13);
488 dib0090_write_reg(state, 0x21, PllCfg);
490 /*** Wait for PLL lock ***/
491 i = 100;
492 do {
493 v = !!(dib0090_read_reg(state, 0x1a) & 0x800);
494 if (v)
495 break;
496 } while (--i);
498 if (i == 0) {
499 dprintk("Pll: Unable to lock Pll");
500 return;
503 /* Finally Remove Bypass mode */
504 PllCfg &= ~(1 << 15);
505 dib0090_write_reg(state, 0x21, PllCfg);
508 if (cfg->io.pll_bypass) {
509 PllCfg |= (cfg->io.pll_bypass << 15);
510 dib0090_write_reg(state, 0x21, PllCfg);
514 static int dib0090_fw_reset_digital(struct dvb_frontend *fe, const struct dib0090_config *cfg)
516 struct dib0090_fw_state *state = fe->tuner_priv;
517 u16 PllCfg;
518 u16 v;
519 int i;
521 dprintk("fw reset digital");
522 HARD_RESET(state);
524 dib0090_fw_write_reg(state, 0x24, EN_PLL | EN_CRYSTAL);
525 dib0090_fw_write_reg(state, 0x1b, EN_DIGCLK | EN_PLL | EN_CRYSTAL); /* PLL, DIG_CLK and CRYSTAL remain */
527 dib0090_fw_write_reg(state, 0x20,
528 ((cfg->io.adc_clock_ratio - 1) << 11) | (0 << 10) | (1 << 9) | (1 << 8) | (cfg->data_tx_drv << 4) | cfg->ls_cfg_pad_drv);
530 v = (0 << 15) | ((!cfg->analog_output) << 14) | (1 << 9) | (0 << 8) | (cfg->clkouttobamse << 4) | (0 << 2) | (0);
531 if (cfg->clkoutdrive != 0)
532 v |= cfg->clkoutdrive << 5;
533 else
534 v |= 7 << 5;
536 v |= 2 << 10;
537 dib0090_fw_write_reg(state, 0x23, v);
539 /* Read Pll current config * */
540 PllCfg = dib0090_fw_read_reg(state, 0x21);
542 /** Reconfigure PLL if current setting is different from default setting **/
543 if ((PllCfg & 0x1FFF) != ((cfg->io.pll_range << 12) | (cfg->io.pll_loopdiv << 6) | (cfg->io.pll_prediv)) && !cfg->io.pll_bypass) {
545 /* Set Bypass mode */
546 PllCfg |= (1 << 15);
547 dib0090_fw_write_reg(state, 0x21, PllCfg);
549 /* Set Reset Pll */
550 PllCfg &= ~(1 << 13);
551 dib0090_fw_write_reg(state, 0x21, PllCfg);
553 /*** Set new Pll configuration in bypass and reset state ***/
554 PllCfg = (1 << 15) | (0 << 13) | (cfg->io.pll_range << 12) | (cfg->io.pll_loopdiv << 6) | (cfg->io.pll_prediv);
555 dib0090_fw_write_reg(state, 0x21, PllCfg);
557 /* Remove Reset Pll */
558 PllCfg |= (1 << 13);
559 dib0090_fw_write_reg(state, 0x21, PllCfg);
561 /*** Wait for PLL lock ***/
562 i = 100;
563 do {
564 v = !!(dib0090_fw_read_reg(state, 0x1a) & 0x800);
565 if (v)
566 break;
567 } while (--i);
569 if (i == 0) {
570 dprintk("Pll: Unable to lock Pll");
571 return -EIO;
574 /* Finally Remove Bypass mode */
575 PllCfg &= ~(1 << 15);
576 dib0090_fw_write_reg(state, 0x21, PllCfg);
579 if (cfg->io.pll_bypass) {
580 PllCfg |= (cfg->io.pll_bypass << 15);
581 dib0090_fw_write_reg(state, 0x21, PllCfg);
584 return dib0090_fw_identify(fe);
587 static int dib0090_wakeup(struct dvb_frontend *fe)
589 struct dib0090_state *state = fe->tuner_priv;
590 if (state->config->sleep)
591 state->config->sleep(fe, 0);
593 /* enable dataTX in case we have been restarted in the wrong moment */
594 dib0090_write_reg(state, 0x23, dib0090_read_reg(state, 0x23) | (1 << 14));
595 return 0;
598 static int dib0090_sleep(struct dvb_frontend *fe)
600 struct dib0090_state *state = fe->tuner_priv;
601 if (state->config->sleep)
602 state->config->sleep(fe, 1);
603 return 0;
606 void dib0090_dcc_freq(struct dvb_frontend *fe, u8 fast)
608 struct dib0090_state *state = fe->tuner_priv;
609 if (fast)
610 dib0090_write_reg(state, 0x04, 0);
611 else
612 dib0090_write_reg(state, 0x04, 1);
615 EXPORT_SYMBOL(dib0090_dcc_freq);
617 static const u16 bb_ramp_pwm_normal_socs[] = {
618 550, /* max BB gain in 10th of dB */
619 (1 << 9) | 8, /* ramp_slope = 1dB of gain -> clock_ticks_per_db = clk_khz / ramp_slope -> BB_RAMP2 */
620 440,
621 (4 << 9) | 0, /* BB_RAMP3 = 26dB */
622 (0 << 9) | 208, /* BB_RAMP4 */
623 (4 << 9) | 208, /* BB_RAMP5 = 29dB */
624 (0 << 9) | 440, /* BB_RAMP6 */
627 static const u16 rf_ramp_pwm_cband_7090[] = {
628 280, /* max RF gain in 10th of dB */
629 18, /* ramp_slope = 1dB of gain -> clock_ticks_per_db = clk_khz / ramp_slope -> RF_RAMP2 */
630 504, /* ramp_max = maximum X used on the ramp */
631 (29 << 10) | 364, /* RF_RAMP5, LNA 1 = 8dB */
632 (0 << 10) | 504, /* RF_RAMP6, LNA 1 */
633 (60 << 10) | 228, /* RF_RAMP7, LNA 2 = 7.7dB */
634 (0 << 10) | 364, /* RF_RAMP8, LNA 2 */
635 (34 << 10) | 109, /* GAIN_4_1, LNA 3 = 6.8dB */
636 (0 << 10) | 228, /* GAIN_4_2, LNA 3 */
637 (37 << 10) | 0, /* RF_RAMP3, LNA 4 = 6.2dB */
638 (0 << 10) | 109, /* RF_RAMP4, LNA 4 */
641 static const u16 rf_ramp_pwm_cband_8090[] = {
642 345, /* max RF gain in 10th of dB */
643 29, /* ramp_slope = 1dB of gain -> clock_ticks_per_db = clk_khz / ramp_slope -> RF_RAMP2 */
644 1000, /* ramp_max = maximum X used on the ramp */
645 (35 << 10) | 772, /* RF_RAMP3, LNA 1 = 8dB */
646 (0 << 10) | 1000, /* RF_RAMP4, LNA 1 */
647 (58 << 10) | 496, /* RF_RAMP5, LNA 2 = 9.5dB */
648 (0 << 10) | 772, /* RF_RAMP6, LNA 2 */
649 (27 << 10) | 200, /* RF_RAMP7, LNA 3 = 10.5dB */
650 (0 << 10) | 496, /* RF_RAMP8, LNA 3 */
651 (40 << 10) | 0, /* GAIN_4_1, LNA 4 = 7dB */
652 (0 << 10) | 200, /* GAIN_4_2, LNA 4 */
655 static const u16 rf_ramp_pwm_uhf_7090[] = {
656 407, /* max RF gain in 10th of dB */
657 13, /* ramp_slope = 1dB of gain -> clock_ticks_per_db = clk_khz / ramp_slope -> RF_RAMP2 */
658 529, /* ramp_max = maximum X used on the ramp */
659 (23 << 10) | 0, /* RF_RAMP3, LNA 1 = 14.7dB */
660 (0 << 10) | 176, /* RF_RAMP4, LNA 1 */
661 (63 << 10) | 400, /* RF_RAMP5, LNA 2 = 8dB */
662 (0 << 10) | 529, /* RF_RAMP6, LNA 2 */
663 (48 << 10) | 316, /* RF_RAMP7, LNA 3 = 6.8dB */
664 (0 << 10) | 400, /* RF_RAMP8, LNA 3 */
665 (29 << 10) | 176, /* GAIN_4_1, LNA 4 = 11.5dB */
666 (0 << 10) | 316, /* GAIN_4_2, LNA 4 */
669 static const u16 rf_ramp_pwm_uhf_8090[] = {
670 388, /* max RF gain in 10th of dB */
671 26, /* ramp_slope = 1dB of gain -> clock_ticks_per_db = clk_khz / ramp_slope -> RF_RAMP2 */
672 1008, /* ramp_max = maximum X used on the ramp */
673 (11 << 10) | 0, /* RF_RAMP3, LNA 1 = 14.7dB */
674 (0 << 10) | 369, /* RF_RAMP4, LNA 1 */
675 (41 << 10) | 809, /* RF_RAMP5, LNA 2 = 8dB */
676 (0 << 10) | 1008, /* RF_RAMP6, LNA 2 */
677 (27 << 10) | 659, /* RF_RAMP7, LNA 3 = 6dB */
678 (0 << 10) | 809, /* RF_RAMP8, LNA 3 */
679 (14 << 10) | 369, /* GAIN_4_1, LNA 4 = 11.5dB */
680 (0 << 10) | 659, /* GAIN_4_2, LNA 4 */
683 static const u16 rf_ramp_pwm_cband[] = {
684 0, /* max RF gain in 10th of dB */
685 0, /* ramp_slope = 1dB of gain -> clock_ticks_per_db = clk_khz / ramp_slope -> 0x2b */
686 0, /* ramp_max = maximum X used on the ramp */
687 (0 << 10) | 0, /* 0x2c, LNA 1 = 0dB */
688 (0 << 10) | 0, /* 0x2d, LNA 1 */
689 (0 << 10) | 0, /* 0x2e, LNA 2 = 0dB */
690 (0 << 10) | 0, /* 0x2f, LNA 2 */
691 (0 << 10) | 0, /* 0x30, LNA 3 = 0dB */
692 (0 << 10) | 0, /* 0x31, LNA 3 */
693 (0 << 10) | 0, /* GAIN_4_1, LNA 4 = 0dB */
694 (0 << 10) | 0, /* GAIN_4_2, LNA 4 */
697 static const u16 rf_ramp_vhf[] = {
698 412, /* max RF gain in 10th of dB */
699 132, 307, 127, /* LNA1, 13.2dB */
700 105, 412, 255, /* LNA2, 10.5dB */
701 50, 50, 127, /* LNA3, 5dB */
702 125, 175, 127, /* LNA4, 12.5dB */
703 0, 0, 127, /* CBAND, 0dB */
706 static const u16 rf_ramp_uhf[] = {
707 412, /* max RF gain in 10th of dB */
708 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 */
709 105, 412, 255, /* LNA2 : 10.5 dB */
710 50, 50, 127, /* LNA3 : 5.0 dB */
711 125, 175, 127, /* LNA4 : 12.5 dB */
712 0, 0, 127, /* CBAND : 0.0 dB */
715 static const u16 rf_ramp_cband_broadmatching[] = /* for p1G only */
717 314, /* Calibrated at 200MHz order has been changed g4-g3-g2-g1 */
718 84, 314, 127, /* LNA1 */
719 80, 230, 255, /* LNA2 */
720 80, 150, 127, /* LNA3 It was measured 12dB, do not lock if 120 */
721 70, 70, 127, /* LNA4 */
722 0, 0, 127, /* CBAND */
725 static const u16 rf_ramp_cband[] = {
726 332, /* max RF gain in 10th of dB */
727 132, 252, 127, /* LNA1, dB */
728 80, 332, 255, /* LNA2, dB */
729 0, 0, 127, /* LNA3, dB */
730 0, 0, 127, /* LNA4, dB */
731 120, 120, 127, /* LT1 CBAND */
734 static const u16 rf_ramp_pwm_vhf[] = {
735 404, /* max RF gain in 10th of dB */
736 25, /* ramp_slope = 1dB of gain -> clock_ticks_per_db = clk_khz / ramp_slope -> 0x2b */
737 1011, /* ramp_max = maximum X used on the ramp */
738 (6 << 10) | 417, /* 0x2c, LNA 1 = 13.2dB */
739 (0 << 10) | 756, /* 0x2d, LNA 1 */
740 (16 << 10) | 756, /* 0x2e, LNA 2 = 10.5dB */
741 (0 << 10) | 1011, /* 0x2f, LNA 2 */
742 (16 << 10) | 290, /* 0x30, LNA 3 = 5dB */
743 (0 << 10) | 417, /* 0x31, LNA 3 */
744 (7 << 10) | 0, /* GAIN_4_1, LNA 4 = 12.5dB */
745 (0 << 10) | 290, /* GAIN_4_2, LNA 4 */
748 static const u16 rf_ramp_pwm_uhf[] = {
749 404, /* max RF gain in 10th of dB */
750 25, /* ramp_slope = 1dB of gain -> clock_ticks_per_db = clk_khz / ramp_slope -> 0x2b */
751 1011, /* ramp_max = maximum X used on the ramp */
752 (6 << 10) | 417, /* 0x2c, LNA 1 = 13.2dB */
753 (0 << 10) | 756, /* 0x2d, LNA 1 */
754 (16 << 10) | 756, /* 0x2e, LNA 2 = 10.5dB */
755 (0 << 10) | 1011, /* 0x2f, LNA 2 */
756 (16 << 10) | 0, /* 0x30, LNA 3 = 5dB */
757 (0 << 10) | 127, /* 0x31, LNA 3 */
758 (7 << 10) | 127, /* GAIN_4_1, LNA 4 = 12.5dB */
759 (0 << 10) | 417, /* GAIN_4_2, LNA 4 */
762 static const u16 bb_ramp_boost[] = {
763 550, /* max BB gain in 10th of dB */
764 260, 260, 26, /* BB1, 26dB */
765 290, 550, 29, /* BB2, 29dB */
768 static const u16 bb_ramp_pwm_normal[] = {
769 500, /* max RF gain in 10th of dB */
770 8, /* ramp_slope = 1dB of gain -> clock_ticks_per_db = clk_khz / ramp_slope -> 0x34 */
771 400,
772 (2 << 9) | 0, /* 0x35 = 21dB */
773 (0 << 9) | 168, /* 0x36 */
774 (2 << 9) | 168, /* 0x37 = 29dB */
775 (0 << 9) | 400, /* 0x38 */
778 struct slope {
779 s16 range;
780 s16 slope;
782 static u16 slopes_to_scale(const struct slope *slopes, u8 num, s16 val)
784 u8 i;
785 u16 rest;
786 u16 ret = 0;
787 for (i = 0; i < num; i++) {
788 if (val > slopes[i].range)
789 rest = slopes[i].range;
790 else
791 rest = val;
792 ret += (rest * slopes[i].slope) / slopes[i].range;
793 val -= rest;
795 return ret;
798 static const struct slope dib0090_wbd_slopes[3] = {
799 {66, 120}, /* -64,-52: offset - 65 */
800 {600, 170}, /* -52,-35: 65 - 665 */
801 {170, 250}, /* -45,-10: 665 - 835 */
804 static s16 dib0090_wbd_to_db(struct dib0090_state *state, u16 wbd)
806 wbd &= 0x3ff;
807 if (wbd < state->wbd_offset)
808 wbd = 0;
809 else
810 wbd -= state->wbd_offset;
811 /* -64dB is the floor */
812 return -640 + (s16) slopes_to_scale(dib0090_wbd_slopes, ARRAY_SIZE(dib0090_wbd_slopes), wbd);
815 static void dib0090_wbd_target(struct dib0090_state *state, u32 rf)
817 u16 offset = 250;
819 /* TODO : DAB digital N+/-1 interferer perfs : offset = 10 */
821 if (state->current_band == BAND_VHF)
822 offset = 650;
823 #ifndef FIRMWARE_FIREFLY
824 if (state->current_band == BAND_VHF)
825 offset = state->config->wbd_vhf_offset;
826 if (state->current_band == BAND_CBAND)
827 offset = state->config->wbd_cband_offset;
828 #endif
830 state->wbd_target = dib0090_wbd_to_db(state, state->wbd_offset + offset);
831 dprintk("wbd-target: %d dB", (u32) state->wbd_target);
834 static const int gain_reg_addr[4] = {
835 0x08, 0x0a, 0x0f, 0x01
838 static void dib0090_gain_apply(struct dib0090_state *state, s16 gain_delta, s16 top_delta, u8 force)
840 u16 rf, bb, ref;
841 u16 i, v, gain_reg[4] = { 0 }, gain;
842 const u16 *g;
844 if (top_delta < -511)
845 top_delta = -511;
846 if (top_delta > 511)
847 top_delta = 511;
849 if (force) {
850 top_delta *= (1 << WBD_ALPHA);
851 gain_delta *= (1 << GAIN_ALPHA);
854 if (top_delta >= ((s16) (state->rf_ramp[0] << WBD_ALPHA) - state->rf_gain_limit)) /* overflow */
855 state->rf_gain_limit = state->rf_ramp[0] << WBD_ALPHA;
856 else
857 state->rf_gain_limit += top_delta;
859 if (state->rf_gain_limit < 0) /*underflow */
860 state->rf_gain_limit = 0;
862 /* use gain as a temporary variable and correct current_gain */
863 gain = ((state->rf_gain_limit >> WBD_ALPHA) + state->bb_ramp[0]) << GAIN_ALPHA;
864 if (gain_delta >= ((s16) gain - state->current_gain)) /* overflow */
865 state->current_gain = gain;
866 else
867 state->current_gain += gain_delta;
868 /* cannot be less than 0 (only if gain_delta is less than 0 we can have current_gain < 0) */
869 if (state->current_gain < 0)
870 state->current_gain = 0;
872 /* now split total gain to rf and bb gain */
873 gain = state->current_gain >> GAIN_ALPHA;
875 /* requested gain is bigger than rf gain limit - ACI/WBD adjustment */
876 if (gain > (state->rf_gain_limit >> WBD_ALPHA)) {
877 rf = state->rf_gain_limit >> WBD_ALPHA;
878 bb = gain - rf;
879 if (bb > state->bb_ramp[0])
880 bb = state->bb_ramp[0];
881 } else { /* high signal level -> all gains put on RF */
882 rf = gain;
883 bb = 0;
886 state->gain[0] = rf;
887 state->gain[1] = bb;
889 /* software ramp */
890 /* Start with RF gains */
891 g = state->rf_ramp + 1; /* point on RF LNA1 max gain */
892 ref = rf;
893 for (i = 0; i < 7; i++) { /* Go over all amplifiers => 5RF amps + 2 BB amps = 7 amps */
894 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 */
895 v = 0; /* force the gain to write for the current amp to be null */
896 else if (ref >= g[1]) /* Gain to set is higher than the high working point of this amp */
897 v = g[2]; /* force this amp to be full gain */
898 else /* compute the value to set to this amp because we are somewhere in his range */
899 v = ((ref - (g[1] - g[0])) * g[2]) / g[0];
901 if (i == 0) /* LNA 1 reg mapping */
902 gain_reg[0] = v;
903 else if (i == 1) /* LNA 2 reg mapping */
904 gain_reg[0] |= v << 7;
905 else if (i == 2) /* LNA 3 reg mapping */
906 gain_reg[1] = v;
907 else if (i == 3) /* LNA 4 reg mapping */
908 gain_reg[1] |= v << 7;
909 else if (i == 4) /* CBAND LNA reg mapping */
910 gain_reg[2] = v | state->rf_lt_def;
911 else if (i == 5) /* BB gain 1 reg mapping */
912 gain_reg[3] = v << 3;
913 else if (i == 6) /* BB gain 2 reg mapping */
914 gain_reg[3] |= v << 8;
916 g += 3; /* go to next gain bloc */
918 /* When RF is finished, start with BB */
919 if (i == 4) {
920 g = state->bb_ramp + 1; /* point on BB gain 1 max gain */
921 ref = bb;
924 gain_reg[3] |= state->bb_1_def;
925 gain_reg[3] |= ((bb % 10) * 100) / 125;
927 #ifdef DEBUG_AGC
928 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,
929 gain_reg[0], gain_reg[1], gain_reg[2], gain_reg[3]);
930 #endif
932 /* Write the amplifier regs */
933 for (i = 0; i < 4; i++) {
934 v = gain_reg[i];
935 if (force || state->gain_reg[i] != v) {
936 state->gain_reg[i] = v;
937 dib0090_write_reg(state, gain_reg_addr[i], v);
942 static void dib0090_set_boost(struct dib0090_state *state, int onoff)
944 state->bb_1_def &= 0xdfff;
945 state->bb_1_def |= onoff << 13;
948 static void dib0090_set_rframp(struct dib0090_state *state, const u16 * cfg)
950 state->rf_ramp = cfg;
953 static void dib0090_set_rframp_pwm(struct dib0090_state *state, const u16 * cfg)
955 state->rf_ramp = cfg;
957 dib0090_write_reg(state, 0x2a, 0xffff);
959 dprintk("total RF gain: %ddB, step: %d", (u32) cfg[0], dib0090_read_reg(state, 0x2a));
961 dib0090_write_regs(state, 0x2c, cfg + 3, 6);
962 dib0090_write_regs(state, 0x3e, cfg + 9, 2);
965 static void dib0090_set_bbramp(struct dib0090_state *state, const u16 * cfg)
967 state->bb_ramp = cfg;
968 dib0090_set_boost(state, cfg[0] > 500); /* we want the boost if the gain is higher that 50dB */
971 static void dib0090_set_bbramp_pwm(struct dib0090_state *state, const u16 * cfg)
973 state->bb_ramp = cfg;
975 dib0090_set_boost(state, cfg[0] > 500); /* we want the boost if the gain is higher that 50dB */
977 dib0090_write_reg(state, 0x33, 0xffff);
978 dprintk("total BB gain: %ddB, step: %d", (u32) cfg[0], dib0090_read_reg(state, 0x33));
979 dib0090_write_regs(state, 0x35, cfg + 3, 4);
982 void dib0090_pwm_gain_reset(struct dvb_frontend *fe)
984 struct dib0090_state *state = fe->tuner_priv;
985 /* reset the AGC */
987 if (state->config->use_pwm_agc) {
988 #ifdef CONFIG_BAND_SBAND
989 if (state->current_band == BAND_SBAND) {
990 dib0090_set_rframp_pwm(state, rf_ramp_pwm_sband);
991 dib0090_set_bbramp_pwm(state, bb_ramp_pwm_boost);
992 } else
993 #endif
994 #ifdef CONFIG_BAND_CBAND
995 if (state->current_band == BAND_CBAND) {
996 if (state->identity.in_soc) {
997 dib0090_set_bbramp_pwm(state, bb_ramp_pwm_normal_socs);
998 if (state->identity.version == SOC_8090_P1G_11R1 || state->identity.version == SOC_8090_P1G_21R1)
999 dib0090_set_rframp_pwm(state, rf_ramp_pwm_cband_8090);
1000 else if (state->identity.version == SOC_7090_P1G_11R1 || state->identity.version == SOC_7090_P1G_21R1)
1001 dib0090_set_rframp_pwm(state, rf_ramp_pwm_cband_7090);
1002 } else {
1003 dib0090_set_rframp_pwm(state, rf_ramp_pwm_cband);
1004 dib0090_set_bbramp_pwm(state, bb_ramp_pwm_normal);
1006 } else
1007 #endif
1008 #ifdef CONFIG_BAND_VHF
1009 if (state->current_band == BAND_VHF) {
1010 if (state->identity.in_soc) {
1011 dib0090_set_bbramp_pwm(state, bb_ramp_pwm_normal_socs);
1012 //dib0090_set_rframp_pwm(state, rf_ramp_pwm_vhf_socs); /* TODO */
1013 } else {
1014 dib0090_set_rframp_pwm(state, rf_ramp_pwm_vhf);
1015 dib0090_set_bbramp_pwm(state, bb_ramp_pwm_normal);
1017 } else
1018 #endif
1020 if (state->identity.in_soc) {
1021 if (state->identity.version == SOC_8090_P1G_11R1 || state->identity.version == SOC_8090_P1G_21R1)
1022 dib0090_set_rframp_pwm(state, rf_ramp_pwm_uhf_8090);
1023 else if (state->identity.version == SOC_7090_P1G_11R1 || state->identity.version == SOC_7090_P1G_21R1)
1024 dib0090_set_rframp_pwm(state, rf_ramp_pwm_uhf_7090);
1025 dib0090_set_bbramp_pwm(state, bb_ramp_pwm_normal_socs);
1026 } else {
1027 dib0090_set_rframp_pwm(state, rf_ramp_pwm_uhf);
1028 dib0090_set_bbramp_pwm(state, bb_ramp_pwm_normal);
1032 if (state->rf_ramp[0] != 0)
1033 dib0090_write_reg(state, 0x32, (3 << 11));
1034 else
1035 dib0090_write_reg(state, 0x32, (0 << 11));
1037 dib0090_write_reg(state, 0x04, 0x01);
1038 dib0090_write_reg(state, 0x39, (1 << 10));
1042 EXPORT_SYMBOL(dib0090_pwm_gain_reset);
1044 static u32 dib0090_get_slow_adc_val(struct dib0090_state *state)
1046 u16 adc_val = dib0090_read_reg(state, 0x1d);
1047 if (state->identity.in_soc) {
1048 adc_val >>= 2;
1050 return adc_val;
1053 int dib0090_gain_control(struct dvb_frontend *fe)
1055 struct dib0090_state *state = fe->tuner_priv;
1056 enum frontend_tune_state *tune_state = &state->tune_state;
1057 int ret = 10;
1059 u16 wbd_val = 0;
1060 u8 apply_gain_immediatly = 1;
1061 s16 wbd_error = 0, adc_error = 0;
1063 if (*tune_state == CT_AGC_START) {
1064 state->agc_freeze = 0;
1065 dib0090_write_reg(state, 0x04, 0x0);
1067 #ifdef CONFIG_BAND_SBAND
1068 if (state->current_band == BAND_SBAND) {
1069 dib0090_set_rframp(state, rf_ramp_sband);
1070 dib0090_set_bbramp(state, bb_ramp_boost);
1071 } else
1072 #endif
1073 #ifdef CONFIG_BAND_VHF
1074 if (state->current_band == BAND_VHF && !state->identity.p1g) {
1075 dib0090_set_rframp(state, rf_ramp_vhf);
1076 dib0090_set_bbramp(state, bb_ramp_boost);
1077 } else
1078 #endif
1079 #ifdef CONFIG_BAND_CBAND
1080 if (state->current_band == BAND_CBAND && !state->identity.p1g) {
1081 dib0090_set_rframp(state, rf_ramp_cband);
1082 dib0090_set_bbramp(state, bb_ramp_boost);
1083 } else
1084 #endif
1085 if ((state->current_band == BAND_CBAND || state->current_band == BAND_VHF) && state->identity.p1g) {
1086 dib0090_set_rframp(state, rf_ramp_cband_broadmatching);
1087 dib0090_set_bbramp(state, bb_ramp_boost);
1088 } else {
1089 dib0090_set_rframp(state, rf_ramp_uhf);
1090 dib0090_set_bbramp(state, bb_ramp_boost);
1093 dib0090_write_reg(state, 0x32, 0);
1094 dib0090_write_reg(state, 0x39, 0);
1096 dib0090_wbd_target(state, state->current_rf);
1098 state->rf_gain_limit = state->rf_ramp[0] << WBD_ALPHA;
1099 state->current_gain = ((state->rf_ramp[0] + state->bb_ramp[0]) / 2) << GAIN_ALPHA;
1101 *tune_state = CT_AGC_STEP_0;
1102 } else if (!state->agc_freeze) {
1103 s16 wbd = 0, i, cnt;
1105 int adc;
1106 wbd_val = dib0090_get_slow_adc_val(state);
1108 if (*tune_state == CT_AGC_STEP_0)
1109 cnt = 5;
1110 else
1111 cnt = 1;
1113 for (i = 0; i < cnt; i++) {
1114 wbd_val = dib0090_get_slow_adc_val(state);
1115 wbd += dib0090_wbd_to_db(state, wbd_val);
1117 wbd /= cnt;
1118 wbd_error = state->wbd_target - wbd;
1120 if (*tune_state == CT_AGC_STEP_0) {
1121 if (wbd_error < 0 && state->rf_gain_limit > 0 && !state->identity.p1g) {
1122 #ifdef CONFIG_BAND_CBAND
1123 /* in case of CBAND tune reduce first the lt_gain2 before adjusting the RF gain */
1124 u8 ltg2 = (state->rf_lt_def >> 10) & 0x7;
1125 if (state->current_band == BAND_CBAND && ltg2) {
1126 ltg2 >>= 1;
1127 state->rf_lt_def &= ltg2 << 10; /* reduce in 3 steps from 7 to 0 */
1129 #endif
1130 } else {
1131 state->agc_step = 0;
1132 *tune_state = CT_AGC_STEP_1;
1134 } else {
1135 /* calc the adc power */
1136 adc = state->config->get_adc_power(fe);
1137 adc = (adc * ((s32) 355774) + (((s32) 1) << 20)) >> 21; /* included in [0:-700] */
1139 adc_error = (s16) (((s32) ADC_TARGET) - adc);
1140 #ifdef CONFIG_STANDARD_DAB
1141 if (state->fe->dtv_property_cache.delivery_system == STANDARD_DAB)
1142 adc_error -= 10;
1143 #endif
1144 #ifdef CONFIG_STANDARD_DVBT
1145 if (state->fe->dtv_property_cache.delivery_system == STANDARD_DVBT &&
1146 (state->fe->dtv_property_cache.modulation == QAM_64 || state->fe->dtv_property_cache.modulation == QAM_16))
1147 adc_error += 60;
1148 #endif
1149 #ifdef CONFIG_SYS_ISDBT
1150 if ((state->fe->dtv_property_cache.delivery_system == SYS_ISDBT) && (((state->fe->dtv_property_cache.layer[0].segment_count >
1153 ((state->fe->dtv_property_cache.layer[0].modulation ==
1154 QAM_64)
1155 || (state->fe->dtv_property_cache.
1156 layer[0].modulation == QAM_16)))
1158 ((state->fe->dtv_property_cache.layer[1].segment_count >
1161 ((state->fe->dtv_property_cache.layer[1].modulation ==
1162 QAM_64)
1163 || (state->fe->dtv_property_cache.
1164 layer[1].modulation == QAM_16)))
1166 ((state->fe->dtv_property_cache.layer[2].segment_count >
1169 ((state->fe->dtv_property_cache.layer[2].modulation ==
1170 QAM_64)
1171 || (state->fe->dtv_property_cache.
1172 layer[2].modulation == QAM_16)))
1175 adc_error += 60;
1176 #endif
1178 if (*tune_state == CT_AGC_STEP_1) { /* quickly go to the correct range of the ADC power */
1179 if (ABS(adc_error) < 50 || state->agc_step++ > 5) {
1181 #ifdef CONFIG_STANDARD_DAB
1182 if (state->fe->dtv_property_cache.delivery_system == STANDARD_DAB) {
1183 dib0090_write_reg(state, 0x02, (1 << 15) | (15 << 11) | (31 << 6) | (63)); /* cap value = 63 : narrow BB filter : Fc = 1.8MHz */
1184 dib0090_write_reg(state, 0x04, 0x0);
1185 } else
1186 #endif
1188 dib0090_write_reg(state, 0x02, (1 << 15) | (3 << 11) | (6 << 6) | (32));
1189 dib0090_write_reg(state, 0x04, 0x01); /*0 = 1KHz ; 1 = 150Hz ; 2 = 50Hz ; 3 = 50KHz ; 4 = servo fast */
1192 *tune_state = CT_AGC_STOP;
1194 } else {
1195 /* everything higher than or equal to CT_AGC_STOP means tracking */
1196 ret = 100; /* 10ms interval */
1197 apply_gain_immediatly = 0;
1200 #ifdef DEBUG_AGC
1201 dprintk
1202 ("tune state %d, ADC = %3ddB (ADC err %3d) WBD %3ddB (WBD err %3d, WBD val SADC: %4d), RFGainLimit (TOP): %3d, signal: %3ddBm",
1203 (u32) * tune_state, (u32) adc, (u32) adc_error, (u32) wbd, (u32) wbd_error, (u32) wbd_val,
1204 (u32) state->rf_gain_limit >> WBD_ALPHA, (s32) 200 + adc - (state->current_gain >> GAIN_ALPHA));
1205 #endif
1208 /* apply gain */
1209 if (!state->agc_freeze)
1210 dib0090_gain_apply(state, adc_error, wbd_error, apply_gain_immediatly);
1211 return ret;
1214 EXPORT_SYMBOL(dib0090_gain_control);
1216 void dib0090_get_current_gain(struct dvb_frontend *fe, u16 * rf, u16 * bb, u16 * rf_gain_limit, u16 * rflt)
1218 struct dib0090_state *state = fe->tuner_priv;
1219 if (rf)
1220 *rf = state->gain[0];
1221 if (bb)
1222 *bb = state->gain[1];
1223 if (rf_gain_limit)
1224 *rf_gain_limit = state->rf_gain_limit;
1225 if (rflt)
1226 *rflt = (state->rf_lt_def >> 10) & 0x7;
1229 EXPORT_SYMBOL(dib0090_get_current_gain);
1231 u16 dib0090_get_wbd_offset(struct dvb_frontend *fe)
1233 struct dib0090_state *state = fe->tuner_priv;
1234 u32 f_MHz = state->fe->dtv_property_cache.frequency / 1000000;
1235 s32 current_temp = state->temperature;
1236 s32 wbd_thot, wbd_tcold;
1237 const struct dib0090_wbd_slope *wbd = state->current_wbd_table;
1239 while (f_MHz > wbd->max_freq)
1240 wbd++;
1242 dprintk("using wbd-table-entry with max freq %d", wbd->max_freq);
1244 if (current_temp < 0)
1245 current_temp = 0;
1246 if (current_temp > 128)
1247 current_temp = 128;
1249 //What Wbd gain to apply for this range of frequency
1250 state->wbdmux &= ~(7 << 13);
1251 if (wbd->wbd_gain != 0)
1252 state->wbdmux |= (wbd->wbd_gain << 13);
1253 else
1254 state->wbdmux |= (4 << 13); // 4 is the default WBD gain
1256 dib0090_write_reg(state, 0x10, state->wbdmux);
1258 //All the curves are linear with slope*f/64+offset
1259 wbd_thot = wbd->offset_hot - (((u32) wbd->slope_hot * f_MHz) >> 6);
1260 wbd_tcold = wbd->offset_cold - (((u32) wbd->slope_cold * f_MHz) >> 6);
1262 // Iet assumes that thot-tcold = 130 equiv 128, current temperature ref is -30deg
1264 wbd_tcold += ((wbd_thot - wbd_tcold) * current_temp) >> 7;
1266 //for (offset = 0; offset < 1000; offset += 4)
1267 // dbgp("offset = %d -> %d\n", offset, dib0090_wbd_to_db(state, offset));
1268 state->wbd_target = dib0090_wbd_to_db(state, state->wbd_offset + wbd_tcold); // get the value in dBm from the offset
1269 dprintk("wbd-target: %d dB", (u32) state->wbd_target);
1270 dprintk("wbd offset applied is %d", wbd_tcold);
1272 return state->wbd_offset + wbd_tcold;
1275 EXPORT_SYMBOL(dib0090_get_wbd_offset);
1277 static const u16 dib0090_defaults[] = {
1279 25, 0x01,
1280 0x0000,
1281 0x99a0,
1282 0x6008,
1283 0x0000,
1284 0x8bcb,
1285 0x0000,
1286 0x0405,
1287 0x0000,
1288 0x0000,
1289 0x0000,
1290 0xb802,
1291 0x0300,
1292 0x2d12,
1293 0xbac0,
1294 0x7c00,
1295 0xdbb9,
1296 0x0954,
1297 0x0743,
1298 0x8000,
1299 0x0001,
1300 0x0040,
1301 0x0100,
1302 0x0000,
1303 0xe910,
1304 0x149e,
1306 1, 0x1c,
1307 0xff2d,
1309 1, 0x39,
1310 0x0000,
1312 2, 0x1e,
1313 0x07FF,
1314 0x0007,
1316 1, 0x24,
1317 EN_UHF | EN_CRYSTAL,
1319 2, 0x3c,
1320 0x3ff,
1321 0x111,
1325 static const u16 dib0090_p1g_additionnal_defaults[] = {
1326 // additionnal INITIALISATION for p1g to be written after dib0090_defaults
1327 1, 0x05,
1328 0xabcd,
1330 1, 0x11,
1331 0x00b4,
1333 1, 0x1c,
1334 0xfffd,
1336 1, 0x40,
1337 0x108,
1341 static void dib0090_set_default_config(struct dib0090_state *state, const u16 * n)
1343 u16 l, r;
1345 l = pgm_read_word(n++);
1346 while (l) {
1347 r = pgm_read_word(n++);
1348 do {
1349 dib0090_write_reg(state, r, pgm_read_word(n++));
1350 r++;
1351 } while (--l);
1352 l = pgm_read_word(n++);
1356 #define CAP_VALUE_MIN (u8) 9
1357 #define CAP_VALUE_MAX (u8) 40
1358 #define HR_MIN (u8) 25
1359 #define HR_MAX (u8) 40
1360 #define POLY_MIN (u8) 0
1361 #define POLY_MAX (u8) 8
1363 void dib0090_set_EFUSE(struct dib0090_state *state)
1365 u8 c,h,n;
1366 u16 e2,e4;
1367 u16 cal;
1369 e2=dib0090_read_reg(state,0x26);
1370 e4=dib0090_read_reg(state,0x28);
1372 if ((state->identity.version == P1D_E_F) || // All P1F uses the internal calibration
1373 (state->identity.version == P1G) || (e2 == 0xffff)) { //W0090G11R1 and W0090G11R1-D : We will find the calibration Value of the Baseband
1375 dib0090_write_reg(state,0x22,0x10); //Start the Calib
1376 cal = (dib0090_read_reg(state,0x22)>>6) & 0x3ff;
1378 if ((cal<670) || (cal==1023)) //Cal at 800 would give too high value for the n
1379 cal=850; //Recenter the n to 32
1380 n = 165 - ((cal * 10)>>6) ;
1381 e2 = e4 = (3<<12) | (34<<6) | (n);
1384 if (e2!=e4) {
1385 e2 &= e4; /* Remove the redundancy */
1388 if (e2 != 0xffff) {
1389 c = e2 & 0x3f;
1390 n = (e2 >> 12) & 0xf;
1391 h= (e2 >> 6) & 0x3f;
1393 if ((c >= CAP_VALUE_MAX) || (c <= CAP_VALUE_MIN))
1394 c=32;
1395 if ((h >= HR_MAX) || (h <= HR_MIN))
1396 h=34;
1397 if ((n >= POLY_MAX) || (n <= POLY_MIN))
1398 n=3;
1400 dib0090_write_reg(state,0x13, (h << 10)) ;
1401 e2 = (n<<11) | ((h>>2)<<6) | (c);
1402 dib0090_write_reg(state,0x2, e2) ; /* Load the BB_2 */
1406 static int dib0090_reset(struct dvb_frontend *fe)
1408 struct dib0090_state *state = fe->tuner_priv;
1410 dib0090_reset_digital(fe, state->config);
1411 if (dib0090_identify(fe) < 0)
1412 return -EIO;
1414 #ifdef CONFIG_TUNER_DIB0090_P1B_SUPPORT
1415 if (!(state->identity.version & 0x1)) /* it is P1B - reset is already done */
1416 return 0;
1417 #endif
1419 if (!state->identity.in_soc) {
1420 if ((dib0090_read_reg(state, 0x1a) >> 5) & 0x2)
1421 dib0090_write_reg(state, 0x1b, (EN_IQADC | EN_BB | EN_BIAS | EN_DIGCLK | EN_PLL | EN_CRYSTAL));
1422 else
1423 dib0090_write_reg(state, 0x1b, (EN_DIGCLK | EN_PLL | EN_CRYSTAL));
1426 dib0090_set_default_config(state, dib0090_defaults);
1428 if (state->identity.in_soc)
1429 dib0090_write_reg(state, 0x18, 0x2910); /* charge pump current = 0 */
1431 if (state->identity.p1g)
1432 dib0090_set_default_config(state, dib0090_p1g_additionnal_defaults);
1434 if (((state->identity.version & 0x1f) >= P1D_E_F) || (state->identity.in_soc)) /* Update the efuse : Only available for KROSUS > P1C and SOC as well*/
1435 dib0090_set_EFUSE(state);
1437 /* Congigure in function of the crystal */
1438 if (state->config->io.clock_khz >= 24000)
1439 dib0090_write_reg(state, 0x14, 1);
1440 else
1441 dib0090_write_reg(state, 0x14, 2);
1442 dprintk("Pll lock : %d", (dib0090_read_reg(state, 0x1a) >> 11) & 0x1);
1444 state->calibrate = DC_CAL | WBD_CAL | TEMP_CAL; /* enable iq-offset-calibration and wbd-calibration when tuning next time */
1446 return 0;
1449 #define steps(u) (((u) > 15) ? ((u)-16) : (u))
1450 #define INTERN_WAIT 10
1451 static int dib0090_get_offset(struct dib0090_state *state, enum frontend_tune_state *tune_state)
1453 int ret = INTERN_WAIT * 10;
1455 switch (*tune_state) {
1456 case CT_TUNER_STEP_2:
1457 /* Turns to positive */
1458 dib0090_write_reg(state, 0x1f, 0x7);
1459 *tune_state = CT_TUNER_STEP_3;
1460 break;
1462 case CT_TUNER_STEP_3:
1463 state->adc_diff = dib0090_read_reg(state, 0x1d);
1465 /* Turns to negative */
1466 dib0090_write_reg(state, 0x1f, 0x4);
1467 *tune_state = CT_TUNER_STEP_4;
1468 break;
1470 case CT_TUNER_STEP_4:
1471 state->adc_diff -= dib0090_read_reg(state, 0x1d);
1472 *tune_state = CT_TUNER_STEP_5;
1473 ret = 0;
1474 break;
1476 default:
1477 break;
1480 return ret;
1483 struct dc_calibration {
1484 u8 addr;
1485 u8 offset;
1486 u8 pga:1;
1487 u16 bb1;
1488 u8 i:1;
1491 static const struct dc_calibration dc_table[] = {
1492 /* Step1 BB gain1= 26 with boost 1, gain 2 = 0 */
1493 {0x06, 5, 1, (1 << 13) | (0 << 8) | (26 << 3), 1},
1494 {0x07, 11, 1, (1 << 13) | (0 << 8) | (26 << 3), 0},
1495 /* Step 2 BB gain 1 = 26 with boost = 1 & gain 2 = 29 */
1496 {0x06, 0, 0, (1 << 13) | (29 << 8) | (26 << 3), 1},
1497 {0x06, 10, 0, (1 << 13) | (29 << 8) | (26 << 3), 0},
1498 {0},
1501 static const struct dc_calibration dc_p1g_table[] = {
1502 /* Step1 BB gain1= 26 with boost 1, gain 2 = 0 */
1503 /* addr ; trim reg offset ; pga ; CTRL_BB1 value ; i or q */
1504 {0x06, 5, 1, (1 << 13) | (0 << 8) | (15 << 3), 1}, // offset_trim2_i_chann 0 0 5 0 0 1 6 9 5
1505 {0x07, 11, 1, (1 << 13) | (0 << 8) | (15 << 3), 0}, // offset_trim2_q_chann 0 0 5 0 0 1 7 15 11
1506 /* Step 2 BB gain 1 = 26 with boost = 1 & gain 2 = 29 */
1507 {0x06, 0, 0, (1 << 13) | (29 << 8) | (15 << 3), 1}, // offset_trim1_i_chann 0 0 5 0 0 1 6 4 0
1508 {0x06, 10, 0, (1 << 13) | (29 << 8) | (15 << 3), 0}, // offset_trim1_q_chann 0 0 5 0 0 1 6 14 10
1509 {0},
1512 static void dib0090_set_trim(struct dib0090_state *state)
1514 u16 *val;
1516 if (state->dc->addr == 0x07)
1517 val = &state->bb7;
1518 else
1519 val = &state->bb6;
1521 *val &= ~(0x1f << state->dc->offset);
1522 *val |= state->step << state->dc->offset;
1524 dib0090_write_reg(state, state->dc->addr, *val);
1527 static int dib0090_dc_offset_calibration(struct dib0090_state *state, enum frontend_tune_state *tune_state)
1529 int ret = 0;
1530 u16 reg;
1532 switch (*tune_state) {
1533 case CT_TUNER_START:
1534 dprintk("Start DC offset calibration");
1536 /* force vcm2 = 0.8V */
1537 state->bb6 = 0;
1538 state->bb7 = 0x040d;
1540 /* the LNA AND LO are off */
1541 reg = dib0090_read_reg(state, 0x24) & 0x0ffb; /* shutdown lna and lo */
1542 dib0090_write_reg(state, 0x24, reg);
1544 state->wbdmux = dib0090_read_reg(state, 0x10);
1545 dib0090_write_reg(state, 0x10, (state->wbdmux & ~(0xff << 3)) | (0x7 << 3) | 0x3); // connect BB, disable WDB enable*
1546 dib0090_write_reg(state, 0x23, dib0090_read_reg(state, 0x23) & ~(1 << 14)); //Discard the DataTX
1548 state->dc = dc_table;
1550 if (state->identity.p1g)
1551 state->dc = dc_p1g_table;
1552 *tune_state = CT_TUNER_STEP_0;
1554 /* fall through */
1556 case CT_TUNER_STEP_0:
1557 dprintk("Sart/continue DC calibration for %s path", (state->dc->i == 1) ? "I" : "Q");
1558 dib0090_write_reg(state, 0x01, state->dc->bb1);
1559 dib0090_write_reg(state, 0x07, state->bb7 | (state->dc->i << 7));
1561 state->step = 0;
1562 state->min_adc_diff = 1023;
1563 *tune_state = CT_TUNER_STEP_1;
1564 ret = 50;
1565 break;
1567 case CT_TUNER_STEP_1:
1568 dib0090_set_trim(state);
1569 *tune_state = CT_TUNER_STEP_2;
1570 break;
1572 case CT_TUNER_STEP_2:
1573 case CT_TUNER_STEP_3:
1574 case CT_TUNER_STEP_4:
1575 ret = dib0090_get_offset(state, tune_state);
1576 break;
1578 case CT_TUNER_STEP_5: /* found an offset */
1579 dprintk("adc_diff = %d, current step= %d", (u32) state->adc_diff, state->step);
1580 if (state->step == 0 && state->adc_diff < 0) {
1581 state->min_adc_diff = -1023;
1582 dprintk("Change of sign of the minimum adc diff");
1585 dprintk("adc_diff = %d, min_adc_diff = %d current_step = %d", state->adc_diff, state->min_adc_diff, state->step);
1587 /* first turn for this frequency */
1588 if (state->step == 0) {
1589 if (state->dc->pga && state->adc_diff < 0)
1590 state->step = 0x10;
1591 if (state->dc->pga == 0 && state->adc_diff > 0)
1592 state->step = 0x10;
1595 /* Look for a change of Sign in the Adc_diff.min_adc_diff is used to STORE the setp N-1 */
1596 if ((state->adc_diff & 0x8000) == (state->min_adc_diff & 0x8000) && steps(state->step) < 15) {
1597 /* stop search when the delta the sign is changing and Steps =15 and Step=0 is force for continuance */
1598 state->step++;
1599 state->min_adc_diff = state->adc_diff; //min is used as N-1
1600 *tune_state = CT_TUNER_STEP_1;
1601 } else {
1602 /* the minimum was what we have seen in the step before */
1603 if (ABS(state->adc_diff) > ABS(state->min_adc_diff)) { //Come back to the previous state since the delta was better
1604 dprintk("Since adc_diff N = %d > adc_diff step N-1 = %d, Come back one step", state->adc_diff, state->min_adc_diff);
1605 state->step--;
1608 dib0090_set_trim(state);
1609 dprintk("BB Offset Cal, BBreg=%hd,Offset=%hd,Value Set=%hd", state->dc->addr, state->adc_diff, state->step);
1611 state->dc++;
1612 if (state->dc->addr == 0) /* done */
1613 *tune_state = CT_TUNER_STEP_6;
1614 else
1615 *tune_state = CT_TUNER_STEP_0;
1618 break;
1620 case CT_TUNER_STEP_6:
1621 dib0090_write_reg(state, 0x07, state->bb7 & ~0x0008); //Force the test bus to be off
1622 dib0090_write_reg(state, 0x1f, 0x7);
1623 *tune_state = CT_TUNER_START; /* reset done -> real tuning can now begin */
1624 state->calibrate &= ~DC_CAL;
1625 default:
1626 break;
1628 return ret;
1631 static int dib0090_wbd_calibration(struct dib0090_state *state, enum frontend_tune_state *tune_state)
1633 u8 wbd_gain;
1634 const struct dib0090_wbd_slope *wbd = state->current_wbd_table;
1636 switch (*tune_state) {
1637 case CT_TUNER_START:
1638 while (state->current_rf / 1000 > wbd->max_freq)
1639 wbd++;
1640 if (wbd->wbd_gain != 0)
1641 wbd_gain = wbd->wbd_gain;
1642 else {
1643 wbd_gain = 4;
1644 #if defined(CONFIG_BAND_LBAND) || defined(CONFIG_BAND_SBAND)
1645 if ((state->current_band == BAND_LBAND) || (state->current_band == BAND_SBAND))
1646 wbd_gain = 2;
1647 #endif
1650 if (wbd_gain == state->wbd_calibration_gain) { /* the WBD calibration has already been done */
1651 *tune_state = CT_TUNER_START;
1652 state->calibrate &= ~WBD_CAL;
1653 return 0;
1656 dib0090_write_reg(state, 0x10, 0x1b81 | (1 << 10) | (wbd_gain << 13) | (1 << 3)); // Force: WBD enable,gain to 4, mux to WBD
1658 dib0090_write_reg(state, 0x24, ((EN_UHF & 0x0fff) | (1 << 1))); //Discard all LNA but crystal !!!
1659 *tune_state = CT_TUNER_STEP_0;
1660 state->wbd_calibration_gain = wbd_gain;
1661 return 90; /* wait for the WBDMUX to switch and for the ADC to sample */
1663 case CT_TUNER_STEP_0:
1664 state->wbd_offset = dib0090_get_slow_adc_val(state);
1665 dprintk("WBD calibration offset = %d", state->wbd_offset);
1666 *tune_state = CT_TUNER_START; /* reset done -> real tuning can now begin */
1667 state->calibrate &= ~WBD_CAL;
1668 break;
1670 default:
1671 break;
1673 return 0;
1676 static void dib0090_set_bandwidth(struct dib0090_state *state)
1678 u16 tmp;
1680 if (state->fe->dtv_property_cache.bandwidth_hz / 1000 <= 5000)
1681 tmp = (3 << 14);
1682 else if (state->fe->dtv_property_cache.bandwidth_hz / 1000 <= 6000)
1683 tmp = (2 << 14);
1684 else if (state->fe->dtv_property_cache.bandwidth_hz / 1000 <= 7000)
1685 tmp = (1 << 14);
1686 else
1687 tmp = (0 << 14);
1689 state->bb_1_def &= 0x3fff;
1690 state->bb_1_def |= tmp;
1692 dib0090_write_reg(state, 0x01, state->bb_1_def); /* be sure that we have the right bb-filter */
1694 dib0090_write_reg(state, 0x03, 0x6008); /* = 0x6008 : vcm3_trim = 1 ; filter2_gm1_trim = 8 ; filter2_cutoff_freq = 0 */
1695 dib0090_write_reg(state, 0x04, 0x1); /* 0 = 1KHz ; 1 = 50Hz ; 2 = 150Hz ; 3 = 50KHz ; 4 = servo fast */
1696 if (state->identity.in_soc) {
1697 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 */
1698 } else {
1699 dib0090_write_reg(state, 0x02, (5 << 11) | (8 << 6) | (22 & 0x3f)); /* 22 = cap_value */
1700 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 */
1704 static const struct dib0090_pll dib0090_pll_table[] = {
1705 #ifdef CONFIG_BAND_CBAND
1706 {56000, 0, 9, 48, 6},
1707 {70000, 1, 9, 48, 6},
1708 {87000, 0, 8, 32, 4},
1709 {105000, 1, 8, 32, 4},
1710 {115000, 0, 7, 24, 6},
1711 {140000, 1, 7, 24, 6},
1712 {170000, 0, 6, 16, 4},
1713 #endif
1714 #ifdef CONFIG_BAND_VHF
1715 {200000, 1, 6, 16, 4},
1716 {230000, 0, 5, 12, 6},
1717 {280000, 1, 5, 12, 6},
1718 {340000, 0, 4, 8, 4},
1719 {380000, 1, 4, 8, 4},
1720 {450000, 0, 3, 6, 6},
1721 #endif
1722 #ifdef CONFIG_BAND_UHF
1723 {580000, 1, 3, 6, 6},
1724 {700000, 0, 2, 4, 4},
1725 {860000, 1, 2, 4, 4},
1726 #endif
1727 #ifdef CONFIG_BAND_LBAND
1728 {1800000, 1, 0, 2, 4},
1729 #endif
1730 #ifdef CONFIG_BAND_SBAND
1731 {2900000, 0, 14, 1, 4},
1732 #endif
1735 static const struct dib0090_tuning dib0090_tuning_table_fm_vhf_on_cband[] = {
1737 #ifdef CONFIG_BAND_CBAND
1738 {184000, 4, 1, 15, 0x280, 0x2912, 0xb94e, EN_CAB},
1739 {227000, 4, 3, 15, 0x280, 0x2912, 0xb94e, EN_CAB},
1740 {380000, 4, 7, 15, 0x280, 0x2912, 0xb94e, EN_CAB},
1741 #endif
1742 #ifdef CONFIG_BAND_UHF
1743 {520000, 2, 0, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},
1744 {550000, 2, 2, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},
1745 {650000, 2, 3, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},
1746 {750000, 2, 5, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},
1747 {850000, 2, 6, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},
1748 {900000, 2, 7, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},
1749 #endif
1750 #ifdef CONFIG_BAND_LBAND
1751 {1500000, 4, 0, 20, 0x300, 0x1912, 0x82c9, EN_LBD},
1752 {1600000, 4, 1, 20, 0x300, 0x1912, 0x82c9, EN_LBD},
1753 {1800000, 4, 3, 20, 0x300, 0x1912, 0x82c9, EN_LBD},
1754 #endif
1755 #ifdef CONFIG_BAND_SBAND
1756 {2300000, 1, 4, 20, 0x300, 0x2d2A, 0x82c7, EN_SBD},
1757 {2900000, 1, 7, 20, 0x280, 0x2deb, 0x8347, EN_SBD},
1758 #endif
1761 static const struct dib0090_tuning dib0090_tuning_table[] = {
1763 #ifdef CONFIG_BAND_CBAND
1764 {170000, 4, 1, 15, 0x280, 0x2912, 0xb94e, EN_CAB},
1765 #endif
1766 #ifdef CONFIG_BAND_VHF
1767 {184000, 1, 1, 15, 0x300, 0x4d12, 0xb94e, EN_VHF},
1768 {227000, 1, 3, 15, 0x300, 0x4d12, 0xb94e, EN_VHF},
1769 {380000, 1, 7, 15, 0x300, 0x4d12, 0xb94e, EN_VHF},
1770 #endif
1771 #ifdef CONFIG_BAND_UHF
1772 {520000, 2, 0, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},
1773 {550000, 2, 2, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},
1774 {650000, 2, 3, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},
1775 {750000, 2, 5, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},
1776 {850000, 2, 6, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},
1777 {900000, 2, 7, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},
1778 #endif
1779 #ifdef CONFIG_BAND_LBAND
1780 {1500000, 4, 0, 20, 0x300, 0x1912, 0x82c9, EN_LBD},
1781 {1600000, 4, 1, 20, 0x300, 0x1912, 0x82c9, EN_LBD},
1782 {1800000, 4, 3, 20, 0x300, 0x1912, 0x82c9, EN_LBD},
1783 #endif
1784 #ifdef CONFIG_BAND_SBAND
1785 {2300000, 1, 4, 20, 0x300, 0x2d2A, 0x82c7, EN_SBD},
1786 {2900000, 1, 7, 20, 0x280, 0x2deb, 0x8347, EN_SBD},
1787 #endif
1790 static const struct dib0090_tuning dib0090_p1g_tuning_table[] = {
1791 //max_freq, switch_trim, lna_tune, lna_bias, v2i, mix, load, tuner_enable;
1792 #ifdef CONFIG_BAND_CBAND
1793 {170000, 4, 1, 0x820f, 0x300, 0x2d22, 0x82cb, EN_CAB}, // FM EN_CAB
1794 #endif
1795 #ifdef CONFIG_BAND_VHF
1796 {184000, 1, 1, 15, 0x300, 0x4d12, 0xb94e, EN_VHF}, // VHF EN_VHF
1797 {227000, 1, 3, 15, 0x300, 0x4d12, 0xb94e, EN_VHF}, // VHF EN_VHF
1798 {380000, 1, 7, 15, 0x300, 0x4d12, 0xb94e, EN_VHF}, // VHF EN_VHF
1799 #endif
1800 #ifdef CONFIG_BAND_UHF
1801 {510000, 2, 0, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF}, // UHF
1802 {540000, 2, 1, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF}, // UHF
1803 {600000, 2, 3, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF}, // UHF
1804 {630000, 2, 4, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF}, // UHF
1805 {680000, 2, 5, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF}, // UHF
1806 {720000, 2, 6, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF}, // UHF
1807 {900000, 2, 7, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF}, // UHF
1808 #endif
1809 #ifdef CONFIG_BAND_LBAND
1810 {1500000, 4, 0, 20, 0x300, 0x1912, 0x82c9, EN_LBD}, // LBD EN_LBD
1811 {1600000, 4, 1, 20, 0x300, 0x1912, 0x82c9, EN_LBD}, // LBD EN_LBD
1812 {1800000, 4, 3, 20, 0x300, 0x1912, 0x82c9, EN_LBD}, // LBD EN_LBD
1813 #endif
1814 #ifdef CONFIG_BAND_SBAND
1815 {2300000, 1, 4, 20, 0x300, 0x2d2A, 0x82c7, EN_SBD}, // SBD EN_SBD
1816 {2900000, 1, 7, 20, 0x280, 0x2deb, 0x8347, EN_SBD}, // SBD EN_SBD
1817 #endif
1820 static const struct dib0090_pll dib0090_p1g_pll_table[] = {
1821 #ifdef CONFIG_BAND_CBAND
1822 {57000, 0, 11, 48, 6}, // CAB
1823 {70000, 1, 11, 48, 6}, // CAB
1824 {86000, 0, 10, 32, 4}, // CAB
1825 {105000, 1, 10, 32, 4}, // FM
1826 {115000, 0, 9, 24, 6}, // FM
1827 {140000, 1, 9, 24, 6}, // MID FM VHF
1828 {170000, 0, 8, 16, 4}, // MID FM VHF
1829 #endif
1830 #ifdef CONFIG_BAND_VHF
1831 {200000, 1, 8, 16, 4}, // VHF
1832 {230000, 0, 7, 12, 6}, // VHF
1833 {280000, 1, 7, 12, 6}, // MID VHF UHF
1834 {340000, 0, 6, 8, 4}, // MID VHF UHF
1835 {380000, 1, 6, 8, 4}, // MID VHF UHF
1836 {455000, 0, 5, 6, 6}, // MID VHF UHF
1837 #endif
1838 #ifdef CONFIG_BAND_UHF
1839 {580000, 1, 5, 6, 6}, // UHF
1840 {680000, 0, 4, 4, 4}, // UHF
1841 {860000, 1, 4, 4, 4}, // UHF
1842 #endif
1843 #ifdef CONFIG_BAND_LBAND
1844 {1800000, 1, 2, 2, 4}, // LBD
1845 #endif
1846 #ifdef CONFIG_BAND_SBAND
1847 {2900000, 0, 1, 1, 6}, // SBD
1848 #endif
1851 static const struct dib0090_tuning dib0090_p1g_tuning_table_fm_vhf_on_cband[] = {
1852 //max_freq, switch_trim, lna_tune, lna_bias, v2i, mix, load, tuner_enable;
1853 #ifdef CONFIG_BAND_CBAND
1854 {184000, 4, 3, 0x4187, 0x2c0, 0x2d22, 0x81cb, EN_CAB}, // FM EN_CAB // 0x8190 Good perf but higher current //0x4187 Low current
1855 {227000, 4, 3, 0x4187, 0x2c0, 0x2d22, 0x81cb, EN_CAB}, // FM EN_CAB
1856 {380000, 4, 3, 0x4187, 0x2c0, 0x2d22, 0x81cb, EN_CAB}, // FM EN_CAB
1857 #endif
1858 #ifdef CONFIG_BAND_UHF
1859 {520000, 2, 0, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF}, // UHF
1860 {550000, 2, 2, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF}, // UHF
1861 {650000, 2, 3, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF}, // UHF
1862 {750000, 2, 5, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF}, // UHF
1863 {850000, 2, 6, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF}, // UHF
1864 {900000, 2, 7, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF}, // UHF
1865 #endif
1866 #ifdef CONFIG_BAND_LBAND
1867 {1500000, 4, 0, 20, 0x300, 0x1912, 0x82c9, EN_LBD}, // LBD EN_LBD
1868 {1600000, 4, 1, 20, 0x300, 0x1912, 0x82c9, EN_LBD}, // LBD EN_LBD
1869 {1800000, 4, 3, 20, 0x300, 0x1912, 0x82c9, EN_LBD}, // LBD EN_LBD
1870 #endif
1871 #ifdef CONFIG_BAND_SBAND
1872 {2300000, 1, 4, 20, 0x300, 0x2d2A, 0x82c7, EN_SBD}, // SBD EN_SBD
1873 {2900000, 1, 7, 20, 0x280, 0x2deb, 0x8347, EN_SBD}, // SBD EN_SBD
1874 #endif
1877 static const struct dib0090_tuning dib0090_tuning_table_cband_7090[] = {
1878 //max_freq, switch_trim, lna_tune, lna_bias, v2i, mix, load, tuner_enable;
1879 #ifdef CONFIG_BAND_CBAND
1880 //{ 184000, 4, 3, 0x018F, 0x2c0, 0x2d22, 0xb9ce, EN_CAB }, // 0x81ce 0x8190 Good perf but higher current //0x4187 Low current
1881 {300000, 4, 3, 0x018F, 0x2c0, 0x2d22, 0xb9ce, EN_CAB},
1882 {380000, 4, 10, 0x018F, 0x2c0, 0x2d22, 0xb9ce, EN_CAB}, //0x4187
1883 {570000, 4, 10, 0x8190, 0x2c0, 0x2d22, 0xb9ce, EN_CAB},
1884 {858000, 4, 5, 0x8190, 0x2c0, 0x2d22, 0xb9ce, EN_CAB},
1885 #endif
1888 static int dib0090_captrim_search(struct dib0090_state *state, enum frontend_tune_state *tune_state)
1890 int ret = 0;
1891 u16 lo4 = 0xe900;
1893 s16 adc_target;
1894 u16 adc;
1895 s8 step_sign;
1896 u8 force_soft_search = 0;
1898 if (state->identity.version == SOC_8090_P1G_11R1 || state->identity.version == SOC_8090_P1G_21R1)
1899 force_soft_search = 1;
1901 if (*tune_state == CT_TUNER_START) {
1902 dprintk("Start Captrim search : %s", (force_soft_search == 1) ? "FORCE SOFT SEARCH" : "AUTO");
1903 dib0090_write_reg(state, 0x10, 0x2B1);
1904 dib0090_write_reg(state, 0x1e, 0x0032);
1906 if (!state->tuner_is_tuned) {
1907 /* prepare a complete captrim */
1908 if (!state->identity.p1g || force_soft_search)
1909 state->step = state->captrim = state->fcaptrim = 64;
1911 state->current_rf = state->rf_request;
1912 } else { /* we are already tuned to this frequency - the configuration is correct */
1913 if (!state->identity.p1g || force_soft_search) {
1914 /* do a minimal captrim even if the frequency has not changed */
1915 state->step = 4;
1916 state->captrim = state->fcaptrim = dib0090_read_reg(state, 0x18) & 0x7f;
1919 state->adc_diff = 3000; // start with a unreachable high number : only set for KROSUS < P1G */
1920 *tune_state = CT_TUNER_STEP_0;
1922 } else if (*tune_state == CT_TUNER_STEP_0) {
1923 if (state->identity.p1g && !force_soft_search) {
1924 // 30MHz => Code 15 for the ration => 128us to lock. Giving approximately
1925 u8 ratio = 31; // (state->config->io.clock_khz / 1024 + 1) & 0x1f;
1927 dib0090_write_reg(state, 0x40, (3 << 7) | (ratio << 2) | (1 << 1) | 1);
1928 dib0090_read_reg(state, 0x40);
1929 //dib0090_write_reg(state, 0x40, (3<<7) | ((((state->config->io.clock_khz >> 11)+1) & 0x1f)<<2) | (1<<1) | 1);
1930 ret = 50;
1931 } else {
1932 state->step /= 2;
1933 dib0090_write_reg(state, 0x18, lo4 | state->captrim);
1935 if (state->identity.in_soc)
1936 ret = 25;
1938 *tune_state = CT_TUNER_STEP_1;
1940 } else if (*tune_state == CT_TUNER_STEP_1) {
1941 if (state->identity.p1g && !force_soft_search) {
1942 dib0090_write_reg(state, 0x40, 0x18c | (0 << 1) | 0);
1943 dib0090_read_reg(state, 0x40);
1945 state->fcaptrim = dib0090_read_reg(state, 0x18) & 0x7F;
1946 dprintk("***Final Captrim= 0x%x", state->fcaptrim);
1947 *tune_state = CT_TUNER_STEP_3;
1949 } else {
1950 /* MERGE for all krosus before P1G */
1951 adc = dib0090_get_slow_adc_val(state);
1952 dprintk("CAPTRIM=%d; ADC = %d (ADC) & %dmV", (u32) state->captrim, (u32) adc, (u32) (adc) * (u32) 1800 / (u32) 1024);
1954 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 !!! */
1955 adc_target = 200;
1956 } else
1957 adc_target = 400;
1959 if (adc >= adc_target) {
1960 adc -= adc_target;
1961 step_sign = -1;
1962 } else {
1963 adc = adc_target - adc;
1964 step_sign = 1;
1967 if (adc < state->adc_diff) {
1968 dprintk("CAPTRIM=%d is closer to target (%d/%d)", (u32) state->captrim, (u32) adc, (u32) state->adc_diff);
1969 state->adc_diff = adc;
1970 state->fcaptrim = state->captrim;
1971 //we could break here, to save time, if we reached a close-enough value
1972 //e.g.: if (state->adc_diff < 20)
1973 //break;
1976 state->captrim += step_sign * state->step;
1977 if (state->step >= 1)
1978 *tune_state = CT_TUNER_STEP_0;
1979 else
1980 *tune_state = CT_TUNER_STEP_2;
1982 ret = 25; //LOLO changed from 15
1984 } else if (*tune_state == CT_TUNER_STEP_2) { /* this step is only used by krosus < P1G */
1985 /*write the final cptrim config */
1986 dib0090_write_reg(state, 0x18, lo4 | state->fcaptrim);
1988 *tune_state = CT_TUNER_STEP_3;
1990 } else if (*tune_state == CT_TUNER_STEP_3) {
1991 state->calibrate &= ~CAPTRIM_CAL;
1992 *tune_state = CT_TUNER_STEP_0;
1995 return ret;
1998 static int dib0090_get_temperature(struct dib0090_state *state, enum frontend_tune_state *tune_state)
2000 int ret = 15;
2001 s16 val;
2003 //The assumption is that the AGC is not active
2004 switch (*tune_state) {
2005 case CT_TUNER_START:
2006 state->wbdmux = dib0090_read_reg(state, 0x10);
2007 dib0090_write_reg(state, 0x10, (state->wbdmux & ~(0xff << 3)) | (0x8 << 3)); //Move to the bias and clear the wbd enable
2009 state->bias = dib0090_read_reg(state, 0x13);
2010 dib0090_write_reg(state, 0x13, state->bias | (0x3 << 8)); //Move to the Ref
2012 *tune_state = CT_TUNER_STEP_0;
2013 /* wait for the WBDMUX to switch and for the ADC to sample */
2014 break;
2016 case CT_TUNER_STEP_0:
2017 state->adc_diff = dib0090_get_slow_adc_val(state); // Get the value for the Ref
2018 dib0090_write_reg(state, 0x13, (state->bias & ~(0x3 << 8)) | (0x2 << 8)); //Move to the Ptat
2019 *tune_state = CT_TUNER_STEP_1;
2020 break;
2022 case CT_TUNER_STEP_1:
2023 val = dib0090_get_slow_adc_val(state); // Get the value for the Ptat
2024 state->temperature = ((s16) ((val - state->adc_diff) * 180) >> 8) + 55; // +55 is defined as = -30deg
2026 dprintk("temperature: %d C", state->temperature - 30);
2028 *tune_state = CT_TUNER_STEP_2;
2029 break;
2031 case CT_TUNER_STEP_2:
2032 //Reload the start values.
2033 dib0090_write_reg(state, 0x13, state->bias);
2034 dib0090_write_reg(state, 0x10, state->wbdmux); /* write back original WBDMUX */
2036 *tune_state = CT_TUNER_START;
2037 state->calibrate &= ~TEMP_CAL;
2038 if (state->config->analog_output == 0)
2039 dib0090_write_reg(state, 0x23, dib0090_read_reg(state, 0x23) | (1 << 14)); //Set the DataTX
2041 break;
2043 default:
2044 ret = 0;
2045 break;
2047 return ret;
2050 #define WBD 0x781 /* 1 1 1 1 0000 0 0 1 */
2051 static int dib0090_tune(struct dvb_frontend *fe)
2053 struct dib0090_state *state = fe->tuner_priv;
2054 const struct dib0090_tuning *tune = state->current_tune_table_index;
2055 const struct dib0090_pll *pll = state->current_pll_table_index;
2056 enum frontend_tune_state *tune_state = &state->tune_state;
2058 u16 lo5, lo6, Den, tmp;
2059 u32 FBDiv, Rest, FREF, VCOF_kHz = 0;
2060 int ret = 10; /* 1ms is the default delay most of the time */
2061 u8 c, i;
2063 /************************* VCO ***************************/
2064 /* Default values for FG */
2065 /* from these are needed : */
2066 /* Cp,HFdiv,VCOband,SD,Num,Den,FB and REFDiv */
2068 /* in any case we first need to do a calibration if needed */
2069 if (*tune_state == CT_TUNER_START) {
2070 /* deactivate DataTX before some calibrations */
2071 if (state->calibrate & (DC_CAL | TEMP_CAL | WBD_CAL))
2072 dib0090_write_reg(state, 0x23, dib0090_read_reg(state, 0x23) & ~(1 << 14));
2073 else /* Activate DataTX in case a calibration has been done before */ if (state->config->analog_output == 0)
2074 dib0090_write_reg(state, 0x23, dib0090_read_reg(state, 0x23) | (1 << 14));
2077 if (state->calibrate & DC_CAL)
2078 return dib0090_dc_offset_calibration(state, tune_state);
2079 else if (state->calibrate & WBD_CAL) {
2080 if (state->current_rf == 0) {
2081 state->current_rf = state->fe->dtv_property_cache.frequency / 1000;
2083 return dib0090_wbd_calibration(state, tune_state);
2084 } else if (state->calibrate & TEMP_CAL)
2085 return dib0090_get_temperature(state, tune_state);
2086 else if (state->calibrate & CAPTRIM_CAL)
2087 return dib0090_captrim_search(state, tune_state);
2089 if (*tune_state == CT_TUNER_START) {
2090 /* 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 */
2091 if (state->config->use_pwm_agc && state->identity.in_soc) {
2092 tmp = dib0090_read_reg(state, 0x39);
2093 if ((tmp >> 10) & 0x1)
2094 dib0090_write_reg(state, 0x39, tmp & ~(1 << 10)); // disengage mux : en_mux_bb1 = 0
2097 state->current_band = (u8) BAND_OF_FREQUENCY(state->fe->dtv_property_cache.frequency / 1000);
2098 state->rf_request =
2099 state->fe->dtv_property_cache.frequency / 1000 + (state->current_band ==
2100 BAND_UHF ? state->config->freq_offset_khz_uhf : state->config->
2101 freq_offset_khz_vhf);
2103 /* in ISDB-T 1seg we shift tuning frequency */
2104 if ((state->fe->dtv_property_cache.delivery_system == SYS_ISDBT && state->fe->dtv_property_cache.isdbt_sb_mode == 1
2105 && state->fe->dtv_property_cache.isdbt_partial_reception == 0)) {
2106 const struct dib0090_low_if_offset_table *LUT_offset = state->config->low_if;
2107 u8 found_offset = 0;
2108 u32 margin_khz = 100;
2110 if (LUT_offset != NULL) {
2111 while (LUT_offset->RF_freq != 0xffff) {
2112 if (((state->rf_request > (LUT_offset->RF_freq - margin_khz))
2113 && (state->rf_request < (LUT_offset->RF_freq + margin_khz)))
2114 && LUT_offset->std == state->fe->dtv_property_cache.delivery_system) {
2115 state->rf_request += LUT_offset->offset_khz;
2116 found_offset = 1;
2117 break;
2119 LUT_offset++;
2123 if (found_offset == 0)
2124 state->rf_request += 400;
2126 if (state->current_rf != state->rf_request || (state->current_standard != state->fe->dtv_property_cache.delivery_system)) {
2127 state->tuner_is_tuned = 0;
2128 state->current_rf = 0;
2129 state->current_standard = 0;
2131 tune = dib0090_tuning_table;
2132 if (state->identity.p1g)
2133 tune = dib0090_p1g_tuning_table;
2135 tmp = (state->identity.version >> 5) & 0x7;
2137 if (state->identity.in_soc) {
2138 if (state->config->force_cband_input) { /* Use the CBAND input for all band */
2139 if (state->current_band & BAND_CBAND || state->current_band & BAND_FM || state->current_band & BAND_VHF
2140 || state->current_band & BAND_UHF) {
2141 state->current_band = BAND_CBAND;
2142 tune = dib0090_tuning_table_cband_7090;
2144 } else { /* Use the CBAND input for all band under UHF */
2145 if (state->current_band & BAND_CBAND || state->current_band & BAND_FM || state->current_band & BAND_VHF) {
2146 state->current_band = BAND_CBAND;
2147 tune = dib0090_tuning_table_cband_7090;
2150 } else
2151 if (tmp == 0x4 || tmp == 0x7) {
2152 /* CBAND tuner version for VHF */
2153 if (state->current_band == BAND_FM || state->current_band == BAND_CBAND || state->current_band == BAND_VHF) {
2154 state->current_band = BAND_CBAND; /* Force CBAND */
2156 tune = dib0090_tuning_table_fm_vhf_on_cband;
2157 if (state->identity.p1g)
2158 tune = dib0090_p1g_tuning_table_fm_vhf_on_cband;
2162 pll = dib0090_pll_table;
2163 if (state->identity.p1g)
2164 pll = dib0090_p1g_pll_table;
2166 /* Look for the interval */
2167 while (state->rf_request > tune->max_freq)
2168 tune++;
2169 while (state->rf_request > pll->max_freq)
2170 pll++;
2172 state->current_tune_table_index = tune;
2173 state->current_pll_table_index = pll;
2175 // select internal switch
2176 dib0090_write_reg(state, 0x0b, 0xb800 | (tune->switch_trim));
2178 // Find the VCO frequency in MHz
2179 VCOF_kHz = (pll->hfdiv * state->rf_request) * 2;
2181 FREF = state->config->io.clock_khz; // REFDIV is 1FREF Has to be as Close as possible to 10MHz
2182 if (state->config->fref_clock_ratio != 0)
2183 FREF /= state->config->fref_clock_ratio;
2185 // Determine the FB divider
2186 // The reference is 10MHz, Therefore the FBdivider is on the first digits
2187 FBDiv = (VCOF_kHz / pll->topresc / FREF);
2188 Rest = (VCOF_kHz / pll->topresc) - FBDiv * FREF; //in kHz
2190 // Avoid Spurs in the loopfilter bandwidth
2191 if (Rest < LPF)
2192 Rest = 0;
2193 else if (Rest < 2 * LPF)
2194 Rest = 2 * LPF;
2195 else if (Rest > (FREF - LPF)) {
2196 Rest = 0;
2197 FBDiv += 1;
2198 } //Go to the next FB
2199 else if (Rest > (FREF - 2 * LPF))
2200 Rest = FREF - 2 * LPF;
2201 Rest = (Rest * 6528) / (FREF / 10);
2202 state->rest = Rest;
2204 /* external loop filter, otherwise:
2205 * lo5 = (0 << 15) | (0 << 12) | (0 << 11) | (3 << 9) | (4 << 6) | (3 << 4) | 4;
2206 * lo6 = 0x0e34 */
2208 if (Rest == 0) {
2209 if (pll->vco_band)
2210 lo5 = 0x049f;
2211 //else if (state->config->analog_output)
2212 // lo5 = 0x041f;
2213 else
2214 lo5 = 0x041f;
2215 } else {
2216 if (pll->vco_band)
2217 lo5 = 0x049e;
2218 else if (state->config->analog_output)
2219 lo5 = 0x041d;
2220 else
2221 lo5 = 0x041c;
2224 if (state->identity.p1g) { /* Bias is done automatically in P1G */
2225 if (state->identity.in_soc) {
2226 if (state->identity.version == SOC_8090_P1G_11R1)
2227 lo5 = 0x46f;
2228 else
2229 lo5 = 0x42f;
2230 } else
2231 lo5 = 0x42c; //BIAS Lo set to 4 by default in case of the Captrim search does not take care of the VCO Bias
2234 lo5 |= (pll->hfdiv_code << 11) | (pll->vco_band << 7); /* bit 15 is the split to the slave, we do not do it here */
2236 //Internal loop filter set...
2237 if (!state->config->io.pll_int_loop_filt) {
2238 if (state->identity.in_soc)
2239 lo6 = 0xff98;
2240 else if (state->identity.p1g || (Rest == 0))
2241 lo6 = 0xfff8;
2242 else
2243 lo6 = 0xff28;
2244 } else
2245 lo6 = (state->config->io.pll_int_loop_filt << 3); // take the loop filter value given by the layout
2246 //dprintk("lo6 = 0x%04x", (u32)lo6);
2248 Den = 1;
2250 if (Rest > 0) {
2251 if (state->config->analog_output)
2252 lo6 |= (1 << 2) | 2; //SigmaDelta and Dither
2253 else {
2254 if (state->identity.in_soc)
2255 lo6 |= (1 << 2) | 2; //SigmaDelta and Dither
2256 else
2257 lo6 |= (1 << 2) | 2; //SigmaDelta and Dither
2259 Den = 255;
2261 // Now we have to define the Num and Denum
2262 // LO1 gets the FBdiv
2263 dib0090_write_reg(state, 0x15, (u16) FBDiv);
2264 // LO2 gets the REFDiv
2265 if (state->config->fref_clock_ratio != 0)
2266 dib0090_write_reg(state, 0x16, (Den << 8) | state->config->fref_clock_ratio);
2267 else
2268 dib0090_write_reg(state, 0x16, (Den << 8) | 1);
2269 // LO3 for the Numerator
2270 dib0090_write_reg(state, 0x17, (u16) Rest);
2271 // VCO and HF DIV
2272 dib0090_write_reg(state, 0x19, lo5);
2273 // SIGMA Delta
2274 dib0090_write_reg(state, 0x1c, lo6);
2276 // Check if the 0090 is analogged configured
2277 //Disable ADC and DigPLL =0xFF9F, 0xffbf for test purposes.
2278 //Enable The Outputs of the BB on DATA_Tx
2279 lo6 = tune->tuner_enable;
2280 if (state->config->analog_output)
2281 lo6 = (lo6 & 0xff9f) | 0x2;
2283 dib0090_write_reg(state, 0x24, lo6 | EN_LO | state->config->use_pwm_agc * EN_CRYSTAL);
2287 state->current_rf = state->rf_request;
2288 state->current_standard = state->fe->dtv_property_cache.delivery_system;
2290 ret = 20;
2291 state->calibrate = CAPTRIM_CAL; /* captrim serach now */
2294 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 */
2295 const struct dib0090_wbd_slope *wbd = state->current_wbd_table;
2297 // if(!state->identity.p1g) {
2298 while (state->current_rf / 1000 > wbd->max_freq)
2299 wbd++;
2300 // }
2302 dib0090_write_reg(state, 0x1e, 0x07ff);
2303 dprintk("Final Captrim: %d", (u32) state->fcaptrim);
2304 dprintk("HFDIV code: %d", (u32) pll->hfdiv_code);
2305 dprintk("VCO = %d", (u32) pll->vco_band);
2306 dprintk("VCOF in kHz: %d ((%d*%d) << 1))", (u32) ((pll->hfdiv * state->rf_request) * 2), (u32) pll->hfdiv, (u32) state->rf_request);
2307 dprintk("REFDIV: %d, FREF: %d", (u32) 1, (u32) state->config->io.clock_khz);
2308 dprintk("FBDIV: %d, Rest: %d", (u32) dib0090_read_reg(state, 0x15), (u32) dib0090_read_reg(state, 0x17));
2309 dprintk("Num: %d, Den: %d, SD: %d", (u32) dib0090_read_reg(state, 0x17), (u32) (dib0090_read_reg(state, 0x16) >> 8),
2310 (u32) dib0090_read_reg(state, 0x1c) & 0x3);
2312 #define WBD 0x781 /* 1 1 1 1 0000 0 0 1 */
2313 c = 4;
2314 i = 3; //wbdmux_bias
2316 if (wbd->wbd_gain != 0) //&& !state->identity.p1g)
2317 c = wbd->wbd_gain;
2319 //Store wideband mux register.
2320 state->wbdmux = (c << 13) | (i << 11) | (WBD | (state->config->use_pwm_agc << 1));
2321 dib0090_write_reg(state, 0x10, state->wbdmux);
2323 if ((tune->tuner_enable == EN_CAB) && state->identity.p1g) {
2324 dprintk("P1G : The cable band is selected and lna_tune = %d", tune->lna_tune);
2325 dib0090_write_reg(state, 0x09, tune->lna_bias);
2326 dib0090_write_reg(state, 0x0b, 0xb800 | (tune->lna_tune << 6) | (tune->switch_trim));
2327 } else
2328 dib0090_write_reg(state, 0x09, (tune->lna_tune << 5) | tune->lna_bias);
2330 dib0090_write_reg(state, 0x0c, tune->v2i);
2331 dib0090_write_reg(state, 0x0d, tune->mix);
2332 dib0090_write_reg(state, 0x0e, tune->load);
2333 *tune_state = CT_TUNER_STEP_1;
2335 } else if (*tune_state == CT_TUNER_STEP_1) {
2336 /* initialize the lt gain register */
2337 state->rf_lt_def = 0x7c00;
2338 // dib0090_write_reg(state, 0x0f, state->rf_lt_def);
2340 dib0090_set_bandwidth(state);
2341 state->tuner_is_tuned = 1;
2343 // if(!state->identity.p1g)
2344 state->calibrate |= WBD_CAL; // TODO: only do the WBD calibration for new tune
2346 state->calibrate |= TEMP_CAL; // Force the Temperature to be remesured at next TUNE.
2347 *tune_state = CT_TUNER_STOP;
2348 } else
2349 ret = FE_CALLBACK_TIME_NEVER;
2350 return ret;
2353 static int dib0090_release(struct dvb_frontend *fe)
2355 kfree(fe->tuner_priv);
2356 fe->tuner_priv = NULL;
2357 return 0;
2360 enum frontend_tune_state dib0090_get_tune_state(struct dvb_frontend *fe)
2362 struct dib0090_state *state = fe->tuner_priv;
2364 return state->tune_state;
2367 EXPORT_SYMBOL(dib0090_get_tune_state);
2369 int dib0090_set_tune_state(struct dvb_frontend *fe, enum frontend_tune_state tune_state)
2371 struct dib0090_state *state = fe->tuner_priv;
2373 state->tune_state = tune_state;
2374 return 0;
2377 EXPORT_SYMBOL(dib0090_set_tune_state);
2379 static int dib0090_get_frequency(struct dvb_frontend *fe, u32 * frequency)
2381 struct dib0090_state *state = fe->tuner_priv;
2383 *frequency = 1000 * state->current_rf;
2384 return 0;
2387 static int dib0090_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *p)
2389 struct dib0090_state *state = fe->tuner_priv;
2390 u32 ret;
2392 state->tune_state = CT_TUNER_START;
2394 do {
2395 ret = dib0090_tune(fe);
2396 if (ret != FE_CALLBACK_TIME_NEVER)
2397 msleep(ret / 10);
2398 else
2399 break;
2400 } while (state->tune_state != CT_TUNER_STOP);
2402 return 0;
2405 static const struct dvb_tuner_ops dib0090_ops = {
2406 .info = {
2407 .name = "DiBcom DiB0090",
2408 .frequency_min = 45000000,
2409 .frequency_max = 860000000,
2410 .frequency_step = 1000,
2412 .release = dib0090_release,
2414 .init = dib0090_wakeup,
2415 .sleep = dib0090_sleep,
2416 .set_params = dib0090_set_params,
2417 .get_frequency = dib0090_get_frequency,
2420 static const struct dvb_tuner_ops dib0090_fw_ops = {
2421 .info = {
2422 .name = "DiBcom DiB0090",
2423 .frequency_min = 45000000,
2424 .frequency_max = 860000000,
2425 .frequency_step = 1000,
2427 .release = dib0090_release,
2429 .init = NULL,
2430 .sleep = NULL,
2431 .set_params = NULL,
2432 .get_frequency = NULL,
2435 static const struct dib0090_wbd_slope dib0090_wbd_table_default[] = {
2436 {470, 0, 250, 0, 100, 4},
2437 {860, 51, 866, 21, 375, 4},
2438 {1700, 0, 800, 0, 850, 4}, //LBAND Predefinition , to calibrate
2439 {2900, 0, 250, 0, 100, 6}, //SBAND Predefinition , NOT tested Yet
2440 {0xFFFF, 0, 0, 0, 0, 0},
2443 struct dvb_frontend *dib0090_register(struct dvb_frontend *fe, struct i2c_adapter *i2c, const struct dib0090_config *config)
2445 struct dib0090_state *st = kzalloc(sizeof(struct dib0090_state), GFP_KERNEL);
2446 if (st == NULL)
2447 return NULL;
2449 st->config = config;
2450 st->i2c = i2c;
2451 st->fe = fe;
2452 fe->tuner_priv = st;
2454 if (config->wbd == NULL)
2455 st->current_wbd_table = dib0090_wbd_table_default;
2456 else
2457 st->current_wbd_table = config->wbd;
2459 if (dib0090_reset(fe) != 0)
2460 goto free_mem;
2462 printk(KERN_INFO "DiB0090: successfully identified\n");
2463 memcpy(&fe->ops.tuner_ops, &dib0090_ops, sizeof(struct dvb_tuner_ops));
2465 return fe;
2466 free_mem:
2467 kfree(st);
2468 fe->tuner_priv = NULL;
2469 return NULL;
2472 EXPORT_SYMBOL(dib0090_register);
2474 struct dvb_frontend *dib0090_fw_register(struct dvb_frontend *fe, struct i2c_adapter *i2c, const struct dib0090_config *config)
2476 struct dib0090_fw_state *st = kzalloc(sizeof(struct dib0090_fw_state), GFP_KERNEL);
2477 if (st == NULL)
2478 return NULL;
2480 st->config = config;
2481 st->i2c = i2c;
2482 st->fe = fe;
2483 fe->tuner_priv = st;
2485 if (dib0090_fw_reset_digital(fe, st->config) != 0)
2486 goto free_mem;
2488 dprintk("DiB0090 FW: successfully identified");
2489 memcpy(&fe->ops.tuner_ops, &dib0090_fw_ops, sizeof(struct dvb_tuner_ops));
2491 return fe;
2492 free_mem:
2493 kfree(st);
2494 fe->tuner_priv = NULL;
2495 return NULL;
2498 EXPORT_SYMBOL(dib0090_fw_register);
2500 MODULE_AUTHOR("Patrick Boettcher <pboettcher@dibcom.fr>");
2501 MODULE_AUTHOR("Olivier Grenie <olivier.grenie@dibcom.fr>");
2502 MODULE_DESCRIPTION("Driver for the DiBcom 0090 base-band RF Tuner");
2503 MODULE_LICENSE("GPL");