blob: 0e87a0bdf7ab8951718a6dcc0ffa75529c93941f [file] [log] [blame]
Olivier Grenie03245a52009-12-04 13:27:57 -03001/*
2 * Linux-DVB Driver for DiBcom's DiB0090 base-band RF Tuner.
3 *
4 * Copyright (C) 2005-9 DiBcom (http://www.dibcom.fr/)
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License as
8 * published by the Free Software Foundation; either version 2 of the
9 * License, or (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 *
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 *
21 *
22 * This code is more or less generated from another driver, please
23 * excuse some codingstyle oddities.
24 *
25 */
26
27#include <linux/kernel.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090028#include <linux/slab.h>
Olivier Grenie03245a52009-12-04 13:27:57 -030029#include <linux/i2c.h>
30
31#include "dvb_frontend.h"
32
33#include "dib0090.h"
34#include "dibx000_common.h"
35
36static int debug;
37module_param(debug, int, 0644);
38MODULE_PARM_DESC(debug, "turn on debugging (default: 0)");
39
40#define dprintk(args...) do { \
41 if (debug) { \
42 printk(KERN_DEBUG "DiB0090: "); \
43 printk(args); \
44 printk("\n"); \
45 } \
46} while (0)
47
Olivier Grenie28fafca2011-01-04 04:27:11 -030048#define CONFIG_SYS_DVBT
Olivier Grenie03245a52009-12-04 13:27:57 -030049#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
54
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
69
70#define EN_IQANA 0x0002
71#define EN_DIGCLK 0x0080 /* not in the 0x24 reg, only in 0x1b */
72#define EN_CRYSTAL 0x0002
73
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
79
Olivier Grenie28fafca2011-01-04 04:27:11 -030080/* Calibration defines */
81#define DC_CAL 0x1
82#define WBD_CAL 0x2
83#define TEMP_CAL 0x4
84#define CAPTRIM_CAL 0x8
85
86#define KROSUS_PLL_LOCKED 0x800
87#define KROSUS 0x2
88
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
95
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
102
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 */
107
Olivier Grenie03245a52009-12-04 13:27:57 -0300108#define pgm_read_word(w) (*w)
109
110struct dc_calibration;
111
112struct 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;
Olivier Grenie28fafca2011-01-04 04:27:11 -0300116 u16 lna_bias;
Olivier Grenie03245a52009-12-04 13:27:57 -0300117 u16 v2i;
118 u16 mix;
119 u16 load;
120 u16 tuner_enable;
121};
122
123struct 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;
129};
130
Olivier Grenie28fafca2011-01-04 04:27:11 -0300131struct dib0090_identity {
132 u8 version;
133 u8 product;
134 u8 p1g;
135 u8 in_soc;
136};
137
Olivier Grenie03245a52009-12-04 13:27:57 -0300138struct dib0090_state {
139 struct i2c_adapter *i2c;
140 struct dvb_frontend *fe;
141 const struct dib0090_config *config;
142
143 u8 current_band;
Olivier Grenie03245a52009-12-04 13:27:57 -0300144 enum frontend_tune_state tune_state;
145 u32 current_rf;
146
147 u16 wbd_offset;
148 s16 wbd_target; /* in dB */
149
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 */
153
154 u16 gain[2]; /* for channel monitoring */
155
156 const u16 *rf_ramp;
157 const u16 *bb_ramp;
158
159 /* for the software AGC ramps */
160 u16 bb_1_def;
161 u16 rf_lt_def;
162 u16 gain_reg[4];
163
164 /* for the captrim/dc-offset search */
165 s8 step;
166 s16 adc_diff;
167 s16 min_adc_diff;
168
169 s8 captrim;
170 s8 fcaptrim;
171
172 const struct dc_calibration *dc;
173 u16 bb6, bb7;
174
175 const struct dib0090_tuning *current_tune_table_index;
176 const struct dib0090_pll *current_pll_table_index;
177
178 u8 tuner_is_tuned;
179 u8 agc_freeze;
180
Olivier Grenie28fafca2011-01-04 04:27:11 -0300181 struct dib0090_identity identity;
182
183 u32 rf_request;
184 u8 current_standard;
185
186 u8 calibrate;
187 u32 rest;
188 u16 bias;
189 s16 temperature;
190
191 u8 wbd_calibration_gain;
192 const struct dib0090_wbd_slope *current_wbd_table;
193 u16 wbdmux;
194};
195
196struct dib0090_fw_state {
197 struct i2c_adapter *i2c;
198 struct dvb_frontend *fe;
199 struct dib0090_identity identity;
200 const struct dib0090_config *config;
Olivier Grenie03245a52009-12-04 13:27:57 -0300201};
202
203static u16 dib0090_read_reg(struct dib0090_state *state, u8 reg)
204{
205 u8 b[2];
206 struct i2c_msg msg[2] = {
Olivier Grenie28fafca2011-01-04 04:27:11 -0300207 {.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},
Olivier Grenie03245a52009-12-04 13:27:57 -0300209 };
210 if (i2c_transfer(state->i2c, msg, 2) != 2) {
211 printk(KERN_WARNING "DiB0090 I2C read failed\n");
212 return 0;
213 }
214 return (b[0] << 8) | b[1];
215}
216
217static int dib0090_write_reg(struct dib0090_state *state, u32 reg, u16 val)
218{
219 u8 b[3] = { reg & 0xff, val >> 8, val & 0xff };
Olivier Grenie28fafca2011-01-04 04:27:11 -0300220 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;
224 }
225 return 0;
226}
227
228static u16 dib0090_fw_read_reg(struct dib0090_fw_state *state, u8 reg)
229{
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;
235 }
236 return (b[0] << 8) | b[1];
237}
238
239static int dib0090_fw_write_reg(struct dib0090_fw_state *state, u8 reg, u16 val)
240{
241 u8 b[2] = { val >> 8, val & 0xff };
242 struct i2c_msg msg = {.addr = reg,.flags = 0,.buf = b,.len = 2 };
Olivier Grenie03245a52009-12-04 13:27:57 -0300243 if (i2c_transfer(state->i2c, &msg, 1) != 1) {
244 printk(KERN_WARNING "DiB0090 I2C write failed\n");
245 return -EREMOTEIO;
246 }
247 return 0;
248}
249
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
255static void dib0090_write_regs(struct dib0090_state *state, u8 r, const u16 * b, u8 c)
256{
257 do {
258 dib0090_write_reg(state, r++, *b++);
259 } while (--c);
260}
261
Olivier Grenie28fafca2011-01-04 04:27:11 -0300262static int dib0090_identify(struct dvb_frontend *fe)
Olivier Grenie03245a52009-12-04 13:27:57 -0300263{
264 struct dib0090_state *state = fe->tuner_priv;
265 u16 v;
Olivier Grenie28fafca2011-01-04 04:27:11 -0300266 struct dib0090_identity *identity = &state->identity;
Olivier Grenie03245a52009-12-04 13:27:57 -0300267
268 v = dib0090_read_reg(state, 0x1a);
269
Olivier Grenie28fafca2011-01-04 04:27:11 -0300270 identity->p1g = 0;
271 identity->in_soc = 0;
272
273 dprintk("Tuner identification (Version = 0x%04x)", v);
Olivier Grenie03245a52009-12-04 13:27:57 -0300274
275 /* without PLL lock info */
Olivier Grenie28fafca2011-01-04 04:27:11 -0300276 v &= ~KROSUS_PLL_LOCKED;
Olivier Grenie03245a52009-12-04 13:27:57 -0300277
Olivier Grenie28fafca2011-01-04 04:27:11 -0300278 identity->version = v & 0xff;
279 identity->product = (v >> 8) & 0xf;
Olivier Grenie03245a52009-12-04 13:27:57 -0300280
Olivier Grenie28fafca2011-01-04 04:27:11 -0300281 if (identity->product != KROSUS)
282 goto identification_error;
Olivier Grenie03245a52009-12-04 13:27:57 -0300283
Olivier Grenie28fafca2011-01-04 04:27:11 -0300284 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;
305 }
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;
322 }
323
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;
345 }
Olivier Grenie03245a52009-12-04 13:27:57 -0300346 }
347
Olivier Grenie28fafca2011-01-04 04:27:11 -0300348 return 0;
349
350 identification_error:
351 return -EIO;
352}
353
354static int dib0090_fw_identify(struct dvb_frontend *fe)
355{
356 struct dib0090_fw_state *state = fe->tuner_priv;
357 struct dib0090_identity *identity = &state->identity;
358
359 u16 v = dib0090_fw_read_reg(state, 0x1a);
360 identity->p1g = 0;
361 identity->in_soc = 0;
362
363 dprintk("FE: Tuner identification (Version = 0x%04x)", v);
364
365 /* without PLL lock info */
366 v &= ~KROSUS_PLL_LOCKED;
367
368 identity->version = v & 0xff;
369 identity->product = (v >> 8) & 0xf;
370
371 if (identity->product != KROSUS)
372 goto identification_error;
373
374 //From the SOC the version definition has changed
375
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;
397 }
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;
414 }
415
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;
437 }
438 }
439
440 return 0;
441
442 identification_error:
443 return -EIO;;
Olivier Grenie03245a52009-12-04 13:27:57 -0300444}
445
446static void dib0090_reset_digital(struct dvb_frontend *fe, const struct dib0090_config *cfg)
447{
448 struct dib0090_state *state = fe->tuner_priv;
Olivier Grenie28fafca2011-01-04 04:27:11 -0300449 u16 PllCfg, i, v;
Olivier Grenie03245a52009-12-04 13:27:57 -0300450
451 HARD_RESET(state);
452
Olivier Grenie28fafca2011-01-04 04:27:11 -0300453 dib0090_write_reg(state, 0x24, EN_PLL | EN_CRYSTAL);
Olivier Grenie03245a52009-12-04 13:27:57 -0300454 dib0090_write_reg(state, 0x1b, EN_DIGCLK | EN_PLL | EN_CRYSTAL); /* PLL, DIG_CLK and CRYSTAL remain */
455
Olivier Grenie28fafca2011-01-04 04:27:11 -0300456 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));
465 }
466
467 /* Read Pll current config * */
468 PllCfg = dib0090_read_reg(state, 0x21);
469
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) {
473
474 /* Set Bypass mode */
475 PllCfg |= (1 << 15);
476 dib0090_write_reg(state, 0x21, PllCfg);
477
478 /* Set Reset Pll */
479 PllCfg &= ~(1 << 13);
480 dib0090_write_reg(state, 0x21, PllCfg);
481
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);
485
486 /* Remove Reset Pll */
487 PllCfg |= (1 << 13);
488 dib0090_write_reg(state, 0x21, PllCfg);
489
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);
497
498 if (i == 0) {
499 dprintk("Pll: Unable to lock Pll");
500 return;
501 }
502
503 /* Finally Remove Bypass mode */
504 PllCfg &= ~(1 << 15);
505 dib0090_write_reg(state, 0x21, PllCfg);
506 }
507
508 if (cfg->io.pll_bypass) {
509 PllCfg |= (cfg->io.pll_bypass << 15);
510 dib0090_write_reg(state, 0x21, PllCfg);
511 }
512}
513
514static int dib0090_fw_reset_digital(struct dvb_frontend *fe, const struct dib0090_config *cfg)
515{
516 struct dib0090_fw_state *state = fe->tuner_priv;
517 u16 PllCfg;
518 u16 v;
519 int i;
520
521 dprintk("fw reset digital");
522 HARD_RESET(state);
523
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 */
526
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);
529
530 v = (0 << 15) | ((!cfg->analog_output) << 14) | (1 << 9) | (0 << 8) | (cfg->clkouttobamse << 4) | (0 << 2) | (0);
Olivier Grenie03245a52009-12-04 13:27:57 -0300531 if (cfg->clkoutdrive != 0)
Olivier Grenie28fafca2011-01-04 04:27:11 -0300532 v |= cfg->clkoutdrive << 5;
Olivier Grenie03245a52009-12-04 13:27:57 -0300533 else
Olivier Grenie28fafca2011-01-04 04:27:11 -0300534 v |= 7 << 5;
Olivier Grenie03245a52009-12-04 13:27:57 -0300535
Olivier Grenie28fafca2011-01-04 04:27:11 -0300536 v |= 2 << 10;
537 dib0090_fw_write_reg(state, 0x23, v);
Olivier Grenie03245a52009-12-04 13:27:57 -0300538
Olivier Grenie28fafca2011-01-04 04:27:11 -0300539 /* Read Pll current config * */
540 PllCfg = dib0090_fw_read_reg(state, 0x21);
541
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) {
544
545 /* Set Bypass mode */
546 PllCfg |= (1 << 15);
547 dib0090_fw_write_reg(state, 0x21, PllCfg);
548
549 /* Set Reset Pll */
550 PllCfg &= ~(1 << 13);
551 dib0090_fw_write_reg(state, 0x21, PllCfg);
552
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);
556
557 /* Remove Reset Pll */
558 PllCfg |= (1 << 13);
559 dib0090_fw_write_reg(state, 0x21, PllCfg);
560
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);
568
569 if (i == 0) {
570 dprintk("Pll: Unable to lock Pll");
571 return -EIO;
572 }
573
574 /* Finally Remove Bypass mode */
575 PllCfg &= ~(1 << 15);
576 dib0090_fw_write_reg(state, 0x21, PllCfg);
577 }
578
579 if (cfg->io.pll_bypass) {
580 PllCfg |= (cfg->io.pll_bypass << 15);
581 dib0090_fw_write_reg(state, 0x21, PllCfg);
582 }
583
584 return dib0090_fw_identify(fe);
Olivier Grenie03245a52009-12-04 13:27:57 -0300585}
586
587static int dib0090_wakeup(struct dvb_frontend *fe)
588{
589 struct dib0090_state *state = fe->tuner_priv;
590 if (state->config->sleep)
591 state->config->sleep(fe, 0);
Olivier Grenie28fafca2011-01-04 04:27:11 -0300592
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));
Olivier Grenie03245a52009-12-04 13:27:57 -0300595 return 0;
596}
597
598static int dib0090_sleep(struct dvb_frontend *fe)
599{
600 struct dib0090_state *state = fe->tuner_priv;
601 if (state->config->sleep)
602 state->config->sleep(fe, 1);
603 return 0;
604}
605
Márton Németh43e3e6d2010-01-16 14:35:03 -0300606void dib0090_dcc_freq(struct dvb_frontend *fe, u8 fast)
Olivier Grenie03245a52009-12-04 13:27:57 -0300607{
608 struct dib0090_state *state = fe->tuner_priv;
609 if (fast)
Olivier Grenie9c783032009-12-07 07:49:40 -0300610 dib0090_write_reg(state, 0x04, 0);
Olivier Grenie03245a52009-12-04 13:27:57 -0300611 else
Olivier Grenie9c783032009-12-07 07:49:40 -0300612 dib0090_write_reg(state, 0x04, 1);
Olivier Grenie03245a52009-12-04 13:27:57 -0300613}
Olivier Grenie28fafca2011-01-04 04:27:11 -0300614
Olivier Grenie03245a52009-12-04 13:27:57 -0300615EXPORT_SYMBOL(dib0090_dcc_freq);
Olivier Grenie9c783032009-12-07 07:49:40 -0300616
Olivier Grenie28fafca2011-01-04 04:27:11 -0300617static 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 */
625};
626
627static 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 */
639};
640
641static 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 */
653};
654
655static 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 */
667};
668
669static 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 */
681};
682
Olivier Grenie03245a52009-12-04 13:27:57 -0300683static 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 */
695};
696
697static 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 */
704};
705
706static 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 */
713};
714
Olivier Grenie28fafca2011-01-04 04:27:11 -0300715static const u16 rf_ramp_cband_broadmatching[] = /* for p1G only */
716{
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 */
723};
724
Olivier Grenie03245a52009-12-04 13:27:57 -0300725static 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 */
732};
733
734static 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 */
746};
747
748static 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 */
760};
761
762static 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 */
766};
767
768static 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 */
776};
777
778struct slope {
Olivier Grenie28fafca2011-01-04 04:27:11 -0300779 s16 range;
780 s16 slope;
Olivier Grenie03245a52009-12-04 13:27:57 -0300781};
782static u16 slopes_to_scale(const struct slope *slopes, u8 num, s16 val)
783{
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;
794 }
795 return ret;
796}
797
798static 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 */
802};
803
804static s16 dib0090_wbd_to_db(struct dib0090_state *state, u16 wbd)
805{
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);
813}
814
815static void dib0090_wbd_target(struct dib0090_state *state, u32 rf)
816{
817 u16 offset = 250;
818
819 /* TODO : DAB digital N+/-1 interferer perfs : offset = 10 */
820
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
829
830 state->wbd_target = dib0090_wbd_to_db(state, state->wbd_offset + offset);
831 dprintk("wbd-target: %d dB", (u32) state->wbd_target);
832}
833
834static const int gain_reg_addr[4] = {
835 0x08, 0x0a, 0x0f, 0x01
836};
837
838static void dib0090_gain_apply(struct dib0090_state *state, s16 gain_delta, s16 top_delta, u8 force)
839{
840 u16 rf, bb, ref;
841 u16 i, v, gain_reg[4] = { 0 }, gain;
842 const u16 *g;
843
844 if (top_delta < -511)
845 top_delta = -511;
846 if (top_delta > 511)
847 top_delta = 511;
848
849 if (force) {
850 top_delta *= (1 << WBD_ALPHA);
851 gain_delta *= (1 << GAIN_ALPHA);
852 }
853
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;
858
859 if (state->rf_gain_limit < 0) /*underflow */
860 state->rf_gain_limit = 0;
861
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;
871
872 /* now split total gain to rf and bb gain */
873 gain = state->current_gain >> GAIN_ALPHA;
874
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;
884 }
885
886 state->gain[0] = rf;
887 state->gain[1] = bb;
888
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];
900
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;
915
916 g += 3; /* go to next gain bloc */
917
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;
922 }
923 }
924 gain_reg[3] |= state->bb_1_def;
925 gain_reg[3] |= ((bb % 10) * 100) / 125;
926
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
931
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);
938 }
939 }
940}
941
942static void dib0090_set_boost(struct dib0090_state *state, int onoff)
943{
944 state->bb_1_def &= 0xdfff;
945 state->bb_1_def |= onoff << 13;
946}
947
948static void dib0090_set_rframp(struct dib0090_state *state, const u16 * cfg)
949{
950 state->rf_ramp = cfg;
951}
952
953static void dib0090_set_rframp_pwm(struct dib0090_state *state, const u16 * cfg)
954{
955 state->rf_ramp = cfg;
956
957 dib0090_write_reg(state, 0x2a, 0xffff);
958
959 dprintk("total RF gain: %ddB, step: %d", (u32) cfg[0], dib0090_read_reg(state, 0x2a));
960
961 dib0090_write_regs(state, 0x2c, cfg + 3, 6);
962 dib0090_write_regs(state, 0x3e, cfg + 9, 2);
963}
964
965static void dib0090_set_bbramp(struct dib0090_state *state, const u16 * cfg)
966{
967 state->bb_ramp = cfg;
968 dib0090_set_boost(state, cfg[0] > 500); /* we want the boost if the gain is higher that 50dB */
969}
970
971static void dib0090_set_bbramp_pwm(struct dib0090_state *state, const u16 * cfg)
972{
973 state->bb_ramp = cfg;
974
975 dib0090_set_boost(state, cfg[0] > 500); /* we want the boost if the gain is higher that 50dB */
976
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);
980}
981
982void dib0090_pwm_gain_reset(struct dvb_frontend *fe)
983{
984 struct dib0090_state *state = fe->tuner_priv;
985 /* reset the AGC */
986
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) {
Olivier Grenie28fafca2011-01-04 04:27:11 -0300996 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);
1005 }
Olivier Grenie03245a52009-12-04 13:27:57 -03001006 } else
1007#endif
1008#ifdef CONFIG_BAND_VHF
1009 if (state->current_band == BAND_VHF) {
Olivier Grenie28fafca2011-01-04 04:27:11 -03001010 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);
1016 }
Olivier Grenie03245a52009-12-04 13:27:57 -03001017 } else
1018#endif
1019 {
Olivier Grenie28fafca2011-01-04 04:27:11 -03001020 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);
1029 }
Olivier Grenie03245a52009-12-04 13:27:57 -03001030 }
1031
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));
1036
Olivier Grenie28fafca2011-01-04 04:27:11 -03001037 dib0090_write_reg(state, 0x04, 0x01);
Olivier Grenie9c783032009-12-07 07:49:40 -03001038 dib0090_write_reg(state, 0x39, (1 << 10));
Olivier Grenie03245a52009-12-04 13:27:57 -03001039 }
1040}
Olivier Grenie28fafca2011-01-04 04:27:11 -03001041
Olivier Grenie03245a52009-12-04 13:27:57 -03001042EXPORT_SYMBOL(dib0090_pwm_gain_reset);
Olivier Grenie9c783032009-12-07 07:49:40 -03001043
Olivier Grenie28fafca2011-01-04 04:27:11 -03001044static u32 dib0090_get_slow_adc_val(struct dib0090_state *state)
1045{
1046 u16 adc_val = dib0090_read_reg(state, 0x1d);
1047 if (state->identity.in_soc) {
1048 adc_val >>= 2;
1049 }
1050 return adc_val;
1051}
1052
Olivier Grenie03245a52009-12-04 13:27:57 -03001053int dib0090_gain_control(struct dvb_frontend *fe)
1054{
1055 struct dib0090_state *state = fe->tuner_priv;
1056 enum frontend_tune_state *tune_state = &state->tune_state;
1057 int ret = 10;
1058
1059 u16 wbd_val = 0;
1060 u8 apply_gain_immediatly = 1;
1061 s16 wbd_error = 0, adc_error = 0;
1062
1063 if (*tune_state == CT_AGC_START) {
1064 state->agc_freeze = 0;
1065 dib0090_write_reg(state, 0x04, 0x0);
1066
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
Olivier Grenie28fafca2011-01-04 04:27:11 -03001074 if (state->current_band == BAND_VHF && !state->identity.p1g) {
Olivier Grenie03245a52009-12-04 13:27:57 -03001075 dib0090_set_rframp(state, rf_ramp_vhf);
1076 dib0090_set_bbramp(state, bb_ramp_boost);
1077 } else
1078#endif
1079#ifdef CONFIG_BAND_CBAND
Olivier Grenie28fafca2011-01-04 04:27:11 -03001080 if (state->current_band == BAND_CBAND && !state->identity.p1g) {
Olivier Grenie03245a52009-12-04 13:27:57 -03001081 dib0090_set_rframp(state, rf_ramp_cband);
1082 dib0090_set_bbramp(state, bb_ramp_boost);
1083 } else
1084#endif
Olivier Grenie28fafca2011-01-04 04:27:11 -03001085 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 {
Olivier Grenie03245a52009-12-04 13:27:57 -03001089 dib0090_set_rframp(state, rf_ramp_uhf);
1090 dib0090_set_bbramp(state, bb_ramp_boost);
1091 }
1092
1093 dib0090_write_reg(state, 0x32, 0);
1094 dib0090_write_reg(state, 0x39, 0);
1095
1096 dib0090_wbd_target(state, state->current_rf);
1097
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;
1100
1101 *tune_state = CT_AGC_STEP_0;
1102 } else if (!state->agc_freeze) {
Olivier Grenie28fafca2011-01-04 04:27:11 -03001103 s16 wbd = 0, i, cnt;
Olivier Grenie03245a52009-12-04 13:27:57 -03001104
1105 int adc;
Olivier Grenie28fafca2011-01-04 04:27:11 -03001106 wbd_val = dib0090_get_slow_adc_val(state);
Olivier Grenie03245a52009-12-04 13:27:57 -03001107
Olivier Grenie28fafca2011-01-04 04:27:11 -03001108 if (*tune_state == CT_AGC_STEP_0)
1109 cnt = 5;
1110 else
1111 cnt = 1;
1112
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);
1116 }
1117 wbd /= cnt;
Olivier Grenie03245a52009-12-04 13:27:57 -03001118 wbd_error = state->wbd_target - wbd;
1119
1120 if (*tune_state == CT_AGC_STEP_0) {
Olivier Grenie28fafca2011-01-04 04:27:11 -03001121 if (wbd_error < 0 && state->rf_gain_limit > 0 && !state->identity.p1g) {
Olivier Grenie03245a52009-12-04 13:27:57 -03001122#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 */
1128 }
1129#endif
1130 } else {
1131 state->agc_step = 0;
1132 *tune_state = CT_AGC_STEP_1;
1133 }
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] */
1138
1139 adc_error = (s16) (((s32) ADC_TARGET) - adc);
1140#ifdef CONFIG_STANDARD_DAB
1141 if (state->fe->dtv_property_cache.delivery_system == STANDARD_DAB)
Olivier Grenie28fafca2011-01-04 04:27:11 -03001142 adc_error -= 10;
Olivier Grenie03245a52009-12-04 13:27:57 -03001143#endif
1144#ifdef CONFIG_STANDARD_DVBT
1145 if (state->fe->dtv_property_cache.delivery_system == STANDARD_DVBT &&
Olivier Grenie28fafca2011-01-04 04:27:11 -03001146 (state->fe->dtv_property_cache.modulation == QAM_64 || state->fe->dtv_property_cache.modulation == QAM_16))
Olivier Grenie03245a52009-12-04 13:27:57 -03001147 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 >
Olivier Grenie28fafca2011-01-04 04:27:11 -03001151 0)
1152 &&
1153 ((state->fe->dtv_property_cache.layer[0].modulation ==
1154 QAM_64)
1155 || (state->fe->dtv_property_cache.
1156 layer[0].modulation == QAM_16)))
1157 ||
1158 ((state->fe->dtv_property_cache.layer[1].segment_count >
1159 0)
1160 &&
1161 ((state->fe->dtv_property_cache.layer[1].modulation ==
1162 QAM_64)
1163 || (state->fe->dtv_property_cache.
1164 layer[1].modulation == QAM_16)))
1165 ||
1166 ((state->fe->dtv_property_cache.layer[2].segment_count >
1167 0)
1168 &&
1169 ((state->fe->dtv_property_cache.layer[2].modulation ==
1170 QAM_64)
1171 || (state->fe->dtv_property_cache.
1172 layer[2].modulation == QAM_16)))
1173 )
1174 )
Olivier Grenie03245a52009-12-04 13:27:57 -03001175 adc_error += 60;
1176#endif
1177
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) {
1180
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
1187 {
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 */
1190 }
1191
1192 *tune_state = CT_AGC_STOP;
1193 }
1194 } else {
1195 /* everything higher than or equal to CT_AGC_STOP means tracking */
1196 ret = 100; /* 10ms interval */
1197 apply_gain_immediatly = 0;
1198 }
1199 }
1200#ifdef DEBUG_AGC
1201 dprintk
Olivier Grenie28fafca2011-01-04 04:27:11 -03001202 ("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));
Olivier Grenie03245a52009-12-04 13:27:57 -03001205#endif
1206 }
1207
1208 /* apply gain */
1209 if (!state->agc_freeze)
1210 dib0090_gain_apply(state, adc_error, wbd_error, apply_gain_immediatly);
1211 return ret;
1212}
Olivier Grenie28fafca2011-01-04 04:27:11 -03001213
Olivier Grenie03245a52009-12-04 13:27:57 -03001214EXPORT_SYMBOL(dib0090_gain_control);
Olivier Grenie9c783032009-12-07 07:49:40 -03001215
Olivier Grenie03245a52009-12-04 13:27:57 -03001216void dib0090_get_current_gain(struct dvb_frontend *fe, u16 * rf, u16 * bb, u16 * rf_gain_limit, u16 * rflt)
1217{
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;
1227}
Olivier Grenie28fafca2011-01-04 04:27:11 -03001228
Olivier Grenie03245a52009-12-04 13:27:57 -03001229EXPORT_SYMBOL(dib0090_get_current_gain);
Olivier Grenie9c783032009-12-07 07:49:40 -03001230
Olivier Grenie28fafca2011-01-04 04:27:11 -03001231u16 dib0090_get_wbd_offset(struct dvb_frontend *fe)
Olivier Grenie03245a52009-12-04 13:27:57 -03001232{
Olivier Grenie28fafca2011-01-04 04:27:11 -03001233 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;
1238
1239 while (f_MHz > wbd->max_freq)
1240 wbd++;
1241
1242 dprintk("using wbd-table-entry with max freq %d", wbd->max_freq);
1243
1244 if (current_temp < 0)
1245 current_temp = 0;
1246 if (current_temp > 128)
1247 current_temp = 128;
1248
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
1255
1256 dib0090_write_reg(state, 0x10, state->wbdmux);
1257
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);
1261
1262 // Iet assumes that thot-tcold = 130 equiv 128, current temperature ref is -30deg
1263
1264 wbd_tcold += ((wbd_thot - wbd_tcold) * current_temp) >> 7;
1265
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);
1271
1272 return state->wbd_offset + wbd_tcold;
Olivier Grenie03245a52009-12-04 13:27:57 -03001273}
Olivier Grenie28fafca2011-01-04 04:27:11 -03001274
Olivier Grenie03245a52009-12-04 13:27:57 -03001275EXPORT_SYMBOL(dib0090_get_wbd_offset);
Olivier Grenie9c783032009-12-07 07:49:40 -03001276
Olivier Grenie03245a52009-12-04 13:27:57 -03001277static const u16 dib0090_defaults[] = {
1278
1279 25, 0x01,
1280 0x0000,
1281 0x99a0,
1282 0x6008,
1283 0x0000,
Olivier Grenie28fafca2011-01-04 04:27:11 -03001284 0x8bcb,
Olivier Grenie03245a52009-12-04 13:27:57 -03001285 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,
1305
1306 1, 0x1c,
1307 0xff2d,
1308
1309 1, 0x39,
1310 0x0000,
1311
Olivier Grenie03245a52009-12-04 13:27:57 -03001312 2, 0x1e,
1313 0x07FF,
1314 0x0007,
1315
1316 1, 0x24,
1317 EN_UHF | EN_CRYSTAL,
1318
1319 2, 0x3c,
1320 0x3ff,
1321 0x111,
1322 0
1323};
1324
Olivier Grenie28fafca2011-01-04 04:27:11 -03001325static const u16 dib0090_p1g_additionnal_defaults[] = {
1326 // additionnal INITIALISATION for p1g to be written after dib0090_defaults
1327 1, 0x05,
1328 0xabcd,
1329
1330 1, 0x11,
1331 0x00b4,
1332
1333 1, 0x1c,
1334 0xfffd,
1335
1336 1, 0x40,
1337 0x108,
1338 0
1339};
1340
1341static void dib0090_set_default_config(struct dib0090_state *state, const u16 * n)
Olivier Grenie03245a52009-12-04 13:27:57 -03001342{
Olivier Grenie28fafca2011-01-04 04:27:11 -03001343 u16 l, r;
Olivier Grenie03245a52009-12-04 13:27:57 -03001344
Olivier Grenie03245a52009-12-04 13:27:57 -03001345 l = pgm_read_word(n++);
1346 while (l) {
1347 r = pgm_read_word(n++);
1348 do {
Olivier Grenie03245a52009-12-04 13:27:57 -03001349 dib0090_write_reg(state, r, pgm_read_word(n++));
1350 r++;
1351 } while (--l);
1352 l = pgm_read_word(n++);
1353 }
Olivier Grenie28fafca2011-01-04 04:27:11 -03001354}
1355
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
1362
1363void dib0090_set_EFUSE(struct dib0090_state *state)
1364{
1365 u8 c,h,n;
1366 u16 e2,e4;
1367 u16 cal;
1368
1369 e2=dib0090_read_reg(state,0x26);
1370 e4=dib0090_read_reg(state,0x28);
1371
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
1374
1375 dib0090_write_reg(state,0x22,0x10); //Start the Calib
1376 cal = (dib0090_read_reg(state,0x22)>>6) & 0x3ff;
1377
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);
1382 }
1383
1384 if (e2!=e4) {
1385 e2 &= e4; /* Remove the redundancy */
1386 }
1387
1388 if (e2 != 0xffff) {
1389 c = e2 & 0x3f;
1390 n = (e2 >> 12) & 0xf;
1391 h= (e2 >> 6) & 0x3f;
1392
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;
1399
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 */
1403 }
1404}
1405
1406static int dib0090_reset(struct dvb_frontend *fe)
1407{
1408 struct dib0090_state *state = fe->tuner_priv;
1409
1410 dib0090_reset_digital(fe, state->config);
1411 if (dib0090_identify(fe) < 0)
1412 return -EIO;
1413
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
1418
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));
1424 }
1425
1426 dib0090_set_default_config(state, dib0090_defaults);
1427
1428 if (state->identity.in_soc)
1429 dib0090_write_reg(state, 0x18, 0x2910); /* charge pump current = 0 */
1430
1431 if (state->identity.p1g)
1432 dib0090_set_default_config(state, dib0090_p1g_additionnal_defaults);
1433
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);
Olivier Grenie03245a52009-12-04 13:27:57 -03001436
1437 /* Congigure in function of the crystal */
1438 if (state->config->io.clock_khz >= 24000)
Olivier Grenie28fafca2011-01-04 04:27:11 -03001439 dib0090_write_reg(state, 0x14, 1);
Olivier Grenie03245a52009-12-04 13:27:57 -03001440 else
Olivier Grenie28fafca2011-01-04 04:27:11 -03001441 dib0090_write_reg(state, 0x14, 2);
Olivier Grenie03245a52009-12-04 13:27:57 -03001442 dprintk("Pll lock : %d", (dib0090_read_reg(state, 0x1a) >> 11) & 0x1);
1443
Olivier Grenie28fafca2011-01-04 04:27:11 -03001444 state->calibrate = DC_CAL | WBD_CAL | TEMP_CAL; /* enable iq-offset-calibration and wbd-calibration when tuning next time */
Olivier Grenie03245a52009-12-04 13:27:57 -03001445
1446 return 0;
1447}
1448
Olivier Grenie9c783032009-12-07 07:49:40 -03001449#define steps(u) (((u) > 15) ? ((u)-16) : (u))
Olivier Grenie03245a52009-12-04 13:27:57 -03001450#define INTERN_WAIT 10
1451static int dib0090_get_offset(struct dib0090_state *state, enum frontend_tune_state *tune_state)
1452{
1453 int ret = INTERN_WAIT * 10;
1454
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;
1461
1462 case CT_TUNER_STEP_3:
1463 state->adc_diff = dib0090_read_reg(state, 0x1d);
1464
1465 /* Turns to negative */
1466 dib0090_write_reg(state, 0x1f, 0x4);
1467 *tune_state = CT_TUNER_STEP_4;
1468 break;
1469
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;
1475
1476 default:
1477 break;
1478 }
1479
1480 return ret;
1481}
1482
1483struct dc_calibration {
Olivier Grenie28fafca2011-01-04 04:27:11 -03001484 u8 addr;
1485 u8 offset;
1486 u8 pga:1;
1487 u16 bb1;
1488 u8 i:1;
Olivier Grenie03245a52009-12-04 13:27:57 -03001489};
1490
1491static 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},
1499};
1500
Olivier Grenie28fafca2011-01-04 04:27:11 -03001501static 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},
1510};
1511
Olivier Grenie03245a52009-12-04 13:27:57 -03001512static void dib0090_set_trim(struct dib0090_state *state)
1513{
1514 u16 *val;
1515
1516 if (state->dc->addr == 0x07)
1517 val = &state->bb7;
1518 else
1519 val = &state->bb6;
1520
1521 *val &= ~(0x1f << state->dc->offset);
1522 *val |= state->step << state->dc->offset;
1523
1524 dib0090_write_reg(state, state->dc->addr, *val);
1525}
1526
1527static int dib0090_dc_offset_calibration(struct dib0090_state *state, enum frontend_tune_state *tune_state)
1528{
1529 int ret = 0;
Olivier Grenie28fafca2011-01-04 04:27:11 -03001530 u16 reg;
Olivier Grenie03245a52009-12-04 13:27:57 -03001531
1532 switch (*tune_state) {
Olivier Grenie03245a52009-12-04 13:27:57 -03001533 case CT_TUNER_START:
Olivier Grenie28fafca2011-01-04 04:27:11 -03001534 dprintk("Start DC offset calibration");
Olivier Grenie03245a52009-12-04 13:27:57 -03001535
1536 /* force vcm2 = 0.8V */
1537 state->bb6 = 0;
1538 state->bb7 = 0x040d;
1539
Olivier Grenie28fafca2011-01-04 04:27:11 -03001540 /* 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);
1543
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
1547
Olivier Grenie03245a52009-12-04 13:27:57 -03001548 state->dc = dc_table;
1549
Olivier Grenie28fafca2011-01-04 04:27:11 -03001550 if (state->identity.p1g)
1551 state->dc = dc_p1g_table;
Olivier Grenie03245a52009-12-04 13:27:57 -03001552 *tune_state = CT_TUNER_STEP_0;
1553
1554 /* fall through */
1555
1556 case CT_TUNER_STEP_0:
Olivier Grenie28fafca2011-01-04 04:27:11 -03001557 dprintk("Sart/continue DC calibration for %s path", (state->dc->i == 1) ? "I" : "Q");
Olivier Grenie03245a52009-12-04 13:27:57 -03001558 dib0090_write_reg(state, 0x01, state->dc->bb1);
1559 dib0090_write_reg(state, 0x07, state->bb7 | (state->dc->i << 7));
1560
1561 state->step = 0;
Olivier Grenie03245a52009-12-04 13:27:57 -03001562 state->min_adc_diff = 1023;
Olivier Grenie03245a52009-12-04 13:27:57 -03001563 *tune_state = CT_TUNER_STEP_1;
1564 ret = 50;
1565 break;
1566
1567 case CT_TUNER_STEP_1:
1568 dib0090_set_trim(state);
Olivier Grenie03245a52009-12-04 13:27:57 -03001569 *tune_state = CT_TUNER_STEP_2;
1570 break;
1571
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;
1577
1578 case CT_TUNER_STEP_5: /* found an offset */
Olivier Grenie28fafca2011-01-04 04:27:11 -03001579 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");
1583 }
1584
1585 dprintk("adc_diff = %d, min_adc_diff = %d current_step = %d", state->adc_diff, state->min_adc_diff, state->step);
Olivier Grenie03245a52009-12-04 13:27:57 -03001586
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;
1593 }
1594
Olivier Grenie28fafca2011-01-04 04:27:11 -03001595 /* 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 */
Olivier Grenie03245a52009-12-04 13:27:57 -03001598 state->step++;
Olivier Grenie28fafca2011-01-04 04:27:11 -03001599 state->min_adc_diff = state->adc_diff; //min is used as N-1
Olivier Grenie03245a52009-12-04 13:27:57 -03001600 *tune_state = CT_TUNER_STEP_1;
1601 } else {
Olivier Grenie03245a52009-12-04 13:27:57 -03001602 /* the minimum was what we have seen in the step before */
Olivier Grenie28fafca2011-01-04 04:27:11 -03001603 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--;
1606 }
Olivier Grenie03245a52009-12-04 13:27:57 -03001607
Olivier Grenie28fafca2011-01-04 04:27:11 -03001608 dib0090_set_trim(state);
1609 dprintk("BB Offset Cal, BBreg=%hd,Offset=%hd,Value Set=%hd", state->dc->addr, state->adc_diff, state->step);
Olivier Grenie03245a52009-12-04 13:27:57 -03001610
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;
1616
1617 }
1618 break;
1619
1620 case CT_TUNER_STEP_6:
Olivier Grenie28fafca2011-01-04 04:27:11 -03001621 dib0090_write_reg(state, 0x07, state->bb7 & ~0x0008); //Force the test bus to be off
Olivier Grenie03245a52009-12-04 13:27:57 -03001622 dib0090_write_reg(state, 0x1f, 0x7);
1623 *tune_state = CT_TUNER_START; /* reset done -> real tuning can now begin */
Olivier Grenie28fafca2011-01-04 04:27:11 -03001624 state->calibrate &= ~DC_CAL;
Olivier Grenie03245a52009-12-04 13:27:57 -03001625 default:
1626 break;
1627 }
1628 return ret;
1629}
1630
1631static int dib0090_wbd_calibration(struct dib0090_state *state, enum frontend_tune_state *tune_state)
1632{
Olivier Grenie28fafca2011-01-04 04:27:11 -03001633 u8 wbd_gain;
1634 const struct dib0090_wbd_slope *wbd = state->current_wbd_table;
1635
Olivier Grenie03245a52009-12-04 13:27:57 -03001636 switch (*tune_state) {
1637 case CT_TUNER_START:
Olivier Grenie28fafca2011-01-04 04:27:11 -03001638 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
1648 }
Olivier Grenie03245a52009-12-04 13:27:57 -03001649
Olivier Grenie28fafca2011-01-04 04:27:11 -03001650 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;
1654 }
1655
1656 dib0090_write_reg(state, 0x10, 0x1b81 | (1 << 10) | (wbd_gain << 13) | (1 << 3)); // Force: WBD enable,gain to 4, mux to WBD
1657
1658 dib0090_write_reg(state, 0x24, ((EN_UHF & 0x0fff) | (1 << 1))); //Discard all LNA but crystal !!!
Olivier Grenie03245a52009-12-04 13:27:57 -03001659 *tune_state = CT_TUNER_STEP_0;
Olivier Grenie28fafca2011-01-04 04:27:11 -03001660 state->wbd_calibration_gain = wbd_gain;
Olivier Grenie03245a52009-12-04 13:27:57 -03001661 return 90; /* wait for the WBDMUX to switch and for the ADC to sample */
Olivier Grenie03245a52009-12-04 13:27:57 -03001662
Olivier Grenie28fafca2011-01-04 04:27:11 -03001663 case CT_TUNER_STEP_0:
1664 state->wbd_offset = dib0090_get_slow_adc_val(state);
1665 dprintk("WBD calibration offset = %d", state->wbd_offset);
Olivier Grenie03245a52009-12-04 13:27:57 -03001666 *tune_state = CT_TUNER_START; /* reset done -> real tuning can now begin */
Olivier Grenie28fafca2011-01-04 04:27:11 -03001667 state->calibrate &= ~WBD_CAL;
Olivier Grenie03245a52009-12-04 13:27:57 -03001668 break;
Olivier Grenie28fafca2011-01-04 04:27:11 -03001669
Olivier Grenie03245a52009-12-04 13:27:57 -03001670 default:
1671 break;
1672 }
1673 return 0;
1674}
1675
1676static void dib0090_set_bandwidth(struct dib0090_state *state)
1677{
1678 u16 tmp;
1679
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);
1688
1689 state->bb_1_def &= 0x3fff;
1690 state->bb_1_def |= tmp;
1691
1692 dib0090_write_reg(state, 0x01, state->bb_1_def); /* be sure that we have the right bb-filter */
Olivier Grenie28fafca2011-01-04 04:27:11 -03001693
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 */
1701 }
Olivier Grenie03245a52009-12-04 13:27:57 -03001702}
1703
1704static 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
1733};
1734
1735static const struct dib0090_tuning dib0090_tuning_table_fm_vhf_on_cband[] = {
1736
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
1759};
1760
1761static const struct dib0090_tuning dib0090_tuning_table[] = {
1762
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
1788};
1789
Olivier Grenie28fafca2011-01-04 04:27:11 -03001790static 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
1818};
1819
1820static 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
1849};
1850
1851static 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
1875};
1876
1877static 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
1886};
1887
1888static int dib0090_captrim_search(struct dib0090_state *state, enum frontend_tune_state *tune_state)
1889{
1890 int ret = 0;
1891 u16 lo4 = 0xe900;
1892
1893 s16 adc_target;
1894 u16 adc;
1895 s8 step_sign;
1896 u8 force_soft_search = 0;
1897
1898 if (state->identity.version == SOC_8090_P1G_11R1 || state->identity.version == SOC_8090_P1G_21R1)
1899 force_soft_search = 1;
1900
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);
1905
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;
1910
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;
1917 }
1918 }
1919 state->adc_diff = 3000; // start with a unreachable high number : only set for KROSUS < P1G */
1920 *tune_state = CT_TUNER_STEP_0;
1921
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;
1926
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);
1934
1935 if (state->identity.in_soc)
1936 ret = 25;
1937 }
1938 *tune_state = CT_TUNER_STEP_1;
1939
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);
1944
1945 state->fcaptrim = dib0090_read_reg(state, 0x18) & 0x7F;
1946 dprintk("***Final Captrim= 0x%x", state->fcaptrim);
1947 *tune_state = CT_TUNER_STEP_3;
1948
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);
1953
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;
1958
1959 if (adc >= adc_target) {
1960 adc -= adc_target;
1961 step_sign = -1;
1962 } else {
1963 adc = adc_target - adc;
1964 step_sign = 1;
1965 }
1966
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;
1974 }
1975
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;
1981
1982 ret = 25; //LOLO changed from 15
1983 }
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);
1987
1988 *tune_state = CT_TUNER_STEP_3;
1989
1990 } else if (*tune_state == CT_TUNER_STEP_3) {
1991 state->calibrate &= ~CAPTRIM_CAL;
1992 *tune_state = CT_TUNER_STEP_0;
1993 }
1994
1995 return ret;
1996}
1997
1998static int dib0090_get_temperature(struct dib0090_state *state, enum frontend_tune_state *tune_state)
1999{
2000 int ret = 15;
2001 s16 val;
2002
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
2008
2009 state->bias = dib0090_read_reg(state, 0x13);
2010 dib0090_write_reg(state, 0x13, state->bias | (0x3 << 8)); //Move to the Ref
2011
2012 *tune_state = CT_TUNER_STEP_0;
2013 /* wait for the WBDMUX to switch and for the ADC to sample */
2014 break;
2015
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;
2021
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
2025
2026 dprintk("temperature: %d C", state->temperature - 30);
2027
2028 *tune_state = CT_TUNER_STEP_2;
2029 break;
2030
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 */
2035
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
2040
2041 break;
2042
2043 default:
2044 ret = 0;
2045 break;
2046 }
2047 return ret;
2048}
2049
Olivier Grenie03245a52009-12-04 13:27:57 -03002050#define WBD 0x781 /* 1 1 1 1 0000 0 0 1 */
2051static int dib0090_tune(struct dvb_frontend *fe)
2052{
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;
2057
Olivier Grenie28fafca2011-01-04 04:27:11 -03002058 u16 lo5, lo6, Den, tmp;
Olivier Grenie03245a52009-12-04 13:27:57 -03002059 u32 FBDiv, Rest, FREF, VCOF_kHz = 0;
Olivier Grenie03245a52009-12-04 13:27:57 -03002060 int ret = 10; /* 1ms is the default delay most of the time */
2061 u8 c, i;
2062
Olivier Grenie28fafca2011-01-04 04:27:11 -03002063 /************************* VCO ***************************/
Olivier Grenie03245a52009-12-04 13:27:57 -03002064 /* Default values for FG */
2065 /* from these are needed : */
2066 /* Cp,HFdiv,VCOband,SD,Num,Den,FB and REFDiv */
2067
Olivier Grenie28fafca2011-01-04 04:27:11 -03002068 /* 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));
Olivier Grenie03245a52009-12-04 13:27:57 -03002075 }
2076
Olivier Grenie28fafca2011-01-04 04:27:11 -03002077 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;
2082 }
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);
2088
Olivier Grenie03245a52009-12-04 13:27:57 -03002089 if (*tune_state == CT_TUNER_START) {
Olivier Grenie28fafca2011-01-04 04:27:11 -03002090 /* 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
2095 }
Olivier Grenie03245a52009-12-04 13:27:57 -03002096
Olivier Grenie28fafca2011-01-04 04:27:11 -03002097 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);
2102
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;
2109
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;
2118 }
2119 LUT_offset++;
2120 }
2121 }
2122
2123 if (found_offset == 0)
2124 state->rf_request += 400;
2125 }
2126 if (state->current_rf != state->rf_request || (state->current_standard != state->fe->dtv_property_cache.delivery_system)) {
2127 state->tuner_is_tuned = 0;
Olivier Grenie03245a52009-12-04 13:27:57 -03002128 state->current_rf = 0;
Olivier Grenie28fafca2011-01-04 04:27:11 -03002129 state->current_standard = 0;
Olivier Grenie03245a52009-12-04 13:27:57 -03002130
Olivier Grenie28fafca2011-01-04 04:27:11 -03002131 tune = dib0090_tuning_table;
2132 if (state->identity.p1g)
2133 tune = dib0090_p1g_tuning_table;
Olivier Grenie03245a52009-12-04 13:27:57 -03002134
Olivier Grenie28fafca2011-01-04 04:27:11 -03002135 tmp = (state->identity.version >> 5) & 0x7;
2136
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;
2143 }
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;
2148 }
2149 }
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 */
2155
2156 tune = dib0090_tuning_table_fm_vhf_on_cband;
2157 if (state->identity.p1g)
2158 tune = dib0090_p1g_tuning_table_fm_vhf_on_cband;
2159 }
2160 }
2161
2162 pll = dib0090_pll_table;
2163 if (state->identity.p1g)
2164 pll = dib0090_p1g_pll_table;
2165
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++;
2171
2172 state->current_tune_table_index = tune;
2173 state->current_pll_table_index = pll;
2174
2175 // select internal switch
Olivier Grenie03245a52009-12-04 13:27:57 -03002176 dib0090_write_reg(state, 0x0b, 0xb800 | (tune->switch_trim));
2177
Olivier Grenie28fafca2011-01-04 04:27:11 -03002178 // Find the VCO frequency in MHz
2179 VCOF_kHz = (pll->hfdiv * state->rf_request) * 2;
Olivier Grenie03245a52009-12-04 13:27:57 -03002180
Olivier Grenie28fafca2011-01-04 04:27:11 -03002181 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;
Olivier Grenie03245a52009-12-04 13:27:57 -03002184
Olivier Grenie28fafca2011-01-04 04:27:11 -03002185 // Determine the FB divider
2186 // The reference is 10MHz, Therefore the FBdivider is on the first digits
Olivier Grenie03245a52009-12-04 13:27:57 -03002187 FBDiv = (VCOF_kHz / pll->topresc / FREF);
Olivier Grenie28fafca2011-01-04 04:27:11 -03002188 Rest = (VCOF_kHz / pll->topresc) - FBDiv * FREF; //in kHz
Olivier Grenie03245a52009-12-04 13:27:57 -03002189
Olivier Grenie28fafca2011-01-04 04:27:11 -03002190 // Avoid Spurs in the loopfilter bandwidth
Olivier Grenie03245a52009-12-04 13:27:57 -03002191 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;
Olivier Grenie28fafca2011-01-04 04:27:11 -03002198 } //Go to the next FB
2199 else if (Rest > (FREF - 2 * LPF))
Olivier Grenie03245a52009-12-04 13:27:57 -03002200 Rest = FREF - 2 * LPF;
2201 Rest = (Rest * 6528) / (FREF / 10);
Olivier Grenie28fafca2011-01-04 04:27:11 -03002202 state->rest = Rest;
2203
2204 /* external loop filter, otherwise:
2205 * lo5 = (0 << 15) | (0 << 12) | (0 << 11) | (3 << 9) | (4 << 6) | (3 << 4) | 4;
2206 * lo6 = 0x0e34 */
2207
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;
2222 }
2223
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
2232 }
2233
2234 lo5 |= (pll->hfdiv_code << 11) | (pll->vco_band << 7); /* bit 15 is the split to the slave, we do not do it here */
2235
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);
Olivier Grenie03245a52009-12-04 13:27:57 -03002247
2248 Den = 1;
2249
Olivier Grenie03245a52009-12-04 13:27:57 -03002250 if (Rest > 0) {
2251 if (state->config->analog_output)
Olivier Grenie28fafca2011-01-04 04:27:11 -03002252 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
2258 }
Olivier Grenie03245a52009-12-04 13:27:57 -03002259 Den = 255;
2260 }
Olivier Grenie28fafca2011-01-04 04:27:11 -03002261 // Now we have to define the Num and Denum
2262 // LO1 gets the FBdiv
Olivier Grenie03245a52009-12-04 13:27:57 -03002263 dib0090_write_reg(state, 0x15, (u16) FBDiv);
Olivier Grenie28fafca2011-01-04 04:27:11 -03002264 // 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
Olivier Grenie03245a52009-12-04 13:27:57 -03002270 dib0090_write_reg(state, 0x17, (u16) Rest);
Olivier Grenie28fafca2011-01-04 04:27:11 -03002271 // VCO and HF DIV
Olivier Grenie03245a52009-12-04 13:27:57 -03002272 dib0090_write_reg(state, 0x19, lo5);
Olivier Grenie28fafca2011-01-04 04:27:11 -03002273 // SIGMA Delta
Olivier Grenie03245a52009-12-04 13:27:57 -03002274 dib0090_write_reg(state, 0x1c, lo6);
2275
Olivier Grenie28fafca2011-01-04 04:27:11 -03002276 // 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
Olivier Grenie03245a52009-12-04 13:27:57 -03002279 lo6 = tune->tuner_enable;
2280 if (state->config->analog_output)
2281 lo6 = (lo6 & 0xff9f) | 0x2;
2282
Olivier Grenie28fafca2011-01-04 04:27:11 -03002283 dib0090_write_reg(state, 0x24, lo6 | EN_LO | state->config->use_pwm_agc * EN_CRYSTAL);
Olivier Grenie03245a52009-12-04 13:27:57 -03002284
Olivier Grenie03245a52009-12-04 13:27:57 -03002285 }
Olivier Grenie03245a52009-12-04 13:27:57 -03002286
Olivier Grenie28fafca2011-01-04 04:27:11 -03002287 state->current_rf = state->rf_request;
2288 state->current_standard = state->fe->dtv_property_cache.delivery_system;
Olivier Grenie03245a52009-12-04 13:27:57 -03002289
2290 ret = 20;
Olivier Grenie28fafca2011-01-04 04:27:11 -03002291 state->calibrate = CAPTRIM_CAL; /* captrim serach now */
2292 }
Olivier Grenie03245a52009-12-04 13:27:57 -03002293
Olivier Grenie28fafca2011-01-04 04:27:11 -03002294 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;
Olivier Grenie03245a52009-12-04 13:27:57 -03002296
Olivier Grenie28fafca2011-01-04 04:27:11 -03002297// if(!state->identity.p1g) {
2298 while (state->current_rf / 1000 > wbd->max_freq)
2299 wbd++;
2300// }
Olivier Grenie03245a52009-12-04 13:27:57 -03002301
Olivier Grenie03245a52009-12-04 13:27:57 -03002302 dib0090_write_reg(state, 0x1e, 0x07ff);
Olivier Grenie28fafca2011-01-04 04:27:11 -03002303 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);
Olivier Grenie03245a52009-12-04 13:27:57 -03002311
Olivier Grenie28fafca2011-01-04 04:27:11 -03002312#define WBD 0x781 /* 1 1 1 1 0000 0 0 1 */
Olivier Grenie03245a52009-12-04 13:27:57 -03002313 c = 4;
Olivier Grenie28fafca2011-01-04 04:27:11 -03002314 i = 3; //wbdmux_bias
2315
2316 if (wbd->wbd_gain != 0) //&& !state->identity.p1g)
2317 c = wbd->wbd_gain;
2318
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);
2322
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);
2329
Olivier Grenie03245a52009-12-04 13:27:57 -03002330 dib0090_write_reg(state, 0x0c, tune->v2i);
2331 dib0090_write_reg(state, 0x0d, tune->mix);
2332 dib0090_write_reg(state, 0x0e, tune->load);
Olivier Grenie28fafca2011-01-04 04:27:11 -03002333 *tune_state = CT_TUNER_STEP_1;
Olivier Grenie03245a52009-12-04 13:27:57 -03002334
Olivier Grenie28fafca2011-01-04 04:27:11 -03002335 } else if (*tune_state == CT_TUNER_STEP_1) {
Olivier Grenie03245a52009-12-04 13:27:57 -03002336 /* initialize the lt gain register */
2337 state->rf_lt_def = 0x7c00;
Olivier Grenie28fafca2011-01-04 04:27:11 -03002338 // dib0090_write_reg(state, 0x0f, state->rf_lt_def);
Olivier Grenie03245a52009-12-04 13:27:57 -03002339
2340 dib0090_set_bandwidth(state);
2341 state->tuner_is_tuned = 1;
Olivier Grenie28fafca2011-01-04 04:27:11 -03002342
2343// if(!state->identity.p1g)
2344 state->calibrate |= WBD_CAL; // TODO: only do the WBD calibration for new tune
2345//
2346 state->calibrate |= TEMP_CAL; // Force the Temperature to be remesured at next TUNE.
Olivier Grenie03245a52009-12-04 13:27:57 -03002347 *tune_state = CT_TUNER_STOP;
2348 } else
2349 ret = FE_CALLBACK_TIME_NEVER;
2350 return ret;
2351}
2352
2353static int dib0090_release(struct dvb_frontend *fe)
2354{
2355 kfree(fe->tuner_priv);
2356 fe->tuner_priv = NULL;
2357 return 0;
2358}
2359
2360enum frontend_tune_state dib0090_get_tune_state(struct dvb_frontend *fe)
2361{
2362 struct dib0090_state *state = fe->tuner_priv;
2363
2364 return state->tune_state;
2365}
Olivier Grenie28fafca2011-01-04 04:27:11 -03002366
Olivier Grenie03245a52009-12-04 13:27:57 -03002367EXPORT_SYMBOL(dib0090_get_tune_state);
2368
2369int dib0090_set_tune_state(struct dvb_frontend *fe, enum frontend_tune_state tune_state)
2370{
2371 struct dib0090_state *state = fe->tuner_priv;
2372
2373 state->tune_state = tune_state;
2374 return 0;
2375}
Olivier Grenie28fafca2011-01-04 04:27:11 -03002376
Olivier Grenie03245a52009-12-04 13:27:57 -03002377EXPORT_SYMBOL(dib0090_set_tune_state);
2378
2379static int dib0090_get_frequency(struct dvb_frontend *fe, u32 * frequency)
2380{
2381 struct dib0090_state *state = fe->tuner_priv;
2382
2383 *frequency = 1000 * state->current_rf;
2384 return 0;
2385}
2386
2387static int dib0090_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *p)
2388{
2389 struct dib0090_state *state = fe->tuner_priv;
Olivier Grenie28fafca2011-01-04 04:27:11 -03002390 u32 ret;
Olivier Grenie03245a52009-12-04 13:27:57 -03002391
2392 state->tune_state = CT_TUNER_START;
2393
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);
2401
2402 return 0;
2403}
2404
2405static 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,
2411 },
2412 .release = dib0090_release,
2413
2414 .init = dib0090_wakeup,
2415 .sleep = dib0090_sleep,
2416 .set_params = dib0090_set_params,
2417 .get_frequency = dib0090_get_frequency,
2418};
2419
Olivier Grenie28fafca2011-01-04 04:27:11 -03002420static 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,
2426 },
2427 .release = dib0090_release,
2428
2429 .init = NULL,
2430 .sleep = NULL,
2431 .set_params = NULL,
2432 .get_frequency = NULL,
2433};
2434
2435static 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},
2441};
2442
Olivier Grenie03245a52009-12-04 13:27:57 -03002443struct dvb_frontend *dib0090_register(struct dvb_frontend *fe, struct i2c_adapter *i2c, const struct dib0090_config *config)
2444{
2445 struct dib0090_state *st = kzalloc(sizeof(struct dib0090_state), GFP_KERNEL);
2446 if (st == NULL)
2447 return NULL;
2448
2449 st->config = config;
2450 st->i2c = i2c;
2451 st->fe = fe;
2452 fe->tuner_priv = st;
2453
Olivier Grenie28fafca2011-01-04 04:27:11 -03002454 if (config->wbd == NULL)
2455 st->current_wbd_table = dib0090_wbd_table_default;
2456 else
2457 st->current_wbd_table = config->wbd;
2458
Olivier Grenie03245a52009-12-04 13:27:57 -03002459 if (dib0090_reset(fe) != 0)
2460 goto free_mem;
2461
2462 printk(KERN_INFO "DiB0090: successfully identified\n");
2463 memcpy(&fe->ops.tuner_ops, &dib0090_ops, sizeof(struct dvb_tuner_ops));
2464
2465 return fe;
2466 free_mem:
2467 kfree(st);
2468 fe->tuner_priv = NULL;
2469 return NULL;
2470}
Olivier Grenie28fafca2011-01-04 04:27:11 -03002471
Olivier Grenie03245a52009-12-04 13:27:57 -03002472EXPORT_SYMBOL(dib0090_register);
2473
Olivier Grenie28fafca2011-01-04 04:27:11 -03002474struct dvb_frontend *dib0090_fw_register(struct dvb_frontend *fe, struct i2c_adapter *i2c, const struct dib0090_config *config)
2475{
2476 struct dib0090_fw_state *st = kzalloc(sizeof(struct dib0090_fw_state), GFP_KERNEL);
2477 if (st == NULL)
2478 return NULL;
2479
2480 st->config = config;
2481 st->i2c = i2c;
2482 st->fe = fe;
2483 fe->tuner_priv = st;
2484
2485 if (dib0090_fw_reset_digital(fe, st->config) != 0)
2486 goto free_mem;
2487
2488 dprintk("DiB0090 FW: successfully identified");
2489 memcpy(&fe->ops.tuner_ops, &dib0090_fw_ops, sizeof(struct dvb_tuner_ops));
2490
2491 return fe;
2492 free_mem:
2493 kfree(st);
2494 fe->tuner_priv = NULL;
2495 return NULL;
2496}
2497
2498EXPORT_SYMBOL(dib0090_fw_register);
2499
Olivier Grenie03245a52009-12-04 13:27:57 -03002500MODULE_AUTHOR("Patrick Boettcher <pboettcher@dibcom.fr>");
2501MODULE_AUTHOR("Olivier Grenie <olivier.grenie@dibcom.fr>");
2502MODULE_DESCRIPTION("Driver for the DiBcom 0090 base-band RF Tuner");
2503MODULE_LICENSE("GPL");