blob: c9c935ae41e47bf9eaccb4f6e9df0ef0701b6e18 [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;
Olivier Grenie5a0deee2011-05-03 12:27:33 -0300194
195 /* for the I2C transfer */
196 struct i2c_msg msg[2];
197 u8 i2c_write_buffer[3];
198 u8 i2c_read_buffer[2];
Olivier Grenie28fafca2011-01-04 04:27:11 -0300199};
200
201struct dib0090_fw_state {
202 struct i2c_adapter *i2c;
203 struct dvb_frontend *fe;
204 struct dib0090_identity identity;
205 const struct dib0090_config *config;
Olivier Grenie5a0deee2011-05-03 12:27:33 -0300206
207 /* for the I2C transfer */
208 struct i2c_msg msg;
209 u8 i2c_write_buffer[2];
210 u8 i2c_read_buffer[2];
Olivier Grenie03245a52009-12-04 13:27:57 -0300211};
212
213static u16 dib0090_read_reg(struct dib0090_state *state, u8 reg)
214{
Olivier Grenie5a0deee2011-05-03 12:27:33 -0300215 state->i2c_write_buffer[0] = reg;
216
217 memset(state->msg, 0, 2 * sizeof(struct i2c_msg));
218 state->msg[0].addr = state->config->i2c_address;
219 state->msg[0].flags = 0;
220 state->msg[0].buf = state->i2c_write_buffer;
221 state->msg[0].len = 1;
222 state->msg[1].addr = state->config->i2c_address;
223 state->msg[1].flags = I2C_M_RD;
224 state->msg[1].buf = state->i2c_read_buffer;
225 state->msg[1].len = 2;
226
227 if (i2c_transfer(state->i2c, state->msg, 2) != 2) {
Olivier Grenie03245a52009-12-04 13:27:57 -0300228 printk(KERN_WARNING "DiB0090 I2C read failed\n");
229 return 0;
230 }
Olivier Grenie5a0deee2011-05-03 12:27:33 -0300231
232 return (state->i2c_read_buffer[0] << 8) | state->i2c_read_buffer[1];
Olivier Grenie03245a52009-12-04 13:27:57 -0300233}
234
235static int dib0090_write_reg(struct dib0090_state *state, u32 reg, u16 val)
236{
Olivier Grenie5a0deee2011-05-03 12:27:33 -0300237 state->i2c_write_buffer[0] = reg & 0xff;
238 state->i2c_write_buffer[1] = val >> 8;
239 state->i2c_write_buffer[2] = val & 0xff;
240
241 memset(state->msg, 0, sizeof(struct i2c_msg));
242 state->msg[0].addr = state->config->i2c_address;
243 state->msg[0].flags = 0;
244 state->msg[0].buf = state->i2c_write_buffer;
245 state->msg[0].len = 3;
246
247 if (i2c_transfer(state->i2c, state->msg, 1) != 1) {
Olivier Grenie28fafca2011-01-04 04:27:11 -0300248 printk(KERN_WARNING "DiB0090 I2C write failed\n");
249 return -EREMOTEIO;
250 }
251 return 0;
252}
253
254static u16 dib0090_fw_read_reg(struct dib0090_fw_state *state, u8 reg)
255{
Olivier Grenie5a0deee2011-05-03 12:27:33 -0300256 state->i2c_write_buffer[0] = reg;
257
258 memset(&state->msg, 0, sizeof(struct i2c_msg));
259 state->msg.addr = reg;
260 state->msg.flags = I2C_M_RD;
261 state->msg.buf = state->i2c_read_buffer;
262 state->msg.len = 2;
263 if (i2c_transfer(state->i2c, &state->msg, 1) != 1) {
Olivier Grenie28fafca2011-01-04 04:27:11 -0300264 printk(KERN_WARNING "DiB0090 I2C read failed\n");
265 return 0;
266 }
Olivier Grenie5a0deee2011-05-03 12:27:33 -0300267 return (state->i2c_read_buffer[0] << 8) | state->i2c_read_buffer[1];
Olivier Grenie28fafca2011-01-04 04:27:11 -0300268}
269
270static int dib0090_fw_write_reg(struct dib0090_fw_state *state, u8 reg, u16 val)
271{
Olivier Grenie5a0deee2011-05-03 12:27:33 -0300272 state->i2c_write_buffer[0] = val >> 8;
273 state->i2c_write_buffer[1] = val & 0xff;
274
275 memset(&state->msg, 0, sizeof(struct i2c_msg));
276 state->msg.addr = reg;
277 state->msg.flags = 0;
278 state->msg.buf = state->i2c_write_buffer;
279 state->msg.len = 2;
280 if (i2c_transfer(state->i2c, &state->msg, 1) != 1) {
Olivier Grenie03245a52009-12-04 13:27:57 -0300281 printk(KERN_WARNING "DiB0090 I2C write failed\n");
282 return -EREMOTEIO;
283 }
284 return 0;
285}
286
287#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)
288#define ADC_TARGET -220
289#define GAIN_ALPHA 5
290#define WBD_ALPHA 6
291#define LPF 100
292static void dib0090_write_regs(struct dib0090_state *state, u8 r, const u16 * b, u8 c)
293{
294 do {
295 dib0090_write_reg(state, r++, *b++);
296 } while (--c);
297}
298
Olivier Grenie28fafca2011-01-04 04:27:11 -0300299static int dib0090_identify(struct dvb_frontend *fe)
Olivier Grenie03245a52009-12-04 13:27:57 -0300300{
301 struct dib0090_state *state = fe->tuner_priv;
302 u16 v;
Olivier Grenie28fafca2011-01-04 04:27:11 -0300303 struct dib0090_identity *identity = &state->identity;
Olivier Grenie03245a52009-12-04 13:27:57 -0300304
305 v = dib0090_read_reg(state, 0x1a);
306
Olivier Grenie28fafca2011-01-04 04:27:11 -0300307 identity->p1g = 0;
308 identity->in_soc = 0;
309
310 dprintk("Tuner identification (Version = 0x%04x)", v);
Olivier Grenie03245a52009-12-04 13:27:57 -0300311
312 /* without PLL lock info */
Olivier Grenie28fafca2011-01-04 04:27:11 -0300313 v &= ~KROSUS_PLL_LOCKED;
Olivier Grenie03245a52009-12-04 13:27:57 -0300314
Olivier Grenie28fafca2011-01-04 04:27:11 -0300315 identity->version = v & 0xff;
316 identity->product = (v >> 8) & 0xf;
Olivier Grenie03245a52009-12-04 13:27:57 -0300317
Olivier Grenie28fafca2011-01-04 04:27:11 -0300318 if (identity->product != KROSUS)
319 goto identification_error;
Olivier Grenie03245a52009-12-04 13:27:57 -0300320
Olivier Grenie28fafca2011-01-04 04:27:11 -0300321 if ((identity->version & 0x3) == SOC) {
322 identity->in_soc = 1;
323 switch (identity->version) {
324 case SOC_8090_P1G_11R1:
325 dprintk("SOC 8090 P1-G11R1 Has been detected");
326 identity->p1g = 1;
327 break;
328 case SOC_8090_P1G_21R1:
329 dprintk("SOC 8090 P1-G21R1 Has been detected");
330 identity->p1g = 1;
331 break;
332 case SOC_7090_P1G_11R1:
333 dprintk("SOC 7090 P1-G11R1 Has been detected");
334 identity->p1g = 1;
335 break;
336 case SOC_7090_P1G_21R1:
337 dprintk("SOC 7090 P1-G21R1 Has been detected");
338 identity->p1g = 1;
339 break;
340 default:
341 goto identification_error;
342 }
343 } else {
344 switch ((identity->version >> 5) & 0x7) {
345 case MP001:
346 dprintk("MP001 : 9090/8096");
347 break;
348 case MP005:
349 dprintk("MP005 : Single Sband");
350 break;
351 case MP008:
352 dprintk("MP008 : diversity VHF-UHF-LBAND");
353 break;
354 case MP009:
355 dprintk("MP009 : diversity 29098 CBAND-UHF-LBAND-SBAND");
356 break;
357 default:
358 goto identification_error;
359 }
360
361 switch (identity->version & 0x1f) {
362 case P1G_21R2:
363 dprintk("P1G_21R2 detected");
364 identity->p1g = 1;
365 break;
366 case P1G:
367 dprintk("P1G detected");
368 identity->p1g = 1;
369 break;
370 case P1D_E_F:
371 dprintk("P1D/E/F detected");
372 break;
373 case P1C:
374 dprintk("P1C detected");
375 break;
376 case P1A_B:
377 dprintk("P1-A/B detected: driver is deactivated - not available");
378 goto identification_error;
379 break;
380 default:
381 goto identification_error;
382 }
Olivier Grenie03245a52009-12-04 13:27:57 -0300383 }
384
Olivier Grenie28fafca2011-01-04 04:27:11 -0300385 return 0;
386
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300387identification_error:
Olivier Grenie28fafca2011-01-04 04:27:11 -0300388 return -EIO;
389}
390
391static int dib0090_fw_identify(struct dvb_frontend *fe)
392{
393 struct dib0090_fw_state *state = fe->tuner_priv;
394 struct dib0090_identity *identity = &state->identity;
395
396 u16 v = dib0090_fw_read_reg(state, 0x1a);
397 identity->p1g = 0;
398 identity->in_soc = 0;
399
400 dprintk("FE: Tuner identification (Version = 0x%04x)", v);
401
402 /* without PLL lock info */
403 v &= ~KROSUS_PLL_LOCKED;
404
405 identity->version = v & 0xff;
406 identity->product = (v >> 8) & 0xf;
407
408 if (identity->product != KROSUS)
409 goto identification_error;
410
Olivier Grenie28fafca2011-01-04 04:27:11 -0300411 if ((identity->version & 0x3) == SOC) {
412 identity->in_soc = 1;
413 switch (identity->version) {
414 case SOC_8090_P1G_11R1:
415 dprintk("SOC 8090 P1-G11R1 Has been detected");
416 identity->p1g = 1;
417 break;
418 case SOC_8090_P1G_21R1:
419 dprintk("SOC 8090 P1-G21R1 Has been detected");
420 identity->p1g = 1;
421 break;
422 case SOC_7090_P1G_11R1:
423 dprintk("SOC 7090 P1-G11R1 Has been detected");
424 identity->p1g = 1;
425 break;
426 case SOC_7090_P1G_21R1:
427 dprintk("SOC 7090 P1-G21R1 Has been detected");
428 identity->p1g = 1;
429 break;
430 default:
431 goto identification_error;
432 }
433 } else {
434 switch ((identity->version >> 5) & 0x7) {
435 case MP001:
436 dprintk("MP001 : 9090/8096");
437 break;
438 case MP005:
439 dprintk("MP005 : Single Sband");
440 break;
441 case MP008:
442 dprintk("MP008 : diversity VHF-UHF-LBAND");
443 break;
444 case MP009:
445 dprintk("MP009 : diversity 29098 CBAND-UHF-LBAND-SBAND");
446 break;
447 default:
448 goto identification_error;
449 }
450
451 switch (identity->version & 0x1f) {
452 case P1G_21R2:
453 dprintk("P1G_21R2 detected");
454 identity->p1g = 1;
455 break;
456 case P1G:
457 dprintk("P1G detected");
458 identity->p1g = 1;
459 break;
460 case P1D_E_F:
461 dprintk("P1D/E/F detected");
462 break;
463 case P1C:
464 dprintk("P1C detected");
465 break;
466 case P1A_B:
467 dprintk("P1-A/B detected: driver is deactivated - not available");
468 goto identification_error;
469 break;
470 default:
471 goto identification_error;
472 }
473 }
474
475 return 0;
476
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300477identification_error:
Olivier Grenie28fafca2011-01-04 04:27:11 -0300478 return -EIO;;
Olivier Grenie03245a52009-12-04 13:27:57 -0300479}
480
481static void dib0090_reset_digital(struct dvb_frontend *fe, const struct dib0090_config *cfg)
482{
483 struct dib0090_state *state = fe->tuner_priv;
Olivier Grenie28fafca2011-01-04 04:27:11 -0300484 u16 PllCfg, i, v;
Olivier Grenie03245a52009-12-04 13:27:57 -0300485
486 HARD_RESET(state);
487
Olivier Grenie28fafca2011-01-04 04:27:11 -0300488 dib0090_write_reg(state, 0x24, EN_PLL | EN_CRYSTAL);
Olivier Grenie03245a52009-12-04 13:27:57 -0300489 dib0090_write_reg(state, 0x1b, EN_DIGCLK | EN_PLL | EN_CRYSTAL); /* PLL, DIG_CLK and CRYSTAL remain */
490
Olivier Grenie28fafca2011-01-04 04:27:11 -0300491 if (!cfg->in_soc) {
492 /* adcClkOutRatio=8->7, release reset */
493 dib0090_write_reg(state, 0x20, ((cfg->io.adc_clock_ratio - 1) << 11) | (0 << 10) | (1 << 9) | (1 << 8) | (0 << 4) | 0);
494 if (cfg->clkoutdrive != 0)
495 dib0090_write_reg(state, 0x23, (0 << 15) | ((!cfg->analog_output) << 14) | (2 << 10) | (1 << 9) | (0 << 8)
496 | (cfg->clkoutdrive << 5) | (cfg->clkouttobamse << 4) | (0 << 2) | (0));
497 else
498 dib0090_write_reg(state, 0x23, (0 << 15) | ((!cfg->analog_output) << 14) | (2 << 10) | (1 << 9) | (0 << 8)
499 | (7 << 5) | (cfg->clkouttobamse << 4) | (0 << 2) | (0));
500 }
501
502 /* Read Pll current config * */
503 PllCfg = dib0090_read_reg(state, 0x21);
504
505 /** Reconfigure PLL if current setting is different from default setting **/
506 if ((PllCfg & 0x1FFF) != ((cfg->io.pll_range << 12) | (cfg->io.pll_loopdiv << 6) | (cfg->io.pll_prediv)) && (!cfg->in_soc)
507 && !cfg->io.pll_bypass) {
508
509 /* Set Bypass mode */
510 PllCfg |= (1 << 15);
511 dib0090_write_reg(state, 0x21, PllCfg);
512
513 /* Set Reset Pll */
514 PllCfg &= ~(1 << 13);
515 dib0090_write_reg(state, 0x21, PllCfg);
516
517 /*** Set new Pll configuration in bypass and reset state ***/
518 PllCfg = (1 << 15) | (0 << 13) | (cfg->io.pll_range << 12) | (cfg->io.pll_loopdiv << 6) | (cfg->io.pll_prediv);
519 dib0090_write_reg(state, 0x21, PllCfg);
520
521 /* Remove Reset Pll */
522 PllCfg |= (1 << 13);
523 dib0090_write_reg(state, 0x21, PllCfg);
524
525 /*** Wait for PLL lock ***/
526 i = 100;
527 do {
528 v = !!(dib0090_read_reg(state, 0x1a) & 0x800);
529 if (v)
530 break;
531 } while (--i);
532
533 if (i == 0) {
534 dprintk("Pll: Unable to lock Pll");
535 return;
536 }
537
538 /* Finally Remove Bypass mode */
539 PllCfg &= ~(1 << 15);
540 dib0090_write_reg(state, 0x21, PllCfg);
541 }
542
543 if (cfg->io.pll_bypass) {
544 PllCfg |= (cfg->io.pll_bypass << 15);
545 dib0090_write_reg(state, 0x21, PllCfg);
546 }
547}
548
549static int dib0090_fw_reset_digital(struct dvb_frontend *fe, const struct dib0090_config *cfg)
550{
551 struct dib0090_fw_state *state = fe->tuner_priv;
552 u16 PllCfg;
553 u16 v;
554 int i;
555
556 dprintk("fw reset digital");
557 HARD_RESET(state);
558
559 dib0090_fw_write_reg(state, 0x24, EN_PLL | EN_CRYSTAL);
560 dib0090_fw_write_reg(state, 0x1b, EN_DIGCLK | EN_PLL | EN_CRYSTAL); /* PLL, DIG_CLK and CRYSTAL remain */
561
562 dib0090_fw_write_reg(state, 0x20,
563 ((cfg->io.adc_clock_ratio - 1) << 11) | (0 << 10) | (1 << 9) | (1 << 8) | (cfg->data_tx_drv << 4) | cfg->ls_cfg_pad_drv);
564
565 v = (0 << 15) | ((!cfg->analog_output) << 14) | (1 << 9) | (0 << 8) | (cfg->clkouttobamse << 4) | (0 << 2) | (0);
Olivier Grenie03245a52009-12-04 13:27:57 -0300566 if (cfg->clkoutdrive != 0)
Olivier Grenie28fafca2011-01-04 04:27:11 -0300567 v |= cfg->clkoutdrive << 5;
Olivier Grenie03245a52009-12-04 13:27:57 -0300568 else
Olivier Grenie28fafca2011-01-04 04:27:11 -0300569 v |= 7 << 5;
Olivier Grenie03245a52009-12-04 13:27:57 -0300570
Olivier Grenie28fafca2011-01-04 04:27:11 -0300571 v |= 2 << 10;
572 dib0090_fw_write_reg(state, 0x23, v);
Olivier Grenie03245a52009-12-04 13:27:57 -0300573
Olivier Grenie28fafca2011-01-04 04:27:11 -0300574 /* Read Pll current config * */
575 PllCfg = dib0090_fw_read_reg(state, 0x21);
576
577 /** Reconfigure PLL if current setting is different from default setting **/
578 if ((PllCfg & 0x1FFF) != ((cfg->io.pll_range << 12) | (cfg->io.pll_loopdiv << 6) | (cfg->io.pll_prediv)) && !cfg->io.pll_bypass) {
579
580 /* Set Bypass mode */
581 PllCfg |= (1 << 15);
582 dib0090_fw_write_reg(state, 0x21, PllCfg);
583
584 /* Set Reset Pll */
585 PllCfg &= ~(1 << 13);
586 dib0090_fw_write_reg(state, 0x21, PllCfg);
587
588 /*** Set new Pll configuration in bypass and reset state ***/
589 PllCfg = (1 << 15) | (0 << 13) | (cfg->io.pll_range << 12) | (cfg->io.pll_loopdiv << 6) | (cfg->io.pll_prediv);
590 dib0090_fw_write_reg(state, 0x21, PllCfg);
591
592 /* Remove Reset Pll */
593 PllCfg |= (1 << 13);
594 dib0090_fw_write_reg(state, 0x21, PllCfg);
595
596 /*** Wait for PLL lock ***/
597 i = 100;
598 do {
599 v = !!(dib0090_fw_read_reg(state, 0x1a) & 0x800);
600 if (v)
601 break;
602 } while (--i);
603
604 if (i == 0) {
605 dprintk("Pll: Unable to lock Pll");
606 return -EIO;
607 }
608
609 /* Finally Remove Bypass mode */
610 PllCfg &= ~(1 << 15);
611 dib0090_fw_write_reg(state, 0x21, PllCfg);
612 }
613
614 if (cfg->io.pll_bypass) {
615 PllCfg |= (cfg->io.pll_bypass << 15);
616 dib0090_fw_write_reg(state, 0x21, PllCfg);
617 }
618
619 return dib0090_fw_identify(fe);
Olivier Grenie03245a52009-12-04 13:27:57 -0300620}
621
622static int dib0090_wakeup(struct dvb_frontend *fe)
623{
624 struct dib0090_state *state = fe->tuner_priv;
625 if (state->config->sleep)
626 state->config->sleep(fe, 0);
Olivier Grenie28fafca2011-01-04 04:27:11 -0300627
628 /* enable dataTX in case we have been restarted in the wrong moment */
629 dib0090_write_reg(state, 0x23, dib0090_read_reg(state, 0x23) | (1 << 14));
Olivier Grenie03245a52009-12-04 13:27:57 -0300630 return 0;
631}
632
633static int dib0090_sleep(struct dvb_frontend *fe)
634{
635 struct dib0090_state *state = fe->tuner_priv;
636 if (state->config->sleep)
637 state->config->sleep(fe, 1);
638 return 0;
639}
640
Márton Németh43e3e6d2010-01-16 14:35:03 -0300641void dib0090_dcc_freq(struct dvb_frontend *fe, u8 fast)
Olivier Grenie03245a52009-12-04 13:27:57 -0300642{
643 struct dib0090_state *state = fe->tuner_priv;
644 if (fast)
Olivier Grenie9c783032009-12-07 07:49:40 -0300645 dib0090_write_reg(state, 0x04, 0);
Olivier Grenie03245a52009-12-04 13:27:57 -0300646 else
Olivier Grenie9c783032009-12-07 07:49:40 -0300647 dib0090_write_reg(state, 0x04, 1);
Olivier Grenie03245a52009-12-04 13:27:57 -0300648}
Olivier Grenie28fafca2011-01-04 04:27:11 -0300649
Olivier Grenie03245a52009-12-04 13:27:57 -0300650EXPORT_SYMBOL(dib0090_dcc_freq);
Olivier Grenie9c783032009-12-07 07:49:40 -0300651
Olivier Grenie28fafca2011-01-04 04:27:11 -0300652static const u16 bb_ramp_pwm_normal_socs[] = {
653 550, /* max BB gain in 10th of dB */
654 (1 << 9) | 8, /* ramp_slope = 1dB of gain -> clock_ticks_per_db = clk_khz / ramp_slope -> BB_RAMP2 */
655 440,
656 (4 << 9) | 0, /* BB_RAMP3 = 26dB */
657 (0 << 9) | 208, /* BB_RAMP4 */
658 (4 << 9) | 208, /* BB_RAMP5 = 29dB */
659 (0 << 9) | 440, /* BB_RAMP6 */
660};
661
662static const u16 rf_ramp_pwm_cband_7090[] = {
663 280, /* max RF gain in 10th of dB */
664 18, /* ramp_slope = 1dB of gain -> clock_ticks_per_db = clk_khz / ramp_slope -> RF_RAMP2 */
665 504, /* ramp_max = maximum X used on the ramp */
666 (29 << 10) | 364, /* RF_RAMP5, LNA 1 = 8dB */
667 (0 << 10) | 504, /* RF_RAMP6, LNA 1 */
668 (60 << 10) | 228, /* RF_RAMP7, LNA 2 = 7.7dB */
669 (0 << 10) | 364, /* RF_RAMP8, LNA 2 */
670 (34 << 10) | 109, /* GAIN_4_1, LNA 3 = 6.8dB */
671 (0 << 10) | 228, /* GAIN_4_2, LNA 3 */
672 (37 << 10) | 0, /* RF_RAMP3, LNA 4 = 6.2dB */
673 (0 << 10) | 109, /* RF_RAMP4, LNA 4 */
674};
675
676static const u16 rf_ramp_pwm_cband_8090[] = {
677 345, /* max RF gain in 10th of dB */
678 29, /* ramp_slope = 1dB of gain -> clock_ticks_per_db = clk_khz / ramp_slope -> RF_RAMP2 */
679 1000, /* ramp_max = maximum X used on the ramp */
680 (35 << 10) | 772, /* RF_RAMP3, LNA 1 = 8dB */
681 (0 << 10) | 1000, /* RF_RAMP4, LNA 1 */
682 (58 << 10) | 496, /* RF_RAMP5, LNA 2 = 9.5dB */
683 (0 << 10) | 772, /* RF_RAMP6, LNA 2 */
684 (27 << 10) | 200, /* RF_RAMP7, LNA 3 = 10.5dB */
685 (0 << 10) | 496, /* RF_RAMP8, LNA 3 */
686 (40 << 10) | 0, /* GAIN_4_1, LNA 4 = 7dB */
687 (0 << 10) | 200, /* GAIN_4_2, LNA 4 */
688};
689
690static const u16 rf_ramp_pwm_uhf_7090[] = {
691 407, /* max RF gain in 10th of dB */
692 13, /* ramp_slope = 1dB of gain -> clock_ticks_per_db = clk_khz / ramp_slope -> RF_RAMP2 */
693 529, /* ramp_max = maximum X used on the ramp */
694 (23 << 10) | 0, /* RF_RAMP3, LNA 1 = 14.7dB */
695 (0 << 10) | 176, /* RF_RAMP4, LNA 1 */
696 (63 << 10) | 400, /* RF_RAMP5, LNA 2 = 8dB */
697 (0 << 10) | 529, /* RF_RAMP6, LNA 2 */
698 (48 << 10) | 316, /* RF_RAMP7, LNA 3 = 6.8dB */
699 (0 << 10) | 400, /* RF_RAMP8, LNA 3 */
700 (29 << 10) | 176, /* GAIN_4_1, LNA 4 = 11.5dB */
701 (0 << 10) | 316, /* GAIN_4_2, LNA 4 */
702};
703
704static const u16 rf_ramp_pwm_uhf_8090[] = {
705 388, /* max RF gain in 10th of dB */
706 26, /* ramp_slope = 1dB of gain -> clock_ticks_per_db = clk_khz / ramp_slope -> RF_RAMP2 */
707 1008, /* ramp_max = maximum X used on the ramp */
708 (11 << 10) | 0, /* RF_RAMP3, LNA 1 = 14.7dB */
709 (0 << 10) | 369, /* RF_RAMP4, LNA 1 */
710 (41 << 10) | 809, /* RF_RAMP5, LNA 2 = 8dB */
711 (0 << 10) | 1008, /* RF_RAMP6, LNA 2 */
712 (27 << 10) | 659, /* RF_RAMP7, LNA 3 = 6dB */
713 (0 << 10) | 809, /* RF_RAMP8, LNA 3 */
714 (14 << 10) | 369, /* GAIN_4_1, LNA 4 = 11.5dB */
715 (0 << 10) | 659, /* GAIN_4_2, LNA 4 */
716};
717
Olivier Grenie03245a52009-12-04 13:27:57 -0300718static const u16 rf_ramp_pwm_cband[] = {
719 0, /* max RF gain in 10th of dB */
720 0, /* ramp_slope = 1dB of gain -> clock_ticks_per_db = clk_khz / ramp_slope -> 0x2b */
721 0, /* ramp_max = maximum X used on the ramp */
722 (0 << 10) | 0, /* 0x2c, LNA 1 = 0dB */
723 (0 << 10) | 0, /* 0x2d, LNA 1 */
724 (0 << 10) | 0, /* 0x2e, LNA 2 = 0dB */
725 (0 << 10) | 0, /* 0x2f, LNA 2 */
726 (0 << 10) | 0, /* 0x30, LNA 3 = 0dB */
727 (0 << 10) | 0, /* 0x31, LNA 3 */
728 (0 << 10) | 0, /* GAIN_4_1, LNA 4 = 0dB */
729 (0 << 10) | 0, /* GAIN_4_2, LNA 4 */
730};
731
732static const u16 rf_ramp_vhf[] = {
733 412, /* max RF gain in 10th of dB */
734 132, 307, 127, /* LNA1, 13.2dB */
735 105, 412, 255, /* LNA2, 10.5dB */
736 50, 50, 127, /* LNA3, 5dB */
737 125, 175, 127, /* LNA4, 12.5dB */
738 0, 0, 127, /* CBAND, 0dB */
739};
740
741static const u16 rf_ramp_uhf[] = {
742 412, /* max RF gain in 10th of dB */
743 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 */
744 105, 412, 255, /* LNA2 : 10.5 dB */
745 50, 50, 127, /* LNA3 : 5.0 dB */
746 125, 175, 127, /* LNA4 : 12.5 dB */
747 0, 0, 127, /* CBAND : 0.0 dB */
748};
749
Olivier Grenie28fafca2011-01-04 04:27:11 -0300750static const u16 rf_ramp_cband_broadmatching[] = /* for p1G only */
751{
752 314, /* Calibrated at 200MHz order has been changed g4-g3-g2-g1 */
753 84, 314, 127, /* LNA1 */
754 80, 230, 255, /* LNA2 */
755 80, 150, 127, /* LNA3 It was measured 12dB, do not lock if 120 */
756 70, 70, 127, /* LNA4 */
757 0, 0, 127, /* CBAND */
758};
759
Olivier Grenie03245a52009-12-04 13:27:57 -0300760static const u16 rf_ramp_cband[] = {
761 332, /* max RF gain in 10th of dB */
762 132, 252, 127, /* LNA1, dB */
763 80, 332, 255, /* LNA2, dB */
764 0, 0, 127, /* LNA3, dB */
765 0, 0, 127, /* LNA4, dB */
766 120, 120, 127, /* LT1 CBAND */
767};
768
769static const u16 rf_ramp_pwm_vhf[] = {
770 404, /* max RF gain in 10th of dB */
771 25, /* ramp_slope = 1dB of gain -> clock_ticks_per_db = clk_khz / ramp_slope -> 0x2b */
772 1011, /* ramp_max = maximum X used on the ramp */
773 (6 << 10) | 417, /* 0x2c, LNA 1 = 13.2dB */
774 (0 << 10) | 756, /* 0x2d, LNA 1 */
775 (16 << 10) | 756, /* 0x2e, LNA 2 = 10.5dB */
776 (0 << 10) | 1011, /* 0x2f, LNA 2 */
777 (16 << 10) | 290, /* 0x30, LNA 3 = 5dB */
778 (0 << 10) | 417, /* 0x31, LNA 3 */
779 (7 << 10) | 0, /* GAIN_4_1, LNA 4 = 12.5dB */
780 (0 << 10) | 290, /* GAIN_4_2, LNA 4 */
781};
782
783static const u16 rf_ramp_pwm_uhf[] = {
784 404, /* max RF gain in 10th of dB */
785 25, /* ramp_slope = 1dB of gain -> clock_ticks_per_db = clk_khz / ramp_slope -> 0x2b */
786 1011, /* ramp_max = maximum X used on the ramp */
787 (6 << 10) | 417, /* 0x2c, LNA 1 = 13.2dB */
788 (0 << 10) | 756, /* 0x2d, LNA 1 */
789 (16 << 10) | 756, /* 0x2e, LNA 2 = 10.5dB */
790 (0 << 10) | 1011, /* 0x2f, LNA 2 */
791 (16 << 10) | 0, /* 0x30, LNA 3 = 5dB */
792 (0 << 10) | 127, /* 0x31, LNA 3 */
793 (7 << 10) | 127, /* GAIN_4_1, LNA 4 = 12.5dB */
794 (0 << 10) | 417, /* GAIN_4_2, LNA 4 */
795};
796
797static const u16 bb_ramp_boost[] = {
798 550, /* max BB gain in 10th of dB */
799 260, 260, 26, /* BB1, 26dB */
800 290, 550, 29, /* BB2, 29dB */
801};
802
803static const u16 bb_ramp_pwm_normal[] = {
804 500, /* max RF gain in 10th of dB */
805 8, /* ramp_slope = 1dB of gain -> clock_ticks_per_db = clk_khz / ramp_slope -> 0x34 */
806 400,
807 (2 << 9) | 0, /* 0x35 = 21dB */
808 (0 << 9) | 168, /* 0x36 */
809 (2 << 9) | 168, /* 0x37 = 29dB */
810 (0 << 9) | 400, /* 0x38 */
811};
812
813struct slope {
Olivier Grenie28fafca2011-01-04 04:27:11 -0300814 s16 range;
815 s16 slope;
Olivier Grenie03245a52009-12-04 13:27:57 -0300816};
817static u16 slopes_to_scale(const struct slope *slopes, u8 num, s16 val)
818{
819 u8 i;
820 u16 rest;
821 u16 ret = 0;
822 for (i = 0; i < num; i++) {
823 if (val > slopes[i].range)
824 rest = slopes[i].range;
825 else
826 rest = val;
827 ret += (rest * slopes[i].slope) / slopes[i].range;
828 val -= rest;
829 }
830 return ret;
831}
832
833static const struct slope dib0090_wbd_slopes[3] = {
834 {66, 120}, /* -64,-52: offset - 65 */
835 {600, 170}, /* -52,-35: 65 - 665 */
836 {170, 250}, /* -45,-10: 665 - 835 */
837};
838
839static s16 dib0090_wbd_to_db(struct dib0090_state *state, u16 wbd)
840{
841 wbd &= 0x3ff;
842 if (wbd < state->wbd_offset)
843 wbd = 0;
844 else
845 wbd -= state->wbd_offset;
846 /* -64dB is the floor */
847 return -640 + (s16) slopes_to_scale(dib0090_wbd_slopes, ARRAY_SIZE(dib0090_wbd_slopes), wbd);
848}
849
850static void dib0090_wbd_target(struct dib0090_state *state, u32 rf)
851{
852 u16 offset = 250;
853
854 /* TODO : DAB digital N+/-1 interferer perfs : offset = 10 */
855
856 if (state->current_band == BAND_VHF)
857 offset = 650;
858#ifndef FIRMWARE_FIREFLY
859 if (state->current_band == BAND_VHF)
860 offset = state->config->wbd_vhf_offset;
861 if (state->current_band == BAND_CBAND)
862 offset = state->config->wbd_cband_offset;
863#endif
864
865 state->wbd_target = dib0090_wbd_to_db(state, state->wbd_offset + offset);
866 dprintk("wbd-target: %d dB", (u32) state->wbd_target);
867}
868
869static const int gain_reg_addr[4] = {
870 0x08, 0x0a, 0x0f, 0x01
871};
872
873static void dib0090_gain_apply(struct dib0090_state *state, s16 gain_delta, s16 top_delta, u8 force)
874{
875 u16 rf, bb, ref;
876 u16 i, v, gain_reg[4] = { 0 }, gain;
877 const u16 *g;
878
879 if (top_delta < -511)
880 top_delta = -511;
881 if (top_delta > 511)
882 top_delta = 511;
883
884 if (force) {
885 top_delta *= (1 << WBD_ALPHA);
886 gain_delta *= (1 << GAIN_ALPHA);
887 }
888
889 if (top_delta >= ((s16) (state->rf_ramp[0] << WBD_ALPHA) - state->rf_gain_limit)) /* overflow */
890 state->rf_gain_limit = state->rf_ramp[0] << WBD_ALPHA;
891 else
892 state->rf_gain_limit += top_delta;
893
894 if (state->rf_gain_limit < 0) /*underflow */
895 state->rf_gain_limit = 0;
896
897 /* use gain as a temporary variable and correct current_gain */
898 gain = ((state->rf_gain_limit >> WBD_ALPHA) + state->bb_ramp[0]) << GAIN_ALPHA;
899 if (gain_delta >= ((s16) gain - state->current_gain)) /* overflow */
900 state->current_gain = gain;
901 else
902 state->current_gain += gain_delta;
903 /* cannot be less than 0 (only if gain_delta is less than 0 we can have current_gain < 0) */
904 if (state->current_gain < 0)
905 state->current_gain = 0;
906
907 /* now split total gain to rf and bb gain */
908 gain = state->current_gain >> GAIN_ALPHA;
909
910 /* requested gain is bigger than rf gain limit - ACI/WBD adjustment */
911 if (gain > (state->rf_gain_limit >> WBD_ALPHA)) {
912 rf = state->rf_gain_limit >> WBD_ALPHA;
913 bb = gain - rf;
914 if (bb > state->bb_ramp[0])
915 bb = state->bb_ramp[0];
916 } else { /* high signal level -> all gains put on RF */
917 rf = gain;
918 bb = 0;
919 }
920
921 state->gain[0] = rf;
922 state->gain[1] = bb;
923
924 /* software ramp */
925 /* Start with RF gains */
926 g = state->rf_ramp + 1; /* point on RF LNA1 max gain */
927 ref = rf;
928 for (i = 0; i < 7; i++) { /* Go over all amplifiers => 5RF amps + 2 BB amps = 7 amps */
929 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 */
930 v = 0; /* force the gain to write for the current amp to be null */
931 else if (ref >= g[1]) /* Gain to set is higher than the high working point of this amp */
932 v = g[2]; /* force this amp to be full gain */
933 else /* compute the value to set to this amp because we are somewhere in his range */
934 v = ((ref - (g[1] - g[0])) * g[2]) / g[0];
935
936 if (i == 0) /* LNA 1 reg mapping */
937 gain_reg[0] = v;
938 else if (i == 1) /* LNA 2 reg mapping */
939 gain_reg[0] |= v << 7;
940 else if (i == 2) /* LNA 3 reg mapping */
941 gain_reg[1] = v;
942 else if (i == 3) /* LNA 4 reg mapping */
943 gain_reg[1] |= v << 7;
944 else if (i == 4) /* CBAND LNA reg mapping */
945 gain_reg[2] = v | state->rf_lt_def;
946 else if (i == 5) /* BB gain 1 reg mapping */
947 gain_reg[3] = v << 3;
948 else if (i == 6) /* BB gain 2 reg mapping */
949 gain_reg[3] |= v << 8;
950
951 g += 3; /* go to next gain bloc */
952
953 /* When RF is finished, start with BB */
954 if (i == 4) {
955 g = state->bb_ramp + 1; /* point on BB gain 1 max gain */
956 ref = bb;
957 }
958 }
959 gain_reg[3] |= state->bb_1_def;
960 gain_reg[3] |= ((bb % 10) * 100) / 125;
961
962#ifdef DEBUG_AGC
963 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,
964 gain_reg[0], gain_reg[1], gain_reg[2], gain_reg[3]);
965#endif
966
967 /* Write the amplifier regs */
968 for (i = 0; i < 4; i++) {
969 v = gain_reg[i];
970 if (force || state->gain_reg[i] != v) {
971 state->gain_reg[i] = v;
972 dib0090_write_reg(state, gain_reg_addr[i], v);
973 }
974 }
975}
976
977static void dib0090_set_boost(struct dib0090_state *state, int onoff)
978{
979 state->bb_1_def &= 0xdfff;
980 state->bb_1_def |= onoff << 13;
981}
982
983static void dib0090_set_rframp(struct dib0090_state *state, const u16 * cfg)
984{
985 state->rf_ramp = cfg;
986}
987
988static void dib0090_set_rframp_pwm(struct dib0090_state *state, const u16 * cfg)
989{
990 state->rf_ramp = cfg;
991
992 dib0090_write_reg(state, 0x2a, 0xffff);
993
994 dprintk("total RF gain: %ddB, step: %d", (u32) cfg[0], dib0090_read_reg(state, 0x2a));
995
996 dib0090_write_regs(state, 0x2c, cfg + 3, 6);
997 dib0090_write_regs(state, 0x3e, cfg + 9, 2);
998}
999
1000static void dib0090_set_bbramp(struct dib0090_state *state, const u16 * cfg)
1001{
1002 state->bb_ramp = cfg;
1003 dib0090_set_boost(state, cfg[0] > 500); /* we want the boost if the gain is higher that 50dB */
1004}
1005
1006static void dib0090_set_bbramp_pwm(struct dib0090_state *state, const u16 * cfg)
1007{
1008 state->bb_ramp = cfg;
1009
1010 dib0090_set_boost(state, cfg[0] > 500); /* we want the boost if the gain is higher that 50dB */
1011
1012 dib0090_write_reg(state, 0x33, 0xffff);
1013 dprintk("total BB gain: %ddB, step: %d", (u32) cfg[0], dib0090_read_reg(state, 0x33));
1014 dib0090_write_regs(state, 0x35, cfg + 3, 4);
1015}
1016
1017void dib0090_pwm_gain_reset(struct dvb_frontend *fe)
1018{
1019 struct dib0090_state *state = fe->tuner_priv;
1020 /* reset the AGC */
1021
1022 if (state->config->use_pwm_agc) {
1023#ifdef CONFIG_BAND_SBAND
1024 if (state->current_band == BAND_SBAND) {
1025 dib0090_set_rframp_pwm(state, rf_ramp_pwm_sband);
1026 dib0090_set_bbramp_pwm(state, bb_ramp_pwm_boost);
1027 } else
1028#endif
1029#ifdef CONFIG_BAND_CBAND
1030 if (state->current_band == BAND_CBAND) {
Olivier Grenie28fafca2011-01-04 04:27:11 -03001031 if (state->identity.in_soc) {
1032 dib0090_set_bbramp_pwm(state, bb_ramp_pwm_normal_socs);
1033 if (state->identity.version == SOC_8090_P1G_11R1 || state->identity.version == SOC_8090_P1G_21R1)
1034 dib0090_set_rframp_pwm(state, rf_ramp_pwm_cband_8090);
1035 else if (state->identity.version == SOC_7090_P1G_11R1 || state->identity.version == SOC_7090_P1G_21R1)
1036 dib0090_set_rframp_pwm(state, rf_ramp_pwm_cband_7090);
1037 } else {
1038 dib0090_set_rframp_pwm(state, rf_ramp_pwm_cband);
1039 dib0090_set_bbramp_pwm(state, bb_ramp_pwm_normal);
1040 }
Olivier Grenie03245a52009-12-04 13:27:57 -03001041 } else
1042#endif
1043#ifdef CONFIG_BAND_VHF
1044 if (state->current_band == BAND_VHF) {
Olivier Grenie28fafca2011-01-04 04:27:11 -03001045 if (state->identity.in_soc) {
1046 dib0090_set_bbramp_pwm(state, bb_ramp_pwm_normal_socs);
Olivier Grenie28fafca2011-01-04 04:27:11 -03001047 } else {
1048 dib0090_set_rframp_pwm(state, rf_ramp_pwm_vhf);
1049 dib0090_set_bbramp_pwm(state, bb_ramp_pwm_normal);
1050 }
Olivier Grenie03245a52009-12-04 13:27:57 -03001051 } else
1052#endif
1053 {
Olivier Grenie28fafca2011-01-04 04:27:11 -03001054 if (state->identity.in_soc) {
1055 if (state->identity.version == SOC_8090_P1G_11R1 || state->identity.version == SOC_8090_P1G_21R1)
1056 dib0090_set_rframp_pwm(state, rf_ramp_pwm_uhf_8090);
1057 else if (state->identity.version == SOC_7090_P1G_11R1 || state->identity.version == SOC_7090_P1G_21R1)
1058 dib0090_set_rframp_pwm(state, rf_ramp_pwm_uhf_7090);
1059 dib0090_set_bbramp_pwm(state, bb_ramp_pwm_normal_socs);
1060 } else {
1061 dib0090_set_rframp_pwm(state, rf_ramp_pwm_uhf);
1062 dib0090_set_bbramp_pwm(state, bb_ramp_pwm_normal);
1063 }
Olivier Grenie03245a52009-12-04 13:27:57 -03001064 }
1065
1066 if (state->rf_ramp[0] != 0)
1067 dib0090_write_reg(state, 0x32, (3 << 11));
1068 else
1069 dib0090_write_reg(state, 0x32, (0 << 11));
1070
Olivier Grenie28fafca2011-01-04 04:27:11 -03001071 dib0090_write_reg(state, 0x04, 0x01);
Olivier Grenie9c783032009-12-07 07:49:40 -03001072 dib0090_write_reg(state, 0x39, (1 << 10));
Olivier Grenie03245a52009-12-04 13:27:57 -03001073 }
1074}
Olivier Grenie28fafca2011-01-04 04:27:11 -03001075
Olivier Grenie03245a52009-12-04 13:27:57 -03001076EXPORT_SYMBOL(dib0090_pwm_gain_reset);
Olivier Grenie9c783032009-12-07 07:49:40 -03001077
Olivier Grenie28fafca2011-01-04 04:27:11 -03001078static u32 dib0090_get_slow_adc_val(struct dib0090_state *state)
1079{
1080 u16 adc_val = dib0090_read_reg(state, 0x1d);
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001081 if (state->identity.in_soc)
Olivier Grenie28fafca2011-01-04 04:27:11 -03001082 adc_val >>= 2;
Olivier Grenie28fafca2011-01-04 04:27:11 -03001083 return adc_val;
1084}
1085
Olivier Grenie03245a52009-12-04 13:27:57 -03001086int dib0090_gain_control(struct dvb_frontend *fe)
1087{
1088 struct dib0090_state *state = fe->tuner_priv;
1089 enum frontend_tune_state *tune_state = &state->tune_state;
1090 int ret = 10;
1091
1092 u16 wbd_val = 0;
1093 u8 apply_gain_immediatly = 1;
1094 s16 wbd_error = 0, adc_error = 0;
1095
1096 if (*tune_state == CT_AGC_START) {
1097 state->agc_freeze = 0;
1098 dib0090_write_reg(state, 0x04, 0x0);
1099
1100#ifdef CONFIG_BAND_SBAND
1101 if (state->current_band == BAND_SBAND) {
1102 dib0090_set_rframp(state, rf_ramp_sband);
1103 dib0090_set_bbramp(state, bb_ramp_boost);
1104 } else
1105#endif
1106#ifdef CONFIG_BAND_VHF
Olivier Grenie28fafca2011-01-04 04:27:11 -03001107 if (state->current_band == BAND_VHF && !state->identity.p1g) {
Olivier Grenie03245a52009-12-04 13:27:57 -03001108 dib0090_set_rframp(state, rf_ramp_vhf);
1109 dib0090_set_bbramp(state, bb_ramp_boost);
1110 } else
1111#endif
1112#ifdef CONFIG_BAND_CBAND
Olivier Grenie28fafca2011-01-04 04:27:11 -03001113 if (state->current_band == BAND_CBAND && !state->identity.p1g) {
Olivier Grenie03245a52009-12-04 13:27:57 -03001114 dib0090_set_rframp(state, rf_ramp_cband);
1115 dib0090_set_bbramp(state, bb_ramp_boost);
1116 } else
1117#endif
Olivier Grenie28fafca2011-01-04 04:27:11 -03001118 if ((state->current_band == BAND_CBAND || state->current_band == BAND_VHF) && state->identity.p1g) {
1119 dib0090_set_rframp(state, rf_ramp_cband_broadmatching);
1120 dib0090_set_bbramp(state, bb_ramp_boost);
1121 } else {
Olivier Grenie03245a52009-12-04 13:27:57 -03001122 dib0090_set_rframp(state, rf_ramp_uhf);
1123 dib0090_set_bbramp(state, bb_ramp_boost);
1124 }
1125
1126 dib0090_write_reg(state, 0x32, 0);
1127 dib0090_write_reg(state, 0x39, 0);
1128
1129 dib0090_wbd_target(state, state->current_rf);
1130
1131 state->rf_gain_limit = state->rf_ramp[0] << WBD_ALPHA;
1132 state->current_gain = ((state->rf_ramp[0] + state->bb_ramp[0]) / 2) << GAIN_ALPHA;
1133
1134 *tune_state = CT_AGC_STEP_0;
1135 } else if (!state->agc_freeze) {
Olivier Grenie28fafca2011-01-04 04:27:11 -03001136 s16 wbd = 0, i, cnt;
Olivier Grenie03245a52009-12-04 13:27:57 -03001137
1138 int adc;
Olivier Grenie28fafca2011-01-04 04:27:11 -03001139 wbd_val = dib0090_get_slow_adc_val(state);
Olivier Grenie03245a52009-12-04 13:27:57 -03001140
Olivier Grenie28fafca2011-01-04 04:27:11 -03001141 if (*tune_state == CT_AGC_STEP_0)
1142 cnt = 5;
1143 else
1144 cnt = 1;
1145
1146 for (i = 0; i < cnt; i++) {
1147 wbd_val = dib0090_get_slow_adc_val(state);
1148 wbd += dib0090_wbd_to_db(state, wbd_val);
1149 }
1150 wbd /= cnt;
Olivier Grenie03245a52009-12-04 13:27:57 -03001151 wbd_error = state->wbd_target - wbd;
1152
1153 if (*tune_state == CT_AGC_STEP_0) {
Olivier Grenie28fafca2011-01-04 04:27:11 -03001154 if (wbd_error < 0 && state->rf_gain_limit > 0 && !state->identity.p1g) {
Olivier Grenie03245a52009-12-04 13:27:57 -03001155#ifdef CONFIG_BAND_CBAND
1156 /* in case of CBAND tune reduce first the lt_gain2 before adjusting the RF gain */
1157 u8 ltg2 = (state->rf_lt_def >> 10) & 0x7;
1158 if (state->current_band == BAND_CBAND && ltg2) {
1159 ltg2 >>= 1;
1160 state->rf_lt_def &= ltg2 << 10; /* reduce in 3 steps from 7 to 0 */
1161 }
1162#endif
1163 } else {
1164 state->agc_step = 0;
1165 *tune_state = CT_AGC_STEP_1;
1166 }
1167 } else {
1168 /* calc the adc power */
1169 adc = state->config->get_adc_power(fe);
1170 adc = (adc * ((s32) 355774) + (((s32) 1) << 20)) >> 21; /* included in [0:-700] */
1171
1172 adc_error = (s16) (((s32) ADC_TARGET) - adc);
1173#ifdef CONFIG_STANDARD_DAB
1174 if (state->fe->dtv_property_cache.delivery_system == STANDARD_DAB)
Olivier Grenie28fafca2011-01-04 04:27:11 -03001175 adc_error -= 10;
Olivier Grenie03245a52009-12-04 13:27:57 -03001176#endif
1177#ifdef CONFIG_STANDARD_DVBT
1178 if (state->fe->dtv_property_cache.delivery_system == STANDARD_DVBT &&
Olivier Grenie28fafca2011-01-04 04:27:11 -03001179 (state->fe->dtv_property_cache.modulation == QAM_64 || state->fe->dtv_property_cache.modulation == QAM_16))
Olivier Grenie03245a52009-12-04 13:27:57 -03001180 adc_error += 60;
1181#endif
1182#ifdef CONFIG_SYS_ISDBT
1183 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 -03001184 0)
1185 &&
1186 ((state->fe->dtv_property_cache.layer[0].modulation ==
1187 QAM_64)
1188 || (state->fe->dtv_property_cache.
1189 layer[0].modulation == QAM_16)))
1190 ||
1191 ((state->fe->dtv_property_cache.layer[1].segment_count >
1192 0)
1193 &&
1194 ((state->fe->dtv_property_cache.layer[1].modulation ==
1195 QAM_64)
1196 || (state->fe->dtv_property_cache.
1197 layer[1].modulation == QAM_16)))
1198 ||
1199 ((state->fe->dtv_property_cache.layer[2].segment_count >
1200 0)
1201 &&
1202 ((state->fe->dtv_property_cache.layer[2].modulation ==
1203 QAM_64)
1204 || (state->fe->dtv_property_cache.
1205 layer[2].modulation == QAM_16)))
1206 )
1207 )
Olivier Grenie03245a52009-12-04 13:27:57 -03001208 adc_error += 60;
1209#endif
1210
1211 if (*tune_state == CT_AGC_STEP_1) { /* quickly go to the correct range of the ADC power */
1212 if (ABS(adc_error) < 50 || state->agc_step++ > 5) {
1213
1214#ifdef CONFIG_STANDARD_DAB
1215 if (state->fe->dtv_property_cache.delivery_system == STANDARD_DAB) {
1216 dib0090_write_reg(state, 0x02, (1 << 15) | (15 << 11) | (31 << 6) | (63)); /* cap value = 63 : narrow BB filter : Fc = 1.8MHz */
1217 dib0090_write_reg(state, 0x04, 0x0);
1218 } else
1219#endif
1220 {
1221 dib0090_write_reg(state, 0x02, (1 << 15) | (3 << 11) | (6 << 6) | (32));
1222 dib0090_write_reg(state, 0x04, 0x01); /*0 = 1KHz ; 1 = 150Hz ; 2 = 50Hz ; 3 = 50KHz ; 4 = servo fast */
1223 }
1224
1225 *tune_state = CT_AGC_STOP;
1226 }
1227 } else {
1228 /* everything higher than or equal to CT_AGC_STOP means tracking */
1229 ret = 100; /* 10ms interval */
1230 apply_gain_immediatly = 0;
1231 }
1232 }
1233#ifdef DEBUG_AGC
1234 dprintk
Olivier Grenie28fafca2011-01-04 04:27:11 -03001235 ("tune state %d, ADC = %3ddB (ADC err %3d) WBD %3ddB (WBD err %3d, WBD val SADC: %4d), RFGainLimit (TOP): %3d, signal: %3ddBm",
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001236 (u32) *tune_state, (u32) adc, (u32) adc_error, (u32) wbd, (u32) wbd_error, (u32) wbd_val,
Olivier Grenie28fafca2011-01-04 04:27:11 -03001237 (u32) state->rf_gain_limit >> WBD_ALPHA, (s32) 200 + adc - (state->current_gain >> GAIN_ALPHA));
Olivier Grenie03245a52009-12-04 13:27:57 -03001238#endif
1239 }
1240
1241 /* apply gain */
1242 if (!state->agc_freeze)
1243 dib0090_gain_apply(state, adc_error, wbd_error, apply_gain_immediatly);
1244 return ret;
1245}
Olivier Grenie28fafca2011-01-04 04:27:11 -03001246
Olivier Grenie03245a52009-12-04 13:27:57 -03001247EXPORT_SYMBOL(dib0090_gain_control);
Olivier Grenie9c783032009-12-07 07:49:40 -03001248
Olivier Grenie03245a52009-12-04 13:27:57 -03001249void dib0090_get_current_gain(struct dvb_frontend *fe, u16 * rf, u16 * bb, u16 * rf_gain_limit, u16 * rflt)
1250{
1251 struct dib0090_state *state = fe->tuner_priv;
1252 if (rf)
1253 *rf = state->gain[0];
1254 if (bb)
1255 *bb = state->gain[1];
1256 if (rf_gain_limit)
1257 *rf_gain_limit = state->rf_gain_limit;
1258 if (rflt)
1259 *rflt = (state->rf_lt_def >> 10) & 0x7;
1260}
Olivier Grenie28fafca2011-01-04 04:27:11 -03001261
Olivier Grenie03245a52009-12-04 13:27:57 -03001262EXPORT_SYMBOL(dib0090_get_current_gain);
Olivier Grenie9c783032009-12-07 07:49:40 -03001263
Olivier Grenie28fafca2011-01-04 04:27:11 -03001264u16 dib0090_get_wbd_offset(struct dvb_frontend *fe)
Olivier Grenie03245a52009-12-04 13:27:57 -03001265{
Olivier Grenie28fafca2011-01-04 04:27:11 -03001266 struct dib0090_state *state = fe->tuner_priv;
1267 u32 f_MHz = state->fe->dtv_property_cache.frequency / 1000000;
1268 s32 current_temp = state->temperature;
1269 s32 wbd_thot, wbd_tcold;
1270 const struct dib0090_wbd_slope *wbd = state->current_wbd_table;
1271
1272 while (f_MHz > wbd->max_freq)
1273 wbd++;
1274
1275 dprintk("using wbd-table-entry with max freq %d", wbd->max_freq);
1276
1277 if (current_temp < 0)
1278 current_temp = 0;
1279 if (current_temp > 128)
1280 current_temp = 128;
1281
Olivier Grenie28fafca2011-01-04 04:27:11 -03001282 state->wbdmux &= ~(7 << 13);
1283 if (wbd->wbd_gain != 0)
1284 state->wbdmux |= (wbd->wbd_gain << 13);
1285 else
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001286 state->wbdmux |= (4 << 13);
Olivier Grenie28fafca2011-01-04 04:27:11 -03001287
1288 dib0090_write_reg(state, 0x10, state->wbdmux);
1289
Olivier Grenie28fafca2011-01-04 04:27:11 -03001290 wbd_thot = wbd->offset_hot - (((u32) wbd->slope_hot * f_MHz) >> 6);
1291 wbd_tcold = wbd->offset_cold - (((u32) wbd->slope_cold * f_MHz) >> 6);
1292
Olivier Grenie28fafca2011-01-04 04:27:11 -03001293 wbd_tcold += ((wbd_thot - wbd_tcold) * current_temp) >> 7;
1294
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001295 state->wbd_target = dib0090_wbd_to_db(state, state->wbd_offset + wbd_tcold);
Olivier Grenie28fafca2011-01-04 04:27:11 -03001296 dprintk("wbd-target: %d dB", (u32) state->wbd_target);
1297 dprintk("wbd offset applied is %d", wbd_tcold);
1298
1299 return state->wbd_offset + wbd_tcold;
Olivier Grenie03245a52009-12-04 13:27:57 -03001300}
Olivier Grenie28fafca2011-01-04 04:27:11 -03001301
Olivier Grenie03245a52009-12-04 13:27:57 -03001302EXPORT_SYMBOL(dib0090_get_wbd_offset);
Olivier Grenie9c783032009-12-07 07:49:40 -03001303
Olivier Grenie03245a52009-12-04 13:27:57 -03001304static const u16 dib0090_defaults[] = {
1305
1306 25, 0x01,
1307 0x0000,
1308 0x99a0,
1309 0x6008,
1310 0x0000,
Olivier Grenie28fafca2011-01-04 04:27:11 -03001311 0x8bcb,
Olivier Grenie03245a52009-12-04 13:27:57 -03001312 0x0000,
1313 0x0405,
1314 0x0000,
1315 0x0000,
1316 0x0000,
1317 0xb802,
1318 0x0300,
1319 0x2d12,
1320 0xbac0,
1321 0x7c00,
1322 0xdbb9,
1323 0x0954,
1324 0x0743,
1325 0x8000,
1326 0x0001,
1327 0x0040,
1328 0x0100,
1329 0x0000,
1330 0xe910,
1331 0x149e,
1332
1333 1, 0x1c,
1334 0xff2d,
1335
1336 1, 0x39,
1337 0x0000,
1338
Olivier Grenie03245a52009-12-04 13:27:57 -03001339 2, 0x1e,
1340 0x07FF,
1341 0x0007,
1342
1343 1, 0x24,
1344 EN_UHF | EN_CRYSTAL,
1345
1346 2, 0x3c,
1347 0x3ff,
1348 0x111,
1349 0
1350};
1351
Olivier Grenie28fafca2011-01-04 04:27:11 -03001352static const u16 dib0090_p1g_additionnal_defaults[] = {
Olivier Grenie28fafca2011-01-04 04:27:11 -03001353 1, 0x05,
1354 0xabcd,
1355
1356 1, 0x11,
1357 0x00b4,
1358
1359 1, 0x1c,
1360 0xfffd,
1361
1362 1, 0x40,
1363 0x108,
1364 0
1365};
1366
1367static void dib0090_set_default_config(struct dib0090_state *state, const u16 * n)
Olivier Grenie03245a52009-12-04 13:27:57 -03001368{
Olivier Grenie28fafca2011-01-04 04:27:11 -03001369 u16 l, r;
Olivier Grenie03245a52009-12-04 13:27:57 -03001370
Olivier Grenie03245a52009-12-04 13:27:57 -03001371 l = pgm_read_word(n++);
1372 while (l) {
1373 r = pgm_read_word(n++);
1374 do {
Olivier Grenie03245a52009-12-04 13:27:57 -03001375 dib0090_write_reg(state, r, pgm_read_word(n++));
1376 r++;
1377 } while (--l);
1378 l = pgm_read_word(n++);
1379 }
Olivier Grenie28fafca2011-01-04 04:27:11 -03001380}
1381
1382#define CAP_VALUE_MIN (u8) 9
1383#define CAP_VALUE_MAX (u8) 40
1384#define HR_MIN (u8) 25
1385#define HR_MAX (u8) 40
1386#define POLY_MIN (u8) 0
1387#define POLY_MAX (u8) 8
1388
1389void dib0090_set_EFUSE(struct dib0090_state *state)
1390{
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001391 u8 c, h, n;
1392 u16 e2, e4;
1393 u16 cal;
Olivier Grenie28fafca2011-01-04 04:27:11 -03001394
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001395 e2 = dib0090_read_reg(state, 0x26);
1396 e4 = dib0090_read_reg(state, 0x28);
Olivier Grenie28fafca2011-01-04 04:27:11 -03001397
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001398 if ((state->identity.version == P1D_E_F) ||
1399 (state->identity.version == P1G) || (e2 == 0xffff)) {
Olivier Grenie28fafca2011-01-04 04:27:11 -03001400
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001401 dib0090_write_reg(state, 0x22, 0x10);
1402 cal = (dib0090_read_reg(state, 0x22) >> 6) & 0x3ff;
Olivier Grenie28fafca2011-01-04 04:27:11 -03001403
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001404 if ((cal < 670) || (cal == 1023))
1405 cal = 850;
1406 n = 165 - ((cal * 10)>>6) ;
1407 e2 = e4 = (3<<12) | (34<<6) | (n);
1408 }
Olivier Grenie28fafca2011-01-04 04:27:11 -03001409
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001410 if (e2 != e4)
1411 e2 &= e4; /* Remove the redundancy */
Olivier Grenie28fafca2011-01-04 04:27:11 -03001412
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001413 if (e2 != 0xffff) {
1414 c = e2 & 0x3f;
1415 n = (e2 >> 12) & 0xf;
1416 h = (e2 >> 6) & 0x3f;
Olivier Grenie28fafca2011-01-04 04:27:11 -03001417
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001418 if ((c >= CAP_VALUE_MAX) || (c <= CAP_VALUE_MIN))
1419 c = 32;
1420 if ((h >= HR_MAX) || (h <= HR_MIN))
1421 h = 34;
1422 if ((n >= POLY_MAX) || (n <= POLY_MIN))
1423 n = 3;
Olivier Grenie28fafca2011-01-04 04:27:11 -03001424
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001425 dib0090_write_reg(state, 0x13, (h << 10)) ;
1426 e2 = (n<<11) | ((h>>2)<<6) | (c);
1427 dib0090_write_reg(state, 0x2, e2) ; /* Load the BB_2 */
1428 }
Olivier Grenie28fafca2011-01-04 04:27:11 -03001429}
1430
1431static int dib0090_reset(struct dvb_frontend *fe)
1432{
1433 struct dib0090_state *state = fe->tuner_priv;
1434
1435 dib0090_reset_digital(fe, state->config);
1436 if (dib0090_identify(fe) < 0)
1437 return -EIO;
1438
1439#ifdef CONFIG_TUNER_DIB0090_P1B_SUPPORT
1440 if (!(state->identity.version & 0x1)) /* it is P1B - reset is already done */
1441 return 0;
1442#endif
1443
1444 if (!state->identity.in_soc) {
1445 if ((dib0090_read_reg(state, 0x1a) >> 5) & 0x2)
1446 dib0090_write_reg(state, 0x1b, (EN_IQADC | EN_BB | EN_BIAS | EN_DIGCLK | EN_PLL | EN_CRYSTAL));
1447 else
1448 dib0090_write_reg(state, 0x1b, (EN_DIGCLK | EN_PLL | EN_CRYSTAL));
1449 }
1450
1451 dib0090_set_default_config(state, dib0090_defaults);
1452
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001453 if (state->identity.in_soc)
1454 dib0090_write_reg(state, 0x18, 0x2910); /* charge pump current = 0 */
Olivier Grenie28fafca2011-01-04 04:27:11 -03001455
1456 if (state->identity.p1g)
1457 dib0090_set_default_config(state, dib0090_p1g_additionnal_defaults);
1458
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001459 /* Update the efuse : Only available for KROSUS > P1C and SOC as well*/
1460 if (((state->identity.version & 0x1f) >= P1D_E_F) || (state->identity.in_soc))
1461 dib0090_set_EFUSE(state);
Olivier Grenie03245a52009-12-04 13:27:57 -03001462
1463 /* Congigure in function of the crystal */
1464 if (state->config->io.clock_khz >= 24000)
Olivier Grenie28fafca2011-01-04 04:27:11 -03001465 dib0090_write_reg(state, 0x14, 1);
Olivier Grenie03245a52009-12-04 13:27:57 -03001466 else
Olivier Grenie28fafca2011-01-04 04:27:11 -03001467 dib0090_write_reg(state, 0x14, 2);
Olivier Grenie03245a52009-12-04 13:27:57 -03001468 dprintk("Pll lock : %d", (dib0090_read_reg(state, 0x1a) >> 11) & 0x1);
1469
Olivier Grenie28fafca2011-01-04 04:27:11 -03001470 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 -03001471
1472 return 0;
1473}
1474
Olivier Grenie9c783032009-12-07 07:49:40 -03001475#define steps(u) (((u) > 15) ? ((u)-16) : (u))
Olivier Grenie03245a52009-12-04 13:27:57 -03001476#define INTERN_WAIT 10
1477static int dib0090_get_offset(struct dib0090_state *state, enum frontend_tune_state *tune_state)
1478{
1479 int ret = INTERN_WAIT * 10;
1480
1481 switch (*tune_state) {
1482 case CT_TUNER_STEP_2:
1483 /* Turns to positive */
1484 dib0090_write_reg(state, 0x1f, 0x7);
1485 *tune_state = CT_TUNER_STEP_3;
1486 break;
1487
1488 case CT_TUNER_STEP_3:
1489 state->adc_diff = dib0090_read_reg(state, 0x1d);
1490
1491 /* Turns to negative */
1492 dib0090_write_reg(state, 0x1f, 0x4);
1493 *tune_state = CT_TUNER_STEP_4;
1494 break;
1495
1496 case CT_TUNER_STEP_4:
1497 state->adc_diff -= dib0090_read_reg(state, 0x1d);
1498 *tune_state = CT_TUNER_STEP_5;
1499 ret = 0;
1500 break;
1501
1502 default:
1503 break;
1504 }
1505
1506 return ret;
1507}
1508
1509struct dc_calibration {
Olivier Grenie28fafca2011-01-04 04:27:11 -03001510 u8 addr;
1511 u8 offset;
1512 u8 pga:1;
1513 u16 bb1;
1514 u8 i:1;
Olivier Grenie03245a52009-12-04 13:27:57 -03001515};
1516
1517static const struct dc_calibration dc_table[] = {
1518 /* Step1 BB gain1= 26 with boost 1, gain 2 = 0 */
1519 {0x06, 5, 1, (1 << 13) | (0 << 8) | (26 << 3), 1},
1520 {0x07, 11, 1, (1 << 13) | (0 << 8) | (26 << 3), 0},
1521 /* Step 2 BB gain 1 = 26 with boost = 1 & gain 2 = 29 */
1522 {0x06, 0, 0, (1 << 13) | (29 << 8) | (26 << 3), 1},
1523 {0x06, 10, 0, (1 << 13) | (29 << 8) | (26 << 3), 0},
1524 {0},
1525};
1526
Olivier Grenie28fafca2011-01-04 04:27:11 -03001527static const struct dc_calibration dc_p1g_table[] = {
1528 /* Step1 BB gain1= 26 with boost 1, gain 2 = 0 */
1529 /* addr ; trim reg offset ; pga ; CTRL_BB1 value ; i or q */
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001530 {0x06, 5, 1, (1 << 13) | (0 << 8) | (15 << 3), 1},
1531 {0x07, 11, 1, (1 << 13) | (0 << 8) | (15 << 3), 0},
Olivier Grenie28fafca2011-01-04 04:27:11 -03001532 /* Step 2 BB gain 1 = 26 with boost = 1 & gain 2 = 29 */
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001533 {0x06, 0, 0, (1 << 13) | (29 << 8) | (15 << 3), 1},
1534 {0x06, 10, 0, (1 << 13) | (29 << 8) | (15 << 3), 0},
Olivier Grenie28fafca2011-01-04 04:27:11 -03001535 {0},
1536};
1537
Olivier Grenie03245a52009-12-04 13:27:57 -03001538static void dib0090_set_trim(struct dib0090_state *state)
1539{
1540 u16 *val;
1541
1542 if (state->dc->addr == 0x07)
1543 val = &state->bb7;
1544 else
1545 val = &state->bb6;
1546
1547 *val &= ~(0x1f << state->dc->offset);
1548 *val |= state->step << state->dc->offset;
1549
1550 dib0090_write_reg(state, state->dc->addr, *val);
1551}
1552
1553static int dib0090_dc_offset_calibration(struct dib0090_state *state, enum frontend_tune_state *tune_state)
1554{
1555 int ret = 0;
Olivier Grenie28fafca2011-01-04 04:27:11 -03001556 u16 reg;
Olivier Grenie03245a52009-12-04 13:27:57 -03001557
1558 switch (*tune_state) {
Olivier Grenie03245a52009-12-04 13:27:57 -03001559 case CT_TUNER_START:
Olivier Grenie28fafca2011-01-04 04:27:11 -03001560 dprintk("Start DC offset calibration");
Olivier Grenie03245a52009-12-04 13:27:57 -03001561
1562 /* force vcm2 = 0.8V */
1563 state->bb6 = 0;
1564 state->bb7 = 0x040d;
1565
Olivier Grenie28fafca2011-01-04 04:27:11 -03001566 /* the LNA AND LO are off */
1567 reg = dib0090_read_reg(state, 0x24) & 0x0ffb; /* shutdown lna and lo */
1568 dib0090_write_reg(state, 0x24, reg);
1569
1570 state->wbdmux = dib0090_read_reg(state, 0x10);
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001571 dib0090_write_reg(state, 0x10, (state->wbdmux & ~(0xff << 3)) | (0x7 << 3) | 0x3);
1572 dib0090_write_reg(state, 0x23, dib0090_read_reg(state, 0x23) & ~(1 << 14));
Olivier Grenie28fafca2011-01-04 04:27:11 -03001573
Olivier Grenie03245a52009-12-04 13:27:57 -03001574 state->dc = dc_table;
1575
Olivier Grenie28fafca2011-01-04 04:27:11 -03001576 if (state->identity.p1g)
1577 state->dc = dc_p1g_table;
Olivier Grenie03245a52009-12-04 13:27:57 -03001578 *tune_state = CT_TUNER_STEP_0;
1579
1580 /* fall through */
1581
1582 case CT_TUNER_STEP_0:
Olivier Grenie28fafca2011-01-04 04:27:11 -03001583 dprintk("Sart/continue DC calibration for %s path", (state->dc->i == 1) ? "I" : "Q");
Olivier Grenie03245a52009-12-04 13:27:57 -03001584 dib0090_write_reg(state, 0x01, state->dc->bb1);
1585 dib0090_write_reg(state, 0x07, state->bb7 | (state->dc->i << 7));
1586
1587 state->step = 0;
Olivier Grenie03245a52009-12-04 13:27:57 -03001588 state->min_adc_diff = 1023;
Olivier Grenie03245a52009-12-04 13:27:57 -03001589 *tune_state = CT_TUNER_STEP_1;
1590 ret = 50;
1591 break;
1592
1593 case CT_TUNER_STEP_1:
1594 dib0090_set_trim(state);
Olivier Grenie03245a52009-12-04 13:27:57 -03001595 *tune_state = CT_TUNER_STEP_2;
1596 break;
1597
1598 case CT_TUNER_STEP_2:
1599 case CT_TUNER_STEP_3:
1600 case CT_TUNER_STEP_4:
1601 ret = dib0090_get_offset(state, tune_state);
1602 break;
1603
1604 case CT_TUNER_STEP_5: /* found an offset */
Olivier Grenie28fafca2011-01-04 04:27:11 -03001605 dprintk("adc_diff = %d, current step= %d", (u32) state->adc_diff, state->step);
1606 if (state->step == 0 && state->adc_diff < 0) {
1607 state->min_adc_diff = -1023;
1608 dprintk("Change of sign of the minimum adc diff");
1609 }
1610
1611 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 -03001612
1613 /* first turn for this frequency */
1614 if (state->step == 0) {
1615 if (state->dc->pga && state->adc_diff < 0)
1616 state->step = 0x10;
1617 if (state->dc->pga == 0 && state->adc_diff > 0)
1618 state->step = 0x10;
1619 }
1620
Olivier Grenie28fafca2011-01-04 04:27:11 -03001621 /* Look for a change of Sign in the Adc_diff.min_adc_diff is used to STORE the setp N-1 */
1622 if ((state->adc_diff & 0x8000) == (state->min_adc_diff & 0x8000) && steps(state->step) < 15) {
1623 /* 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 -03001624 state->step++;
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001625 state->min_adc_diff = state->adc_diff;
Olivier Grenie03245a52009-12-04 13:27:57 -03001626 *tune_state = CT_TUNER_STEP_1;
1627 } else {
Olivier Grenie03245a52009-12-04 13:27:57 -03001628 /* the minimum was what we have seen in the step before */
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001629 if (ABS(state->adc_diff) > ABS(state->min_adc_diff)) {
Olivier Grenie28fafca2011-01-04 04:27:11 -03001630 dprintk("Since adc_diff N = %d > adc_diff step N-1 = %d, Come back one step", state->adc_diff, state->min_adc_diff);
1631 state->step--;
1632 }
Olivier Grenie03245a52009-12-04 13:27:57 -03001633
Olivier Grenie28fafca2011-01-04 04:27:11 -03001634 dib0090_set_trim(state);
1635 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 -03001636
1637 state->dc++;
1638 if (state->dc->addr == 0) /* done */
1639 *tune_state = CT_TUNER_STEP_6;
1640 else
1641 *tune_state = CT_TUNER_STEP_0;
1642
1643 }
1644 break;
1645
1646 case CT_TUNER_STEP_6:
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001647 dib0090_write_reg(state, 0x07, state->bb7 & ~0x0008);
Olivier Grenie03245a52009-12-04 13:27:57 -03001648 dib0090_write_reg(state, 0x1f, 0x7);
1649 *tune_state = CT_TUNER_START; /* reset done -> real tuning can now begin */
Olivier Grenie28fafca2011-01-04 04:27:11 -03001650 state->calibrate &= ~DC_CAL;
Olivier Grenie03245a52009-12-04 13:27:57 -03001651 default:
1652 break;
1653 }
1654 return ret;
1655}
1656
1657static int dib0090_wbd_calibration(struct dib0090_state *state, enum frontend_tune_state *tune_state)
1658{
Olivier Grenie28fafca2011-01-04 04:27:11 -03001659 u8 wbd_gain;
1660 const struct dib0090_wbd_slope *wbd = state->current_wbd_table;
1661
Olivier Grenie03245a52009-12-04 13:27:57 -03001662 switch (*tune_state) {
1663 case CT_TUNER_START:
Olivier Grenie28fafca2011-01-04 04:27:11 -03001664 while (state->current_rf / 1000 > wbd->max_freq)
1665 wbd++;
1666 if (wbd->wbd_gain != 0)
1667 wbd_gain = wbd->wbd_gain;
1668 else {
1669 wbd_gain = 4;
1670#if defined(CONFIG_BAND_LBAND) || defined(CONFIG_BAND_SBAND)
1671 if ((state->current_band == BAND_LBAND) || (state->current_band == BAND_SBAND))
1672 wbd_gain = 2;
1673#endif
1674 }
Olivier Grenie03245a52009-12-04 13:27:57 -03001675
Olivier Grenie28fafca2011-01-04 04:27:11 -03001676 if (wbd_gain == state->wbd_calibration_gain) { /* the WBD calibration has already been done */
1677 *tune_state = CT_TUNER_START;
1678 state->calibrate &= ~WBD_CAL;
1679 return 0;
1680 }
1681
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001682 dib0090_write_reg(state, 0x10, 0x1b81 | (1 << 10) | (wbd_gain << 13) | (1 << 3));
Olivier Grenie28fafca2011-01-04 04:27:11 -03001683
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001684 dib0090_write_reg(state, 0x24, ((EN_UHF & 0x0fff) | (1 << 1)));
Olivier Grenie03245a52009-12-04 13:27:57 -03001685 *tune_state = CT_TUNER_STEP_0;
Olivier Grenie28fafca2011-01-04 04:27:11 -03001686 state->wbd_calibration_gain = wbd_gain;
Olivier Grenie03245a52009-12-04 13:27:57 -03001687 return 90; /* wait for the WBDMUX to switch and for the ADC to sample */
Olivier Grenie03245a52009-12-04 13:27:57 -03001688
Olivier Grenie28fafca2011-01-04 04:27:11 -03001689 case CT_TUNER_STEP_0:
1690 state->wbd_offset = dib0090_get_slow_adc_val(state);
1691 dprintk("WBD calibration offset = %d", state->wbd_offset);
Olivier Grenie03245a52009-12-04 13:27:57 -03001692 *tune_state = CT_TUNER_START; /* reset done -> real tuning can now begin */
Olivier Grenie28fafca2011-01-04 04:27:11 -03001693 state->calibrate &= ~WBD_CAL;
Olivier Grenie03245a52009-12-04 13:27:57 -03001694 break;
Olivier Grenie28fafca2011-01-04 04:27:11 -03001695
Olivier Grenie03245a52009-12-04 13:27:57 -03001696 default:
1697 break;
1698 }
1699 return 0;
1700}
1701
1702static void dib0090_set_bandwidth(struct dib0090_state *state)
1703{
1704 u16 tmp;
1705
1706 if (state->fe->dtv_property_cache.bandwidth_hz / 1000 <= 5000)
1707 tmp = (3 << 14);
1708 else if (state->fe->dtv_property_cache.bandwidth_hz / 1000 <= 6000)
1709 tmp = (2 << 14);
1710 else if (state->fe->dtv_property_cache.bandwidth_hz / 1000 <= 7000)
1711 tmp = (1 << 14);
1712 else
1713 tmp = (0 << 14);
1714
1715 state->bb_1_def &= 0x3fff;
1716 state->bb_1_def |= tmp;
1717
1718 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 -03001719
1720 dib0090_write_reg(state, 0x03, 0x6008); /* = 0x6008 : vcm3_trim = 1 ; filter2_gm1_trim = 8 ; filter2_cutoff_freq = 0 */
1721 dib0090_write_reg(state, 0x04, 0x1); /* 0 = 1KHz ; 1 = 50Hz ; 2 = 150Hz ; 3 = 50KHz ; 4 = servo fast */
1722 if (state->identity.in_soc) {
1723 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 */
1724 } else {
1725 dib0090_write_reg(state, 0x02, (5 << 11) | (8 << 6) | (22 & 0x3f)); /* 22 = cap_value */
1726 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 */
1727 }
Olivier Grenie03245a52009-12-04 13:27:57 -03001728}
1729
1730static const struct dib0090_pll dib0090_pll_table[] = {
1731#ifdef CONFIG_BAND_CBAND
1732 {56000, 0, 9, 48, 6},
1733 {70000, 1, 9, 48, 6},
1734 {87000, 0, 8, 32, 4},
1735 {105000, 1, 8, 32, 4},
1736 {115000, 0, 7, 24, 6},
1737 {140000, 1, 7, 24, 6},
1738 {170000, 0, 6, 16, 4},
1739#endif
1740#ifdef CONFIG_BAND_VHF
1741 {200000, 1, 6, 16, 4},
1742 {230000, 0, 5, 12, 6},
1743 {280000, 1, 5, 12, 6},
1744 {340000, 0, 4, 8, 4},
1745 {380000, 1, 4, 8, 4},
1746 {450000, 0, 3, 6, 6},
1747#endif
1748#ifdef CONFIG_BAND_UHF
1749 {580000, 1, 3, 6, 6},
1750 {700000, 0, 2, 4, 4},
1751 {860000, 1, 2, 4, 4},
1752#endif
1753#ifdef CONFIG_BAND_LBAND
1754 {1800000, 1, 0, 2, 4},
1755#endif
1756#ifdef CONFIG_BAND_SBAND
1757 {2900000, 0, 14, 1, 4},
1758#endif
1759};
1760
1761static const struct dib0090_tuning dib0090_tuning_table_fm_vhf_on_cband[] = {
1762
1763#ifdef CONFIG_BAND_CBAND
1764 {184000, 4, 1, 15, 0x280, 0x2912, 0xb94e, EN_CAB},
1765 {227000, 4, 3, 15, 0x280, 0x2912, 0xb94e, EN_CAB},
1766 {380000, 4, 7, 15, 0x280, 0x2912, 0xb94e, EN_CAB},
1767#endif
1768#ifdef CONFIG_BAND_UHF
1769 {520000, 2, 0, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},
1770 {550000, 2, 2, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},
1771 {650000, 2, 3, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},
1772 {750000, 2, 5, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},
1773 {850000, 2, 6, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},
1774 {900000, 2, 7, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},
1775#endif
1776#ifdef CONFIG_BAND_LBAND
1777 {1500000, 4, 0, 20, 0x300, 0x1912, 0x82c9, EN_LBD},
1778 {1600000, 4, 1, 20, 0x300, 0x1912, 0x82c9, EN_LBD},
1779 {1800000, 4, 3, 20, 0x300, 0x1912, 0x82c9, EN_LBD},
1780#endif
1781#ifdef CONFIG_BAND_SBAND
1782 {2300000, 1, 4, 20, 0x300, 0x2d2A, 0x82c7, EN_SBD},
1783 {2900000, 1, 7, 20, 0x280, 0x2deb, 0x8347, EN_SBD},
1784#endif
1785};
1786
1787static const struct dib0090_tuning dib0090_tuning_table[] = {
1788
1789#ifdef CONFIG_BAND_CBAND
1790 {170000, 4, 1, 15, 0x280, 0x2912, 0xb94e, EN_CAB},
1791#endif
1792#ifdef CONFIG_BAND_VHF
1793 {184000, 1, 1, 15, 0x300, 0x4d12, 0xb94e, EN_VHF},
1794 {227000, 1, 3, 15, 0x300, 0x4d12, 0xb94e, EN_VHF},
1795 {380000, 1, 7, 15, 0x300, 0x4d12, 0xb94e, EN_VHF},
1796#endif
1797#ifdef CONFIG_BAND_UHF
1798 {520000, 2, 0, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},
1799 {550000, 2, 2, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},
1800 {650000, 2, 3, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},
1801 {750000, 2, 5, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},
1802 {850000, 2, 6, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},
1803 {900000, 2, 7, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},
1804#endif
1805#ifdef CONFIG_BAND_LBAND
1806 {1500000, 4, 0, 20, 0x300, 0x1912, 0x82c9, EN_LBD},
1807 {1600000, 4, 1, 20, 0x300, 0x1912, 0x82c9, EN_LBD},
1808 {1800000, 4, 3, 20, 0x300, 0x1912, 0x82c9, EN_LBD},
1809#endif
1810#ifdef CONFIG_BAND_SBAND
1811 {2300000, 1, 4, 20, 0x300, 0x2d2A, 0x82c7, EN_SBD},
1812 {2900000, 1, 7, 20, 0x280, 0x2deb, 0x8347, EN_SBD},
1813#endif
1814};
1815
Olivier Grenie28fafca2011-01-04 04:27:11 -03001816static const struct dib0090_tuning dib0090_p1g_tuning_table[] = {
Olivier Grenie28fafca2011-01-04 04:27:11 -03001817#ifdef CONFIG_BAND_CBAND
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001818 {170000, 4, 1, 0x820f, 0x300, 0x2d22, 0x82cb, EN_CAB},
Olivier Grenie28fafca2011-01-04 04:27:11 -03001819#endif
1820#ifdef CONFIG_BAND_VHF
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001821 {184000, 1, 1, 15, 0x300, 0x4d12, 0xb94e, EN_VHF},
1822 {227000, 1, 3, 15, 0x300, 0x4d12, 0xb94e, EN_VHF},
1823 {380000, 1, 7, 15, 0x300, 0x4d12, 0xb94e, EN_VHF},
Olivier Grenie28fafca2011-01-04 04:27:11 -03001824#endif
1825#ifdef CONFIG_BAND_UHF
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001826 {510000, 2, 0, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},
1827 {540000, 2, 1, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},
1828 {600000, 2, 3, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},
1829 {630000, 2, 4, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},
1830 {680000, 2, 5, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},
1831 {720000, 2, 6, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},
1832 {900000, 2, 7, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},
Olivier Grenie28fafca2011-01-04 04:27:11 -03001833#endif
1834#ifdef CONFIG_BAND_LBAND
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001835 {1500000, 4, 0, 20, 0x300, 0x1912, 0x82c9, EN_LBD},
1836 {1600000, 4, 1, 20, 0x300, 0x1912, 0x82c9, EN_LBD},
1837 {1800000, 4, 3, 20, 0x300, 0x1912, 0x82c9, EN_LBD},
Olivier Grenie28fafca2011-01-04 04:27:11 -03001838#endif
1839#ifdef CONFIG_BAND_SBAND
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001840 {2300000, 1, 4, 20, 0x300, 0x2d2A, 0x82c7, EN_SBD},
1841 {2900000, 1, 7, 20, 0x280, 0x2deb, 0x8347, EN_SBD},
Olivier Grenie28fafca2011-01-04 04:27:11 -03001842#endif
1843};
1844
1845static const struct dib0090_pll dib0090_p1g_pll_table[] = {
1846#ifdef CONFIG_BAND_CBAND
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001847 {57000, 0, 11, 48, 6},
1848 {70000, 1, 11, 48, 6},
1849 {86000, 0, 10, 32, 4},
1850 {105000, 1, 10, 32, 4},
1851 {115000, 0, 9, 24, 6},
1852 {140000, 1, 9, 24, 6},
1853 {170000, 0, 8, 16, 4},
Olivier Grenie28fafca2011-01-04 04:27:11 -03001854#endif
1855#ifdef CONFIG_BAND_VHF
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001856 {200000, 1, 8, 16, 4},
1857 {230000, 0, 7, 12, 6},
1858 {280000, 1, 7, 12, 6},
1859 {340000, 0, 6, 8, 4},
1860 {380000, 1, 6, 8, 4},
1861 {455000, 0, 5, 6, 6},
Olivier Grenie28fafca2011-01-04 04:27:11 -03001862#endif
1863#ifdef CONFIG_BAND_UHF
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001864 {580000, 1, 5, 6, 6},
1865 {680000, 0, 4, 4, 4},
1866 {860000, 1, 4, 4, 4},
Olivier Grenie28fafca2011-01-04 04:27:11 -03001867#endif
1868#ifdef CONFIG_BAND_LBAND
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001869 {1800000, 1, 2, 2, 4},
Olivier Grenie28fafca2011-01-04 04:27:11 -03001870#endif
1871#ifdef CONFIG_BAND_SBAND
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001872 {2900000, 0, 1, 1, 6},
Olivier Grenie28fafca2011-01-04 04:27:11 -03001873#endif
1874};
1875
1876static const struct dib0090_tuning dib0090_p1g_tuning_table_fm_vhf_on_cband[] = {
Olivier Grenie28fafca2011-01-04 04:27:11 -03001877#ifdef CONFIG_BAND_CBAND
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001878 {184000, 4, 3, 0x4187, 0x2c0, 0x2d22, 0x81cb, EN_CAB},
1879 {227000, 4, 3, 0x4187, 0x2c0, 0x2d22, 0x81cb, EN_CAB},
1880 {380000, 4, 3, 0x4187, 0x2c0, 0x2d22, 0x81cb, EN_CAB},
Olivier Grenie28fafca2011-01-04 04:27:11 -03001881#endif
1882#ifdef CONFIG_BAND_UHF
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001883 {520000, 2, 0, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},
1884 {550000, 2, 2, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},
1885 {650000, 2, 3, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},
1886 {750000, 2, 5, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},
1887 {850000, 2, 6, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},
1888 {900000, 2, 7, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},
Olivier Grenie28fafca2011-01-04 04:27:11 -03001889#endif
1890#ifdef CONFIG_BAND_LBAND
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001891 {1500000, 4, 0, 20, 0x300, 0x1912, 0x82c9, EN_LBD},
1892 {1600000, 4, 1, 20, 0x300, 0x1912, 0x82c9, EN_LBD},
1893 {1800000, 4, 3, 20, 0x300, 0x1912, 0x82c9, EN_LBD},
Olivier Grenie28fafca2011-01-04 04:27:11 -03001894#endif
1895#ifdef CONFIG_BAND_SBAND
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001896 {2300000, 1, 4, 20, 0x300, 0x2d2A, 0x82c7, EN_SBD},
1897 {2900000, 1, 7, 20, 0x280, 0x2deb, 0x8347, EN_SBD},
Olivier Grenie28fafca2011-01-04 04:27:11 -03001898#endif
1899};
1900
1901static const struct dib0090_tuning dib0090_tuning_table_cband_7090[] = {
Olivier Grenie28fafca2011-01-04 04:27:11 -03001902#ifdef CONFIG_BAND_CBAND
Olivier Grenie28fafca2011-01-04 04:27:11 -03001903 {300000, 4, 3, 0x018F, 0x2c0, 0x2d22, 0xb9ce, EN_CAB},
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001904 {380000, 4, 10, 0x018F, 0x2c0, 0x2d22, 0xb9ce, EN_CAB},
Olivier Grenie28fafca2011-01-04 04:27:11 -03001905 {570000, 4, 10, 0x8190, 0x2c0, 0x2d22, 0xb9ce, EN_CAB},
1906 {858000, 4, 5, 0x8190, 0x2c0, 0x2d22, 0xb9ce, EN_CAB},
1907#endif
1908};
1909
1910static int dib0090_captrim_search(struct dib0090_state *state, enum frontend_tune_state *tune_state)
1911{
1912 int ret = 0;
1913 u16 lo4 = 0xe900;
1914
1915 s16 adc_target;
1916 u16 adc;
1917 s8 step_sign;
1918 u8 force_soft_search = 0;
1919
1920 if (state->identity.version == SOC_8090_P1G_11R1 || state->identity.version == SOC_8090_P1G_21R1)
1921 force_soft_search = 1;
1922
1923 if (*tune_state == CT_TUNER_START) {
1924 dprintk("Start Captrim search : %s", (force_soft_search == 1) ? "FORCE SOFT SEARCH" : "AUTO");
1925 dib0090_write_reg(state, 0x10, 0x2B1);
1926 dib0090_write_reg(state, 0x1e, 0x0032);
1927
1928 if (!state->tuner_is_tuned) {
1929 /* prepare a complete captrim */
1930 if (!state->identity.p1g || force_soft_search)
1931 state->step = state->captrim = state->fcaptrim = 64;
1932
1933 state->current_rf = state->rf_request;
1934 } else { /* we are already tuned to this frequency - the configuration is correct */
1935 if (!state->identity.p1g || force_soft_search) {
1936 /* do a minimal captrim even if the frequency has not changed */
1937 state->step = 4;
1938 state->captrim = state->fcaptrim = dib0090_read_reg(state, 0x18) & 0x7f;
1939 }
1940 }
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001941 state->adc_diff = 3000;
Olivier Grenie28fafca2011-01-04 04:27:11 -03001942 *tune_state = CT_TUNER_STEP_0;
1943
1944 } else if (*tune_state == CT_TUNER_STEP_0) {
1945 if (state->identity.p1g && !force_soft_search) {
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001946 u8 ratio = 31;
Olivier Grenie28fafca2011-01-04 04:27:11 -03001947
1948 dib0090_write_reg(state, 0x40, (3 << 7) | (ratio << 2) | (1 << 1) | 1);
1949 dib0090_read_reg(state, 0x40);
Olivier Grenie28fafca2011-01-04 04:27:11 -03001950 ret = 50;
1951 } else {
1952 state->step /= 2;
1953 dib0090_write_reg(state, 0x18, lo4 | state->captrim);
1954
1955 if (state->identity.in_soc)
1956 ret = 25;
1957 }
1958 *tune_state = CT_TUNER_STEP_1;
1959
1960 } else if (*tune_state == CT_TUNER_STEP_1) {
1961 if (state->identity.p1g && !force_soft_search) {
1962 dib0090_write_reg(state, 0x40, 0x18c | (0 << 1) | 0);
1963 dib0090_read_reg(state, 0x40);
1964
1965 state->fcaptrim = dib0090_read_reg(state, 0x18) & 0x7F;
1966 dprintk("***Final Captrim= 0x%x", state->fcaptrim);
1967 *tune_state = CT_TUNER_STEP_3;
1968
1969 } else {
1970 /* MERGE for all krosus before P1G */
1971 adc = dib0090_get_slow_adc_val(state);
1972 dprintk("CAPTRIM=%d; ADC = %d (ADC) & %dmV", (u32) state->captrim, (u32) adc, (u32) (adc) * (u32) 1800 / (u32) 1024);
1973
1974 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 !!! */
1975 adc_target = 200;
1976 } else
1977 adc_target = 400;
1978
1979 if (adc >= adc_target) {
1980 adc -= adc_target;
1981 step_sign = -1;
1982 } else {
1983 adc = adc_target - adc;
1984 step_sign = 1;
1985 }
1986
1987 if (adc < state->adc_diff) {
1988 dprintk("CAPTRIM=%d is closer to target (%d/%d)", (u32) state->captrim, (u32) adc, (u32) state->adc_diff);
1989 state->adc_diff = adc;
1990 state->fcaptrim = state->captrim;
Olivier Grenie28fafca2011-01-04 04:27:11 -03001991 }
1992
1993 state->captrim += step_sign * state->step;
1994 if (state->step >= 1)
1995 *tune_state = CT_TUNER_STEP_0;
1996 else
1997 *tune_state = CT_TUNER_STEP_2;
1998
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001999 ret = 25;
Olivier Grenie28fafca2011-01-04 04:27:11 -03002000 }
2001 } else if (*tune_state == CT_TUNER_STEP_2) { /* this step is only used by krosus < P1G */
2002 /*write the final cptrim config */
2003 dib0090_write_reg(state, 0x18, lo4 | state->fcaptrim);
2004
2005 *tune_state = CT_TUNER_STEP_3;
2006
2007 } else if (*tune_state == CT_TUNER_STEP_3) {
2008 state->calibrate &= ~CAPTRIM_CAL;
2009 *tune_state = CT_TUNER_STEP_0;
2010 }
2011
2012 return ret;
2013}
2014
2015static int dib0090_get_temperature(struct dib0090_state *state, enum frontend_tune_state *tune_state)
2016{
2017 int ret = 15;
2018 s16 val;
2019
Olivier Grenie28fafca2011-01-04 04:27:11 -03002020 switch (*tune_state) {
2021 case CT_TUNER_START:
2022 state->wbdmux = dib0090_read_reg(state, 0x10);
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002023 dib0090_write_reg(state, 0x10, (state->wbdmux & ~(0xff << 3)) | (0x8 << 3));
Olivier Grenie28fafca2011-01-04 04:27:11 -03002024
2025 state->bias = dib0090_read_reg(state, 0x13);
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002026 dib0090_write_reg(state, 0x13, state->bias | (0x3 << 8));
Olivier Grenie28fafca2011-01-04 04:27:11 -03002027
2028 *tune_state = CT_TUNER_STEP_0;
2029 /* wait for the WBDMUX to switch and for the ADC to sample */
2030 break;
2031
2032 case CT_TUNER_STEP_0:
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002033 state->adc_diff = dib0090_get_slow_adc_val(state);
2034 dib0090_write_reg(state, 0x13, (state->bias & ~(0x3 << 8)) | (0x2 << 8));
Olivier Grenie28fafca2011-01-04 04:27:11 -03002035 *tune_state = CT_TUNER_STEP_1;
2036 break;
2037
2038 case CT_TUNER_STEP_1:
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002039 val = dib0090_get_slow_adc_val(state);
2040 state->temperature = ((s16) ((val - state->adc_diff) * 180) >> 8) + 55;
Olivier Grenie28fafca2011-01-04 04:27:11 -03002041
2042 dprintk("temperature: %d C", state->temperature - 30);
2043
2044 *tune_state = CT_TUNER_STEP_2;
2045 break;
2046
2047 case CT_TUNER_STEP_2:
Olivier Grenie28fafca2011-01-04 04:27:11 -03002048 dib0090_write_reg(state, 0x13, state->bias);
2049 dib0090_write_reg(state, 0x10, state->wbdmux); /* write back original WBDMUX */
2050
2051 *tune_state = CT_TUNER_START;
2052 state->calibrate &= ~TEMP_CAL;
2053 if (state->config->analog_output == 0)
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002054 dib0090_write_reg(state, 0x23, dib0090_read_reg(state, 0x23) | (1 << 14));
Olivier Grenie28fafca2011-01-04 04:27:11 -03002055
2056 break;
2057
2058 default:
2059 ret = 0;
2060 break;
2061 }
2062 return ret;
2063}
2064
Olivier Grenie03245a52009-12-04 13:27:57 -03002065#define WBD 0x781 /* 1 1 1 1 0000 0 0 1 */
2066static int dib0090_tune(struct dvb_frontend *fe)
2067{
2068 struct dib0090_state *state = fe->tuner_priv;
2069 const struct dib0090_tuning *tune = state->current_tune_table_index;
2070 const struct dib0090_pll *pll = state->current_pll_table_index;
2071 enum frontend_tune_state *tune_state = &state->tune_state;
2072
Olivier Grenie28fafca2011-01-04 04:27:11 -03002073 u16 lo5, lo6, Den, tmp;
Olivier Grenie03245a52009-12-04 13:27:57 -03002074 u32 FBDiv, Rest, FREF, VCOF_kHz = 0;
Olivier Grenie03245a52009-12-04 13:27:57 -03002075 int ret = 10; /* 1ms is the default delay most of the time */
2076 u8 c, i;
2077
Olivier Grenie28fafca2011-01-04 04:27:11 -03002078 /************************* VCO ***************************/
Olivier Grenie03245a52009-12-04 13:27:57 -03002079 /* Default values for FG */
2080 /* from these are needed : */
2081 /* Cp,HFdiv,VCOband,SD,Num,Den,FB and REFDiv */
2082
Olivier Grenie28fafca2011-01-04 04:27:11 -03002083 /* in any case we first need to do a calibration if needed */
2084 if (*tune_state == CT_TUNER_START) {
2085 /* deactivate DataTX before some calibrations */
2086 if (state->calibrate & (DC_CAL | TEMP_CAL | WBD_CAL))
2087 dib0090_write_reg(state, 0x23, dib0090_read_reg(state, 0x23) & ~(1 << 14));
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002088 else
2089 /* Activate DataTX in case a calibration has been done before */
2090 if (state->config->analog_output == 0)
2091 dib0090_write_reg(state, 0x23, dib0090_read_reg(state, 0x23) | (1 << 14));
Olivier Grenie03245a52009-12-04 13:27:57 -03002092 }
2093
Olivier Grenie28fafca2011-01-04 04:27:11 -03002094 if (state->calibrate & DC_CAL)
2095 return dib0090_dc_offset_calibration(state, tune_state);
2096 else if (state->calibrate & WBD_CAL) {
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002097 if (state->current_rf == 0)
Olivier Grenie28fafca2011-01-04 04:27:11 -03002098 state->current_rf = state->fe->dtv_property_cache.frequency / 1000;
Olivier Grenie28fafca2011-01-04 04:27:11 -03002099 return dib0090_wbd_calibration(state, tune_state);
2100 } else if (state->calibrate & TEMP_CAL)
2101 return dib0090_get_temperature(state, tune_state);
2102 else if (state->calibrate & CAPTRIM_CAL)
2103 return dib0090_captrim_search(state, tune_state);
2104
Olivier Grenie03245a52009-12-04 13:27:57 -03002105 if (*tune_state == CT_TUNER_START) {
Olivier Grenie28fafca2011-01-04 04:27:11 -03002106 /* 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 */
2107 if (state->config->use_pwm_agc && state->identity.in_soc) {
2108 tmp = dib0090_read_reg(state, 0x39);
2109 if ((tmp >> 10) & 0x1)
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002110 dib0090_write_reg(state, 0x39, tmp & ~(1 << 10));
Olivier Grenie28fafca2011-01-04 04:27:11 -03002111 }
Olivier Grenie03245a52009-12-04 13:27:57 -03002112
Olivier Grenie28fafca2011-01-04 04:27:11 -03002113 state->current_band = (u8) BAND_OF_FREQUENCY(state->fe->dtv_property_cache.frequency / 1000);
2114 state->rf_request =
2115 state->fe->dtv_property_cache.frequency / 1000 + (state->current_band ==
2116 BAND_UHF ? state->config->freq_offset_khz_uhf : state->config->
2117 freq_offset_khz_vhf);
2118
2119 /* in ISDB-T 1seg we shift tuning frequency */
2120 if ((state->fe->dtv_property_cache.delivery_system == SYS_ISDBT && state->fe->dtv_property_cache.isdbt_sb_mode == 1
2121 && state->fe->dtv_property_cache.isdbt_partial_reception == 0)) {
2122 const struct dib0090_low_if_offset_table *LUT_offset = state->config->low_if;
2123 u8 found_offset = 0;
2124 u32 margin_khz = 100;
2125
2126 if (LUT_offset != NULL) {
2127 while (LUT_offset->RF_freq != 0xffff) {
2128 if (((state->rf_request > (LUT_offset->RF_freq - margin_khz))
2129 && (state->rf_request < (LUT_offset->RF_freq + margin_khz)))
2130 && LUT_offset->std == state->fe->dtv_property_cache.delivery_system) {
2131 state->rf_request += LUT_offset->offset_khz;
2132 found_offset = 1;
2133 break;
2134 }
2135 LUT_offset++;
2136 }
2137 }
2138
2139 if (found_offset == 0)
2140 state->rf_request += 400;
2141 }
2142 if (state->current_rf != state->rf_request || (state->current_standard != state->fe->dtv_property_cache.delivery_system)) {
2143 state->tuner_is_tuned = 0;
Olivier Grenie03245a52009-12-04 13:27:57 -03002144 state->current_rf = 0;
Olivier Grenie28fafca2011-01-04 04:27:11 -03002145 state->current_standard = 0;
Olivier Grenie03245a52009-12-04 13:27:57 -03002146
Olivier Grenie28fafca2011-01-04 04:27:11 -03002147 tune = dib0090_tuning_table;
2148 if (state->identity.p1g)
2149 tune = dib0090_p1g_tuning_table;
Olivier Grenie03245a52009-12-04 13:27:57 -03002150
Olivier Grenie28fafca2011-01-04 04:27:11 -03002151 tmp = (state->identity.version >> 5) & 0x7;
2152
2153 if (state->identity.in_soc) {
2154 if (state->config->force_cband_input) { /* Use the CBAND input for all band */
2155 if (state->current_band & BAND_CBAND || state->current_band & BAND_FM || state->current_band & BAND_VHF
2156 || state->current_band & BAND_UHF) {
2157 state->current_band = BAND_CBAND;
2158 tune = dib0090_tuning_table_cband_7090;
2159 }
2160 } else { /* Use the CBAND input for all band under UHF */
2161 if (state->current_band & BAND_CBAND || state->current_band & BAND_FM || state->current_band & BAND_VHF) {
2162 state->current_band = BAND_CBAND;
2163 tune = dib0090_tuning_table_cband_7090;
2164 }
2165 }
2166 } else
2167 if (tmp == 0x4 || tmp == 0x7) {
2168 /* CBAND tuner version for VHF */
2169 if (state->current_band == BAND_FM || state->current_band == BAND_CBAND || state->current_band == BAND_VHF) {
2170 state->current_band = BAND_CBAND; /* Force CBAND */
2171
2172 tune = dib0090_tuning_table_fm_vhf_on_cband;
2173 if (state->identity.p1g)
2174 tune = dib0090_p1g_tuning_table_fm_vhf_on_cband;
2175 }
2176 }
2177
2178 pll = dib0090_pll_table;
2179 if (state->identity.p1g)
2180 pll = dib0090_p1g_pll_table;
2181
2182 /* Look for the interval */
2183 while (state->rf_request > tune->max_freq)
2184 tune++;
2185 while (state->rf_request > pll->max_freq)
2186 pll++;
2187
2188 state->current_tune_table_index = tune;
2189 state->current_pll_table_index = pll;
2190
Olivier Grenie03245a52009-12-04 13:27:57 -03002191 dib0090_write_reg(state, 0x0b, 0xb800 | (tune->switch_trim));
2192
Olivier Grenie28fafca2011-01-04 04:27:11 -03002193 VCOF_kHz = (pll->hfdiv * state->rf_request) * 2;
Olivier Grenie03245a52009-12-04 13:27:57 -03002194
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002195 FREF = state->config->io.clock_khz;
Olivier Grenie28fafca2011-01-04 04:27:11 -03002196 if (state->config->fref_clock_ratio != 0)
2197 FREF /= state->config->fref_clock_ratio;
Olivier Grenie03245a52009-12-04 13:27:57 -03002198
Olivier Grenie03245a52009-12-04 13:27:57 -03002199 FBDiv = (VCOF_kHz / pll->topresc / FREF);
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002200 Rest = (VCOF_kHz / pll->topresc) - FBDiv * FREF;
Olivier Grenie03245a52009-12-04 13:27:57 -03002201
2202 if (Rest < LPF)
2203 Rest = 0;
2204 else if (Rest < 2 * LPF)
2205 Rest = 2 * LPF;
2206 else if (Rest > (FREF - LPF)) {
2207 Rest = 0;
2208 FBDiv += 1;
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002209 } else if (Rest > (FREF - 2 * LPF))
Olivier Grenie03245a52009-12-04 13:27:57 -03002210 Rest = FREF - 2 * LPF;
2211 Rest = (Rest * 6528) / (FREF / 10);
Olivier Grenie28fafca2011-01-04 04:27:11 -03002212 state->rest = Rest;
2213
2214 /* external loop filter, otherwise:
2215 * lo5 = (0 << 15) | (0 << 12) | (0 << 11) | (3 << 9) | (4 << 6) | (3 << 4) | 4;
2216 * lo6 = 0x0e34 */
2217
2218 if (Rest == 0) {
2219 if (pll->vco_band)
2220 lo5 = 0x049f;
Olivier Grenie28fafca2011-01-04 04:27:11 -03002221 else
2222 lo5 = 0x041f;
2223 } else {
2224 if (pll->vco_band)
2225 lo5 = 0x049e;
2226 else if (state->config->analog_output)
2227 lo5 = 0x041d;
2228 else
2229 lo5 = 0x041c;
2230 }
2231
2232 if (state->identity.p1g) { /* Bias is done automatically in P1G */
2233 if (state->identity.in_soc) {
2234 if (state->identity.version == SOC_8090_P1G_11R1)
2235 lo5 = 0x46f;
2236 else
2237 lo5 = 0x42f;
2238 } else
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002239 lo5 = 0x42c;
Olivier Grenie28fafca2011-01-04 04:27:11 -03002240 }
2241
2242 lo5 |= (pll->hfdiv_code << 11) | (pll->vco_band << 7); /* bit 15 is the split to the slave, we do not do it here */
2243
Olivier Grenie28fafca2011-01-04 04:27:11 -03002244 if (!state->config->io.pll_int_loop_filt) {
2245 if (state->identity.in_soc)
2246 lo6 = 0xff98;
2247 else if (state->identity.p1g || (Rest == 0))
2248 lo6 = 0xfff8;
2249 else
2250 lo6 = 0xff28;
2251 } else
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002252 lo6 = (state->config->io.pll_int_loop_filt << 3);
Olivier Grenie03245a52009-12-04 13:27:57 -03002253
2254 Den = 1;
2255
Olivier Grenie03245a52009-12-04 13:27:57 -03002256 if (Rest > 0) {
2257 if (state->config->analog_output)
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002258 lo6 |= (1 << 2) | 2;
Olivier Grenie28fafca2011-01-04 04:27:11 -03002259 else {
2260 if (state->identity.in_soc)
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002261 lo6 |= (1 << 2) | 2;
Olivier Grenie28fafca2011-01-04 04:27:11 -03002262 else
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002263 lo6 |= (1 << 2) | 2;
Olivier Grenie28fafca2011-01-04 04:27:11 -03002264 }
Olivier Grenie03245a52009-12-04 13:27:57 -03002265 Den = 255;
2266 }
Olivier Grenie03245a52009-12-04 13:27:57 -03002267 dib0090_write_reg(state, 0x15, (u16) FBDiv);
Olivier Grenie28fafca2011-01-04 04:27:11 -03002268 if (state->config->fref_clock_ratio != 0)
2269 dib0090_write_reg(state, 0x16, (Den << 8) | state->config->fref_clock_ratio);
2270 else
2271 dib0090_write_reg(state, 0x16, (Den << 8) | 1);
Olivier Grenie03245a52009-12-04 13:27:57 -03002272 dib0090_write_reg(state, 0x17, (u16) Rest);
Olivier Grenie03245a52009-12-04 13:27:57 -03002273 dib0090_write_reg(state, 0x19, lo5);
Olivier Grenie03245a52009-12-04 13:27:57 -03002274 dib0090_write_reg(state, 0x1c, lo6);
2275
2276 lo6 = tune->tuner_enable;
2277 if (state->config->analog_output)
2278 lo6 = (lo6 & 0xff9f) | 0x2;
2279
Olivier Grenie28fafca2011-01-04 04:27:11 -03002280 dib0090_write_reg(state, 0x24, lo6 | EN_LO | state->config->use_pwm_agc * EN_CRYSTAL);
Olivier Grenie03245a52009-12-04 13:27:57 -03002281
Olivier Grenie03245a52009-12-04 13:27:57 -03002282 }
Olivier Grenie03245a52009-12-04 13:27:57 -03002283
Olivier Grenie28fafca2011-01-04 04:27:11 -03002284 state->current_rf = state->rf_request;
2285 state->current_standard = state->fe->dtv_property_cache.delivery_system;
Olivier Grenie03245a52009-12-04 13:27:57 -03002286
2287 ret = 20;
Olivier Grenie28fafca2011-01-04 04:27:11 -03002288 state->calibrate = CAPTRIM_CAL; /* captrim serach now */
2289 }
Olivier Grenie03245a52009-12-04 13:27:57 -03002290
Olivier Grenie28fafca2011-01-04 04:27:11 -03002291 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 */
2292 const struct dib0090_wbd_slope *wbd = state->current_wbd_table;
Olivier Grenie03245a52009-12-04 13:27:57 -03002293
Olivier Grenie28fafca2011-01-04 04:27:11 -03002294 while (state->current_rf / 1000 > wbd->max_freq)
2295 wbd++;
Olivier Grenie03245a52009-12-04 13:27:57 -03002296
Olivier Grenie03245a52009-12-04 13:27:57 -03002297 dib0090_write_reg(state, 0x1e, 0x07ff);
Olivier Grenie28fafca2011-01-04 04:27:11 -03002298 dprintk("Final Captrim: %d", (u32) state->fcaptrim);
2299 dprintk("HFDIV code: %d", (u32) pll->hfdiv_code);
2300 dprintk("VCO = %d", (u32) pll->vco_band);
2301 dprintk("VCOF in kHz: %d ((%d*%d) << 1))", (u32) ((pll->hfdiv * state->rf_request) * 2), (u32) pll->hfdiv, (u32) state->rf_request);
2302 dprintk("REFDIV: %d, FREF: %d", (u32) 1, (u32) state->config->io.clock_khz);
2303 dprintk("FBDIV: %d, Rest: %d", (u32) dib0090_read_reg(state, 0x15), (u32) dib0090_read_reg(state, 0x17));
2304 dprintk("Num: %d, Den: %d, SD: %d", (u32) dib0090_read_reg(state, 0x17), (u32) (dib0090_read_reg(state, 0x16) >> 8),
2305 (u32) dib0090_read_reg(state, 0x1c) & 0x3);
Olivier Grenie03245a52009-12-04 13:27:57 -03002306
Olivier Grenie28fafca2011-01-04 04:27:11 -03002307#define WBD 0x781 /* 1 1 1 1 0000 0 0 1 */
Olivier Grenie03245a52009-12-04 13:27:57 -03002308 c = 4;
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002309 i = 3;
Olivier Grenie28fafca2011-01-04 04:27:11 -03002310
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002311 if (wbd->wbd_gain != 0)
Olivier Grenie28fafca2011-01-04 04:27:11 -03002312 c = wbd->wbd_gain;
2313
Olivier Grenie28fafca2011-01-04 04:27:11 -03002314 state->wbdmux = (c << 13) | (i << 11) | (WBD | (state->config->use_pwm_agc << 1));
2315 dib0090_write_reg(state, 0x10, state->wbdmux);
2316
2317 if ((tune->tuner_enable == EN_CAB) && state->identity.p1g) {
2318 dprintk("P1G : The cable band is selected and lna_tune = %d", tune->lna_tune);
2319 dib0090_write_reg(state, 0x09, tune->lna_bias);
2320 dib0090_write_reg(state, 0x0b, 0xb800 | (tune->lna_tune << 6) | (tune->switch_trim));
2321 } else
2322 dib0090_write_reg(state, 0x09, (tune->lna_tune << 5) | tune->lna_bias);
2323
Olivier Grenie03245a52009-12-04 13:27:57 -03002324 dib0090_write_reg(state, 0x0c, tune->v2i);
2325 dib0090_write_reg(state, 0x0d, tune->mix);
2326 dib0090_write_reg(state, 0x0e, tune->load);
Olivier Grenie28fafca2011-01-04 04:27:11 -03002327 *tune_state = CT_TUNER_STEP_1;
Olivier Grenie03245a52009-12-04 13:27:57 -03002328
Olivier Grenie28fafca2011-01-04 04:27:11 -03002329 } else if (*tune_state == CT_TUNER_STEP_1) {
Olivier Grenie03245a52009-12-04 13:27:57 -03002330 /* initialize the lt gain register */
2331 state->rf_lt_def = 0x7c00;
Olivier Grenie03245a52009-12-04 13:27:57 -03002332
2333 dib0090_set_bandwidth(state);
2334 state->tuner_is_tuned = 1;
Olivier Grenie28fafca2011-01-04 04:27:11 -03002335
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002336 state->calibrate |= WBD_CAL;
2337 state->calibrate |= TEMP_CAL;
Olivier Grenie03245a52009-12-04 13:27:57 -03002338 *tune_state = CT_TUNER_STOP;
2339 } else
2340 ret = FE_CALLBACK_TIME_NEVER;
2341 return ret;
2342}
2343
2344static int dib0090_release(struct dvb_frontend *fe)
2345{
2346 kfree(fe->tuner_priv);
2347 fe->tuner_priv = NULL;
2348 return 0;
2349}
2350
2351enum frontend_tune_state dib0090_get_tune_state(struct dvb_frontend *fe)
2352{
2353 struct dib0090_state *state = fe->tuner_priv;
2354
2355 return state->tune_state;
2356}
Olivier Grenie28fafca2011-01-04 04:27:11 -03002357
Olivier Grenie03245a52009-12-04 13:27:57 -03002358EXPORT_SYMBOL(dib0090_get_tune_state);
2359
2360int dib0090_set_tune_state(struct dvb_frontend *fe, enum frontend_tune_state tune_state)
2361{
2362 struct dib0090_state *state = fe->tuner_priv;
2363
2364 state->tune_state = tune_state;
2365 return 0;
2366}
Olivier Grenie28fafca2011-01-04 04:27:11 -03002367
Olivier Grenie03245a52009-12-04 13:27:57 -03002368EXPORT_SYMBOL(dib0090_set_tune_state);
2369
2370static int dib0090_get_frequency(struct dvb_frontend *fe, u32 * frequency)
2371{
2372 struct dib0090_state *state = fe->tuner_priv;
2373
2374 *frequency = 1000 * state->current_rf;
2375 return 0;
2376}
2377
2378static int dib0090_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *p)
2379{
2380 struct dib0090_state *state = fe->tuner_priv;
Olivier Grenie28fafca2011-01-04 04:27:11 -03002381 u32 ret;
Olivier Grenie03245a52009-12-04 13:27:57 -03002382
2383 state->tune_state = CT_TUNER_START;
2384
2385 do {
2386 ret = dib0090_tune(fe);
2387 if (ret != FE_CALLBACK_TIME_NEVER)
2388 msleep(ret / 10);
2389 else
2390 break;
2391 } while (state->tune_state != CT_TUNER_STOP);
2392
2393 return 0;
2394}
2395
2396static const struct dvb_tuner_ops dib0090_ops = {
2397 .info = {
2398 .name = "DiBcom DiB0090",
2399 .frequency_min = 45000000,
2400 .frequency_max = 860000000,
2401 .frequency_step = 1000,
2402 },
2403 .release = dib0090_release,
2404
2405 .init = dib0090_wakeup,
2406 .sleep = dib0090_sleep,
2407 .set_params = dib0090_set_params,
2408 .get_frequency = dib0090_get_frequency,
2409};
2410
Olivier Grenie28fafca2011-01-04 04:27:11 -03002411static const struct dvb_tuner_ops dib0090_fw_ops = {
2412 .info = {
2413 .name = "DiBcom DiB0090",
2414 .frequency_min = 45000000,
2415 .frequency_max = 860000000,
2416 .frequency_step = 1000,
2417 },
2418 .release = dib0090_release,
2419
2420 .init = NULL,
2421 .sleep = NULL,
2422 .set_params = NULL,
2423 .get_frequency = NULL,
2424};
2425
2426static const struct dib0090_wbd_slope dib0090_wbd_table_default[] = {
2427 {470, 0, 250, 0, 100, 4},
2428 {860, 51, 866, 21, 375, 4},
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002429 {1700, 0, 800, 0, 850, 4},
2430 {2900, 0, 250, 0, 100, 6},
Olivier Grenie28fafca2011-01-04 04:27:11 -03002431 {0xFFFF, 0, 0, 0, 0, 0},
2432};
2433
Olivier Grenie03245a52009-12-04 13:27:57 -03002434struct dvb_frontend *dib0090_register(struct dvb_frontend *fe, struct i2c_adapter *i2c, const struct dib0090_config *config)
2435{
2436 struct dib0090_state *st = kzalloc(sizeof(struct dib0090_state), GFP_KERNEL);
2437 if (st == NULL)
2438 return NULL;
2439
2440 st->config = config;
2441 st->i2c = i2c;
2442 st->fe = fe;
2443 fe->tuner_priv = st;
2444
Olivier Grenie28fafca2011-01-04 04:27:11 -03002445 if (config->wbd == NULL)
2446 st->current_wbd_table = dib0090_wbd_table_default;
2447 else
2448 st->current_wbd_table = config->wbd;
2449
Olivier Grenie03245a52009-12-04 13:27:57 -03002450 if (dib0090_reset(fe) != 0)
2451 goto free_mem;
2452
2453 printk(KERN_INFO "DiB0090: successfully identified\n");
2454 memcpy(&fe->ops.tuner_ops, &dib0090_ops, sizeof(struct dvb_tuner_ops));
2455
2456 return fe;
2457 free_mem:
2458 kfree(st);
2459 fe->tuner_priv = NULL;
2460 return NULL;
2461}
Olivier Grenie28fafca2011-01-04 04:27:11 -03002462
Olivier Grenie03245a52009-12-04 13:27:57 -03002463EXPORT_SYMBOL(dib0090_register);
2464
Olivier Grenie28fafca2011-01-04 04:27:11 -03002465struct dvb_frontend *dib0090_fw_register(struct dvb_frontend *fe, struct i2c_adapter *i2c, const struct dib0090_config *config)
2466{
2467 struct dib0090_fw_state *st = kzalloc(sizeof(struct dib0090_fw_state), GFP_KERNEL);
2468 if (st == NULL)
2469 return NULL;
2470
2471 st->config = config;
2472 st->i2c = i2c;
2473 st->fe = fe;
2474 fe->tuner_priv = st;
2475
2476 if (dib0090_fw_reset_digital(fe, st->config) != 0)
2477 goto free_mem;
2478
2479 dprintk("DiB0090 FW: successfully identified");
2480 memcpy(&fe->ops.tuner_ops, &dib0090_fw_ops, sizeof(struct dvb_tuner_ops));
2481
2482 return fe;
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002483free_mem:
Olivier Grenie28fafca2011-01-04 04:27:11 -03002484 kfree(st);
2485 fe->tuner_priv = NULL;
2486 return NULL;
2487}
Olivier Grenie28fafca2011-01-04 04:27:11 -03002488EXPORT_SYMBOL(dib0090_fw_register);
2489
Olivier Grenie03245a52009-12-04 13:27:57 -03002490MODULE_AUTHOR("Patrick Boettcher <pboettcher@dibcom.fr>");
2491MODULE_AUTHOR("Olivier Grenie <olivier.grenie@dibcom.fr>");
2492MODULE_DESCRIPTION("Driver for the DiBcom 0090 base-band RF Tuner");
2493MODULE_LICENSE("GPL");