blob: 52ff1a252a907186e4086a6bf9b0f606f215bfa7 [file] [log] [blame]
Olivier Grenie03245a52009-12-04 13:27:57 -03001/*
2 * Linux-DVB Driver for DiBcom's DiB0090 base-band RF Tuner.
3 *
4 * Copyright (C) 2005-9 DiBcom (http://www.dibcom.fr/)
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License as
8 * published by the Free Software Foundation; either version 2 of the
9 * License, or (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 *
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 *
21 *
22 * This code is more or less generated from another driver, please
23 * excuse some codingstyle oddities.
24 *
25 */
26
27#include <linux/kernel.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090028#include <linux/slab.h>
Olivier Grenie03245a52009-12-04 13:27:57 -030029#include <linux/i2c.h>
30
31#include "dvb_frontend.h"
32
33#include "dib0090.h"
34#include "dibx000_common.h"
35
36static int debug;
37module_param(debug, int, 0644);
38MODULE_PARM_DESC(debug, "turn on debugging (default: 0)");
39
40#define dprintk(args...) do { \
41 if (debug) { \
42 printk(KERN_DEBUG "DiB0090: "); \
43 printk(args); \
44 printk("\n"); \
45 } \
46} while (0)
47
Olivier Grenie28fafca2011-01-04 04:27:11 -030048#define CONFIG_SYS_DVBT
Olivier Grenie03245a52009-12-04 13:27:57 -030049#define CONFIG_SYS_ISDBT
50#define CONFIG_BAND_CBAND
51#define CONFIG_BAND_VHF
52#define CONFIG_BAND_UHF
53#define CONFIG_DIB0090_USE_PWM_AGC
54
55#define EN_LNA0 0x8000
56#define EN_LNA1 0x4000
57#define EN_LNA2 0x2000
58#define EN_LNA3 0x1000
59#define EN_MIX0 0x0800
60#define EN_MIX1 0x0400
61#define EN_MIX2 0x0200
62#define EN_MIX3 0x0100
63#define EN_IQADC 0x0040
64#define EN_PLL 0x0020
65#define EN_TX 0x0010
66#define EN_BB 0x0008
67#define EN_LO 0x0004
68#define EN_BIAS 0x0001
69
70#define EN_IQANA 0x0002
71#define EN_DIGCLK 0x0080 /* not in the 0x24 reg, only in 0x1b */
72#define EN_CRYSTAL 0x0002
73
74#define EN_UHF 0x22E9
75#define EN_VHF 0x44E9
76#define EN_LBD 0x11E9
77#define EN_SBD 0x44E9
78#define EN_CAB 0x88E9
79
Olivier Grenie28fafca2011-01-04 04:27:11 -030080/* Calibration defines */
81#define DC_CAL 0x1
82#define WBD_CAL 0x2
83#define TEMP_CAL 0x4
84#define CAPTRIM_CAL 0x8
85
86#define KROSUS_PLL_LOCKED 0x800
87#define KROSUS 0x2
88
89/* Use those defines to identify SOC version */
90#define SOC 0x02
91#define SOC_7090_P1G_11R1 0x82
92#define SOC_7090_P1G_21R1 0x8a
93#define SOC_8090_P1G_11R1 0x86
94#define SOC_8090_P1G_21R1 0x8e
95
96/* else use thos ones to check */
97#define P1A_B 0x0
98#define P1C 0x1
99#define P1D_E_F 0x3
100#define P1G 0x7
101#define P1G_21R2 0xf
102
103#define MP001 0x1 /* Single 9090/8096 */
104#define MP005 0x4 /* Single Sband */
105#define MP008 0x6 /* Dual diversity VHF-UHF-LBAND */
106#define MP009 0x7 /* Dual diversity 29098 CBAND-UHF-LBAND-SBAND */
107
Olivier Grenie03245a52009-12-04 13:27:57 -0300108#define pgm_read_word(w) (*w)
109
110struct dc_calibration;
111
112struct dib0090_tuning {
113 u32 max_freq; /* for every frequency less than or equal to that field: this information is correct */
114 u8 switch_trim;
115 u8 lna_tune;
Olivier Grenie28fafca2011-01-04 04:27:11 -0300116 u16 lna_bias;
Olivier Grenie03245a52009-12-04 13:27:57 -0300117 u16 v2i;
118 u16 mix;
119 u16 load;
120 u16 tuner_enable;
121};
122
123struct dib0090_pll {
124 u32 max_freq; /* for every frequency less than or equal to that field: this information is correct */
125 u8 vco_band;
126 u8 hfdiv_code;
127 u8 hfdiv;
128 u8 topresc;
129};
130
Olivier Grenie28fafca2011-01-04 04:27:11 -0300131struct dib0090_identity {
132 u8 version;
133 u8 product;
134 u8 p1g;
135 u8 in_soc;
136};
137
Olivier Grenie03245a52009-12-04 13:27:57 -0300138struct dib0090_state {
139 struct i2c_adapter *i2c;
140 struct dvb_frontend *fe;
141 const struct dib0090_config *config;
142
143 u8 current_band;
Olivier Grenie03245a52009-12-04 13:27:57 -0300144 enum frontend_tune_state tune_state;
145 u32 current_rf;
146
147 u16 wbd_offset;
148 s16 wbd_target; /* in dB */
149
150 s16 rf_gain_limit; /* take-over-point: where to split between bb and rf gain */
151 s16 current_gain; /* keeps the currently programmed gain */
152 u8 agc_step; /* new binary search */
153
154 u16 gain[2]; /* for channel monitoring */
155
156 const u16 *rf_ramp;
157 const u16 *bb_ramp;
158
159 /* for the software AGC ramps */
160 u16 bb_1_def;
161 u16 rf_lt_def;
162 u16 gain_reg[4];
163
164 /* for the captrim/dc-offset search */
165 s8 step;
166 s16 adc_diff;
167 s16 min_adc_diff;
168
169 s8 captrim;
170 s8 fcaptrim;
171
172 const struct dc_calibration *dc;
173 u16 bb6, bb7;
174
175 const struct dib0090_tuning *current_tune_table_index;
176 const struct dib0090_pll *current_pll_table_index;
177
178 u8 tuner_is_tuned;
179 u8 agc_freeze;
180
Olivier Grenie28fafca2011-01-04 04:27:11 -0300181 struct dib0090_identity identity;
182
183 u32 rf_request;
184 u8 current_standard;
185
186 u8 calibrate;
187 u32 rest;
188 u16 bias;
189 s16 temperature;
190
191 u8 wbd_calibration_gain;
192 const struct dib0090_wbd_slope *current_wbd_table;
193 u16 wbdmux;
194};
195
196struct dib0090_fw_state {
197 struct i2c_adapter *i2c;
198 struct dvb_frontend *fe;
199 struct dib0090_identity identity;
200 const struct dib0090_config *config;
Olivier Grenie03245a52009-12-04 13:27:57 -0300201};
202
203static u16 dib0090_read_reg(struct dib0090_state *state, u8 reg)
204{
205 u8 b[2];
206 struct i2c_msg msg[2] = {
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300207 {.addr = state->config->i2c_address, .flags = 0, .buf = &reg, .len = 1},
208 {.addr = state->config->i2c_address, .flags = I2C_M_RD, .buf = b, .len = 2},
Olivier Grenie03245a52009-12-04 13:27:57 -0300209 };
210 if (i2c_transfer(state->i2c, msg, 2) != 2) {
211 printk(KERN_WARNING "DiB0090 I2C read failed\n");
212 return 0;
213 }
214 return (b[0] << 8) | b[1];
215}
216
217static int dib0090_write_reg(struct dib0090_state *state, u32 reg, u16 val)
218{
219 u8 b[3] = { reg & 0xff, val >> 8, val & 0xff };
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300220 struct i2c_msg msg = {.addr = state->config->i2c_address, .flags = 0, .buf = b, .len = 3 };
Olivier Grenie28fafca2011-01-04 04:27:11 -0300221 if (i2c_transfer(state->i2c, &msg, 1) != 1) {
222 printk(KERN_WARNING "DiB0090 I2C write failed\n");
223 return -EREMOTEIO;
224 }
225 return 0;
226}
227
228static u16 dib0090_fw_read_reg(struct dib0090_fw_state *state, u8 reg)
229{
230 u8 b[2];
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300231 struct i2c_msg msg = {.addr = reg, .flags = I2C_M_RD, .buf = b, .len = 2 };
Olivier Grenie28fafca2011-01-04 04:27:11 -0300232 if (i2c_transfer(state->i2c, &msg, 1) != 1) {
233 printk(KERN_WARNING "DiB0090 I2C read failed\n");
234 return 0;
235 }
236 return (b[0] << 8) | b[1];
237}
238
239static int dib0090_fw_write_reg(struct dib0090_fw_state *state, u8 reg, u16 val)
240{
241 u8 b[2] = { val >> 8, val & 0xff };
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300242 struct i2c_msg msg = {.addr = reg, .flags = 0, .buf = b, .len = 2 };
Olivier Grenie03245a52009-12-04 13:27:57 -0300243 if (i2c_transfer(state->i2c, &msg, 1) != 1) {
244 printk(KERN_WARNING "DiB0090 I2C write failed\n");
245 return -EREMOTEIO;
246 }
247 return 0;
248}
249
250#define HARD_RESET(state) do { if (cfg->reset) { if (cfg->sleep) cfg->sleep(fe, 0); msleep(10); cfg->reset(fe, 1); msleep(10); cfg->reset(fe, 0); msleep(10); } } while (0)
251#define ADC_TARGET -220
252#define GAIN_ALPHA 5
253#define WBD_ALPHA 6
254#define LPF 100
255static void dib0090_write_regs(struct dib0090_state *state, u8 r, const u16 * b, u8 c)
256{
257 do {
258 dib0090_write_reg(state, r++, *b++);
259 } while (--c);
260}
261
Olivier Grenie28fafca2011-01-04 04:27:11 -0300262static int dib0090_identify(struct dvb_frontend *fe)
Olivier Grenie03245a52009-12-04 13:27:57 -0300263{
264 struct dib0090_state *state = fe->tuner_priv;
265 u16 v;
Olivier Grenie28fafca2011-01-04 04:27:11 -0300266 struct dib0090_identity *identity = &state->identity;
Olivier Grenie03245a52009-12-04 13:27:57 -0300267
268 v = dib0090_read_reg(state, 0x1a);
269
Olivier Grenie28fafca2011-01-04 04:27:11 -0300270 identity->p1g = 0;
271 identity->in_soc = 0;
272
273 dprintk("Tuner identification (Version = 0x%04x)", v);
Olivier Grenie03245a52009-12-04 13:27:57 -0300274
275 /* without PLL lock info */
Olivier Grenie28fafca2011-01-04 04:27:11 -0300276 v &= ~KROSUS_PLL_LOCKED;
Olivier Grenie03245a52009-12-04 13:27:57 -0300277
Olivier Grenie28fafca2011-01-04 04:27:11 -0300278 identity->version = v & 0xff;
279 identity->product = (v >> 8) & 0xf;
Olivier Grenie03245a52009-12-04 13:27:57 -0300280
Olivier Grenie28fafca2011-01-04 04:27:11 -0300281 if (identity->product != KROSUS)
282 goto identification_error;
Olivier Grenie03245a52009-12-04 13:27:57 -0300283
Olivier Grenie28fafca2011-01-04 04:27:11 -0300284 if ((identity->version & 0x3) == SOC) {
285 identity->in_soc = 1;
286 switch (identity->version) {
287 case SOC_8090_P1G_11R1:
288 dprintk("SOC 8090 P1-G11R1 Has been detected");
289 identity->p1g = 1;
290 break;
291 case SOC_8090_P1G_21R1:
292 dprintk("SOC 8090 P1-G21R1 Has been detected");
293 identity->p1g = 1;
294 break;
295 case SOC_7090_P1G_11R1:
296 dprintk("SOC 7090 P1-G11R1 Has been detected");
297 identity->p1g = 1;
298 break;
299 case SOC_7090_P1G_21R1:
300 dprintk("SOC 7090 P1-G21R1 Has been detected");
301 identity->p1g = 1;
302 break;
303 default:
304 goto identification_error;
305 }
306 } else {
307 switch ((identity->version >> 5) & 0x7) {
308 case MP001:
309 dprintk("MP001 : 9090/8096");
310 break;
311 case MP005:
312 dprintk("MP005 : Single Sband");
313 break;
314 case MP008:
315 dprintk("MP008 : diversity VHF-UHF-LBAND");
316 break;
317 case MP009:
318 dprintk("MP009 : diversity 29098 CBAND-UHF-LBAND-SBAND");
319 break;
320 default:
321 goto identification_error;
322 }
323
324 switch (identity->version & 0x1f) {
325 case P1G_21R2:
326 dprintk("P1G_21R2 detected");
327 identity->p1g = 1;
328 break;
329 case P1G:
330 dprintk("P1G detected");
331 identity->p1g = 1;
332 break;
333 case P1D_E_F:
334 dprintk("P1D/E/F detected");
335 break;
336 case P1C:
337 dprintk("P1C detected");
338 break;
339 case P1A_B:
340 dprintk("P1-A/B detected: driver is deactivated - not available");
341 goto identification_error;
342 break;
343 default:
344 goto identification_error;
345 }
Olivier Grenie03245a52009-12-04 13:27:57 -0300346 }
347
Olivier Grenie28fafca2011-01-04 04:27:11 -0300348 return 0;
349
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300350identification_error:
Olivier Grenie28fafca2011-01-04 04:27:11 -0300351 return -EIO;
352}
353
354static int dib0090_fw_identify(struct dvb_frontend *fe)
355{
356 struct dib0090_fw_state *state = fe->tuner_priv;
357 struct dib0090_identity *identity = &state->identity;
358
359 u16 v = dib0090_fw_read_reg(state, 0x1a);
360 identity->p1g = 0;
361 identity->in_soc = 0;
362
363 dprintk("FE: Tuner identification (Version = 0x%04x)", v);
364
365 /* without PLL lock info */
366 v &= ~KROSUS_PLL_LOCKED;
367
368 identity->version = v & 0xff;
369 identity->product = (v >> 8) & 0xf;
370
371 if (identity->product != KROSUS)
372 goto identification_error;
373
Olivier Grenie28fafca2011-01-04 04:27:11 -0300374 if ((identity->version & 0x3) == SOC) {
375 identity->in_soc = 1;
376 switch (identity->version) {
377 case SOC_8090_P1G_11R1:
378 dprintk("SOC 8090 P1-G11R1 Has been detected");
379 identity->p1g = 1;
380 break;
381 case SOC_8090_P1G_21R1:
382 dprintk("SOC 8090 P1-G21R1 Has been detected");
383 identity->p1g = 1;
384 break;
385 case SOC_7090_P1G_11R1:
386 dprintk("SOC 7090 P1-G11R1 Has been detected");
387 identity->p1g = 1;
388 break;
389 case SOC_7090_P1G_21R1:
390 dprintk("SOC 7090 P1-G21R1 Has been detected");
391 identity->p1g = 1;
392 break;
393 default:
394 goto identification_error;
395 }
396 } else {
397 switch ((identity->version >> 5) & 0x7) {
398 case MP001:
399 dprintk("MP001 : 9090/8096");
400 break;
401 case MP005:
402 dprintk("MP005 : Single Sband");
403 break;
404 case MP008:
405 dprintk("MP008 : diversity VHF-UHF-LBAND");
406 break;
407 case MP009:
408 dprintk("MP009 : diversity 29098 CBAND-UHF-LBAND-SBAND");
409 break;
410 default:
411 goto identification_error;
412 }
413
414 switch (identity->version & 0x1f) {
415 case P1G_21R2:
416 dprintk("P1G_21R2 detected");
417 identity->p1g = 1;
418 break;
419 case P1G:
420 dprintk("P1G detected");
421 identity->p1g = 1;
422 break;
423 case P1D_E_F:
424 dprintk("P1D/E/F detected");
425 break;
426 case P1C:
427 dprintk("P1C detected");
428 break;
429 case P1A_B:
430 dprintk("P1-A/B detected: driver is deactivated - not available");
431 goto identification_error;
432 break;
433 default:
434 goto identification_error;
435 }
436 }
437
438 return 0;
439
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300440identification_error:
Olivier Grenie28fafca2011-01-04 04:27:11 -0300441 return -EIO;;
Olivier Grenie03245a52009-12-04 13:27:57 -0300442}
443
444static void dib0090_reset_digital(struct dvb_frontend *fe, const struct dib0090_config *cfg)
445{
446 struct dib0090_state *state = fe->tuner_priv;
Olivier Grenie28fafca2011-01-04 04:27:11 -0300447 u16 PllCfg, i, v;
Olivier Grenie03245a52009-12-04 13:27:57 -0300448
449 HARD_RESET(state);
450
Olivier Grenie28fafca2011-01-04 04:27:11 -0300451 dib0090_write_reg(state, 0x24, EN_PLL | EN_CRYSTAL);
Olivier Grenie03245a52009-12-04 13:27:57 -0300452 dib0090_write_reg(state, 0x1b, EN_DIGCLK | EN_PLL | EN_CRYSTAL); /* PLL, DIG_CLK and CRYSTAL remain */
453
Olivier Grenie28fafca2011-01-04 04:27:11 -0300454 if (!cfg->in_soc) {
455 /* adcClkOutRatio=8->7, release reset */
456 dib0090_write_reg(state, 0x20, ((cfg->io.adc_clock_ratio - 1) << 11) | (0 << 10) | (1 << 9) | (1 << 8) | (0 << 4) | 0);
457 if (cfg->clkoutdrive != 0)
458 dib0090_write_reg(state, 0x23, (0 << 15) | ((!cfg->analog_output) << 14) | (2 << 10) | (1 << 9) | (0 << 8)
459 | (cfg->clkoutdrive << 5) | (cfg->clkouttobamse << 4) | (0 << 2) | (0));
460 else
461 dib0090_write_reg(state, 0x23, (0 << 15) | ((!cfg->analog_output) << 14) | (2 << 10) | (1 << 9) | (0 << 8)
462 | (7 << 5) | (cfg->clkouttobamse << 4) | (0 << 2) | (0));
463 }
464
465 /* Read Pll current config * */
466 PllCfg = dib0090_read_reg(state, 0x21);
467
468 /** Reconfigure PLL if current setting is different from default setting **/
469 if ((PllCfg & 0x1FFF) != ((cfg->io.pll_range << 12) | (cfg->io.pll_loopdiv << 6) | (cfg->io.pll_prediv)) && (!cfg->in_soc)
470 && !cfg->io.pll_bypass) {
471
472 /* Set Bypass mode */
473 PllCfg |= (1 << 15);
474 dib0090_write_reg(state, 0x21, PllCfg);
475
476 /* Set Reset Pll */
477 PllCfg &= ~(1 << 13);
478 dib0090_write_reg(state, 0x21, PllCfg);
479
480 /*** Set new Pll configuration in bypass and reset state ***/
481 PllCfg = (1 << 15) | (0 << 13) | (cfg->io.pll_range << 12) | (cfg->io.pll_loopdiv << 6) | (cfg->io.pll_prediv);
482 dib0090_write_reg(state, 0x21, PllCfg);
483
484 /* Remove Reset Pll */
485 PllCfg |= (1 << 13);
486 dib0090_write_reg(state, 0x21, PllCfg);
487
488 /*** Wait for PLL lock ***/
489 i = 100;
490 do {
491 v = !!(dib0090_read_reg(state, 0x1a) & 0x800);
492 if (v)
493 break;
494 } while (--i);
495
496 if (i == 0) {
497 dprintk("Pll: Unable to lock Pll");
498 return;
499 }
500
501 /* Finally Remove Bypass mode */
502 PllCfg &= ~(1 << 15);
503 dib0090_write_reg(state, 0x21, PllCfg);
504 }
505
506 if (cfg->io.pll_bypass) {
507 PllCfg |= (cfg->io.pll_bypass << 15);
508 dib0090_write_reg(state, 0x21, PllCfg);
509 }
510}
511
512static int dib0090_fw_reset_digital(struct dvb_frontend *fe, const struct dib0090_config *cfg)
513{
514 struct dib0090_fw_state *state = fe->tuner_priv;
515 u16 PllCfg;
516 u16 v;
517 int i;
518
519 dprintk("fw reset digital");
520 HARD_RESET(state);
521
522 dib0090_fw_write_reg(state, 0x24, EN_PLL | EN_CRYSTAL);
523 dib0090_fw_write_reg(state, 0x1b, EN_DIGCLK | EN_PLL | EN_CRYSTAL); /* PLL, DIG_CLK and CRYSTAL remain */
524
525 dib0090_fw_write_reg(state, 0x20,
526 ((cfg->io.adc_clock_ratio - 1) << 11) | (0 << 10) | (1 << 9) | (1 << 8) | (cfg->data_tx_drv << 4) | cfg->ls_cfg_pad_drv);
527
528 v = (0 << 15) | ((!cfg->analog_output) << 14) | (1 << 9) | (0 << 8) | (cfg->clkouttobamse << 4) | (0 << 2) | (0);
Olivier Grenie03245a52009-12-04 13:27:57 -0300529 if (cfg->clkoutdrive != 0)
Olivier Grenie28fafca2011-01-04 04:27:11 -0300530 v |= cfg->clkoutdrive << 5;
Olivier Grenie03245a52009-12-04 13:27:57 -0300531 else
Olivier Grenie28fafca2011-01-04 04:27:11 -0300532 v |= 7 << 5;
Olivier Grenie03245a52009-12-04 13:27:57 -0300533
Olivier Grenie28fafca2011-01-04 04:27:11 -0300534 v |= 2 << 10;
535 dib0090_fw_write_reg(state, 0x23, v);
Olivier Grenie03245a52009-12-04 13:27:57 -0300536
Olivier Grenie28fafca2011-01-04 04:27:11 -0300537 /* Read Pll current config * */
538 PllCfg = dib0090_fw_read_reg(state, 0x21);
539
540 /** Reconfigure PLL if current setting is different from default setting **/
541 if ((PllCfg & 0x1FFF) != ((cfg->io.pll_range << 12) | (cfg->io.pll_loopdiv << 6) | (cfg->io.pll_prediv)) && !cfg->io.pll_bypass) {
542
543 /* Set Bypass mode */
544 PllCfg |= (1 << 15);
545 dib0090_fw_write_reg(state, 0x21, PllCfg);
546
547 /* Set Reset Pll */
548 PllCfg &= ~(1 << 13);
549 dib0090_fw_write_reg(state, 0x21, PllCfg);
550
551 /*** Set new Pll configuration in bypass and reset state ***/
552 PllCfg = (1 << 15) | (0 << 13) | (cfg->io.pll_range << 12) | (cfg->io.pll_loopdiv << 6) | (cfg->io.pll_prediv);
553 dib0090_fw_write_reg(state, 0x21, PllCfg);
554
555 /* Remove Reset Pll */
556 PllCfg |= (1 << 13);
557 dib0090_fw_write_reg(state, 0x21, PllCfg);
558
559 /*** Wait for PLL lock ***/
560 i = 100;
561 do {
562 v = !!(dib0090_fw_read_reg(state, 0x1a) & 0x800);
563 if (v)
564 break;
565 } while (--i);
566
567 if (i == 0) {
568 dprintk("Pll: Unable to lock Pll");
569 return -EIO;
570 }
571
572 /* Finally Remove Bypass mode */
573 PllCfg &= ~(1 << 15);
574 dib0090_fw_write_reg(state, 0x21, PllCfg);
575 }
576
577 if (cfg->io.pll_bypass) {
578 PllCfg |= (cfg->io.pll_bypass << 15);
579 dib0090_fw_write_reg(state, 0x21, PllCfg);
580 }
581
582 return dib0090_fw_identify(fe);
Olivier Grenie03245a52009-12-04 13:27:57 -0300583}
584
585static int dib0090_wakeup(struct dvb_frontend *fe)
586{
587 struct dib0090_state *state = fe->tuner_priv;
588 if (state->config->sleep)
589 state->config->sleep(fe, 0);
Olivier Grenie28fafca2011-01-04 04:27:11 -0300590
591 /* enable dataTX in case we have been restarted in the wrong moment */
592 dib0090_write_reg(state, 0x23, dib0090_read_reg(state, 0x23) | (1 << 14));
Olivier Grenie03245a52009-12-04 13:27:57 -0300593 return 0;
594}
595
596static int dib0090_sleep(struct dvb_frontend *fe)
597{
598 struct dib0090_state *state = fe->tuner_priv;
599 if (state->config->sleep)
600 state->config->sleep(fe, 1);
601 return 0;
602}
603
Márton Németh43e3e6d2010-01-16 14:35:03 -0300604void dib0090_dcc_freq(struct dvb_frontend *fe, u8 fast)
Olivier Grenie03245a52009-12-04 13:27:57 -0300605{
606 struct dib0090_state *state = fe->tuner_priv;
607 if (fast)
Olivier Grenie9c783032009-12-07 07:49:40 -0300608 dib0090_write_reg(state, 0x04, 0);
Olivier Grenie03245a52009-12-04 13:27:57 -0300609 else
Olivier Grenie9c783032009-12-07 07:49:40 -0300610 dib0090_write_reg(state, 0x04, 1);
Olivier Grenie03245a52009-12-04 13:27:57 -0300611}
Olivier Grenie28fafca2011-01-04 04:27:11 -0300612
Olivier Grenie03245a52009-12-04 13:27:57 -0300613EXPORT_SYMBOL(dib0090_dcc_freq);
Olivier Grenie9c783032009-12-07 07:49:40 -0300614
Olivier Grenie28fafca2011-01-04 04:27:11 -0300615static const u16 bb_ramp_pwm_normal_socs[] = {
616 550, /* max BB gain in 10th of dB */
617 (1 << 9) | 8, /* ramp_slope = 1dB of gain -> clock_ticks_per_db = clk_khz / ramp_slope -> BB_RAMP2 */
618 440,
619 (4 << 9) | 0, /* BB_RAMP3 = 26dB */
620 (0 << 9) | 208, /* BB_RAMP4 */
621 (4 << 9) | 208, /* BB_RAMP5 = 29dB */
622 (0 << 9) | 440, /* BB_RAMP6 */
623};
624
625static const u16 rf_ramp_pwm_cband_7090[] = {
626 280, /* max RF gain in 10th of dB */
627 18, /* ramp_slope = 1dB of gain -> clock_ticks_per_db = clk_khz / ramp_slope -> RF_RAMP2 */
628 504, /* ramp_max = maximum X used on the ramp */
629 (29 << 10) | 364, /* RF_RAMP5, LNA 1 = 8dB */
630 (0 << 10) | 504, /* RF_RAMP6, LNA 1 */
631 (60 << 10) | 228, /* RF_RAMP7, LNA 2 = 7.7dB */
632 (0 << 10) | 364, /* RF_RAMP8, LNA 2 */
633 (34 << 10) | 109, /* GAIN_4_1, LNA 3 = 6.8dB */
634 (0 << 10) | 228, /* GAIN_4_2, LNA 3 */
635 (37 << 10) | 0, /* RF_RAMP3, LNA 4 = 6.2dB */
636 (0 << 10) | 109, /* RF_RAMP4, LNA 4 */
637};
638
639static const u16 rf_ramp_pwm_cband_8090[] = {
640 345, /* max RF gain in 10th of dB */
641 29, /* ramp_slope = 1dB of gain -> clock_ticks_per_db = clk_khz / ramp_slope -> RF_RAMP2 */
642 1000, /* ramp_max = maximum X used on the ramp */
643 (35 << 10) | 772, /* RF_RAMP3, LNA 1 = 8dB */
644 (0 << 10) | 1000, /* RF_RAMP4, LNA 1 */
645 (58 << 10) | 496, /* RF_RAMP5, LNA 2 = 9.5dB */
646 (0 << 10) | 772, /* RF_RAMP6, LNA 2 */
647 (27 << 10) | 200, /* RF_RAMP7, LNA 3 = 10.5dB */
648 (0 << 10) | 496, /* RF_RAMP8, LNA 3 */
649 (40 << 10) | 0, /* GAIN_4_1, LNA 4 = 7dB */
650 (0 << 10) | 200, /* GAIN_4_2, LNA 4 */
651};
652
653static const u16 rf_ramp_pwm_uhf_7090[] = {
654 407, /* max RF gain in 10th of dB */
655 13, /* ramp_slope = 1dB of gain -> clock_ticks_per_db = clk_khz / ramp_slope -> RF_RAMP2 */
656 529, /* ramp_max = maximum X used on the ramp */
657 (23 << 10) | 0, /* RF_RAMP3, LNA 1 = 14.7dB */
658 (0 << 10) | 176, /* RF_RAMP4, LNA 1 */
659 (63 << 10) | 400, /* RF_RAMP5, LNA 2 = 8dB */
660 (0 << 10) | 529, /* RF_RAMP6, LNA 2 */
661 (48 << 10) | 316, /* RF_RAMP7, LNA 3 = 6.8dB */
662 (0 << 10) | 400, /* RF_RAMP8, LNA 3 */
663 (29 << 10) | 176, /* GAIN_4_1, LNA 4 = 11.5dB */
664 (0 << 10) | 316, /* GAIN_4_2, LNA 4 */
665};
666
667static const u16 rf_ramp_pwm_uhf_8090[] = {
668 388, /* max RF gain in 10th of dB */
669 26, /* ramp_slope = 1dB of gain -> clock_ticks_per_db = clk_khz / ramp_slope -> RF_RAMP2 */
670 1008, /* ramp_max = maximum X used on the ramp */
671 (11 << 10) | 0, /* RF_RAMP3, LNA 1 = 14.7dB */
672 (0 << 10) | 369, /* RF_RAMP4, LNA 1 */
673 (41 << 10) | 809, /* RF_RAMP5, LNA 2 = 8dB */
674 (0 << 10) | 1008, /* RF_RAMP6, LNA 2 */
675 (27 << 10) | 659, /* RF_RAMP7, LNA 3 = 6dB */
676 (0 << 10) | 809, /* RF_RAMP8, LNA 3 */
677 (14 << 10) | 369, /* GAIN_4_1, LNA 4 = 11.5dB */
678 (0 << 10) | 659, /* GAIN_4_2, LNA 4 */
679};
680
Olivier Grenie03245a52009-12-04 13:27:57 -0300681static const u16 rf_ramp_pwm_cband[] = {
682 0, /* max RF gain in 10th of dB */
683 0, /* ramp_slope = 1dB of gain -> clock_ticks_per_db = clk_khz / ramp_slope -> 0x2b */
684 0, /* ramp_max = maximum X used on the ramp */
685 (0 << 10) | 0, /* 0x2c, LNA 1 = 0dB */
686 (0 << 10) | 0, /* 0x2d, LNA 1 */
687 (0 << 10) | 0, /* 0x2e, LNA 2 = 0dB */
688 (0 << 10) | 0, /* 0x2f, LNA 2 */
689 (0 << 10) | 0, /* 0x30, LNA 3 = 0dB */
690 (0 << 10) | 0, /* 0x31, LNA 3 */
691 (0 << 10) | 0, /* GAIN_4_1, LNA 4 = 0dB */
692 (0 << 10) | 0, /* GAIN_4_2, LNA 4 */
693};
694
695static const u16 rf_ramp_vhf[] = {
696 412, /* max RF gain in 10th of dB */
697 132, 307, 127, /* LNA1, 13.2dB */
698 105, 412, 255, /* LNA2, 10.5dB */
699 50, 50, 127, /* LNA3, 5dB */
700 125, 175, 127, /* LNA4, 12.5dB */
701 0, 0, 127, /* CBAND, 0dB */
702};
703
704static const u16 rf_ramp_uhf[] = {
705 412, /* max RF gain in 10th of dB */
706 132, 307, 127, /* LNA1 : total gain = 13.2dB, point on the ramp where this amp is full gain, value to write to get full gain */
707 105, 412, 255, /* LNA2 : 10.5 dB */
708 50, 50, 127, /* LNA3 : 5.0 dB */
709 125, 175, 127, /* LNA4 : 12.5 dB */
710 0, 0, 127, /* CBAND : 0.0 dB */
711};
712
Olivier Grenie28fafca2011-01-04 04:27:11 -0300713static const u16 rf_ramp_cband_broadmatching[] = /* for p1G only */
714{
715 314, /* Calibrated at 200MHz order has been changed g4-g3-g2-g1 */
716 84, 314, 127, /* LNA1 */
717 80, 230, 255, /* LNA2 */
718 80, 150, 127, /* LNA3 It was measured 12dB, do not lock if 120 */
719 70, 70, 127, /* LNA4 */
720 0, 0, 127, /* CBAND */
721};
722
Olivier Grenie03245a52009-12-04 13:27:57 -0300723static const u16 rf_ramp_cband[] = {
724 332, /* max RF gain in 10th of dB */
725 132, 252, 127, /* LNA1, dB */
726 80, 332, 255, /* LNA2, dB */
727 0, 0, 127, /* LNA3, dB */
728 0, 0, 127, /* LNA4, dB */
729 120, 120, 127, /* LT1 CBAND */
730};
731
732static const u16 rf_ramp_pwm_vhf[] = {
733 404, /* max RF gain in 10th of dB */
734 25, /* ramp_slope = 1dB of gain -> clock_ticks_per_db = clk_khz / ramp_slope -> 0x2b */
735 1011, /* ramp_max = maximum X used on the ramp */
736 (6 << 10) | 417, /* 0x2c, LNA 1 = 13.2dB */
737 (0 << 10) | 756, /* 0x2d, LNA 1 */
738 (16 << 10) | 756, /* 0x2e, LNA 2 = 10.5dB */
739 (0 << 10) | 1011, /* 0x2f, LNA 2 */
740 (16 << 10) | 290, /* 0x30, LNA 3 = 5dB */
741 (0 << 10) | 417, /* 0x31, LNA 3 */
742 (7 << 10) | 0, /* GAIN_4_1, LNA 4 = 12.5dB */
743 (0 << 10) | 290, /* GAIN_4_2, LNA 4 */
744};
745
746static const u16 rf_ramp_pwm_uhf[] = {
747 404, /* max RF gain in 10th of dB */
748 25, /* ramp_slope = 1dB of gain -> clock_ticks_per_db = clk_khz / ramp_slope -> 0x2b */
749 1011, /* ramp_max = maximum X used on the ramp */
750 (6 << 10) | 417, /* 0x2c, LNA 1 = 13.2dB */
751 (0 << 10) | 756, /* 0x2d, LNA 1 */
752 (16 << 10) | 756, /* 0x2e, LNA 2 = 10.5dB */
753 (0 << 10) | 1011, /* 0x2f, LNA 2 */
754 (16 << 10) | 0, /* 0x30, LNA 3 = 5dB */
755 (0 << 10) | 127, /* 0x31, LNA 3 */
756 (7 << 10) | 127, /* GAIN_4_1, LNA 4 = 12.5dB */
757 (0 << 10) | 417, /* GAIN_4_2, LNA 4 */
758};
759
760static const u16 bb_ramp_boost[] = {
761 550, /* max BB gain in 10th of dB */
762 260, 260, 26, /* BB1, 26dB */
763 290, 550, 29, /* BB2, 29dB */
764};
765
766static const u16 bb_ramp_pwm_normal[] = {
767 500, /* max RF gain in 10th of dB */
768 8, /* ramp_slope = 1dB of gain -> clock_ticks_per_db = clk_khz / ramp_slope -> 0x34 */
769 400,
770 (2 << 9) | 0, /* 0x35 = 21dB */
771 (0 << 9) | 168, /* 0x36 */
772 (2 << 9) | 168, /* 0x37 = 29dB */
773 (0 << 9) | 400, /* 0x38 */
774};
775
776struct slope {
Olivier Grenie28fafca2011-01-04 04:27:11 -0300777 s16 range;
778 s16 slope;
Olivier Grenie03245a52009-12-04 13:27:57 -0300779};
780static u16 slopes_to_scale(const struct slope *slopes, u8 num, s16 val)
781{
782 u8 i;
783 u16 rest;
784 u16 ret = 0;
785 for (i = 0; i < num; i++) {
786 if (val > slopes[i].range)
787 rest = slopes[i].range;
788 else
789 rest = val;
790 ret += (rest * slopes[i].slope) / slopes[i].range;
791 val -= rest;
792 }
793 return ret;
794}
795
796static const struct slope dib0090_wbd_slopes[3] = {
797 {66, 120}, /* -64,-52: offset - 65 */
798 {600, 170}, /* -52,-35: 65 - 665 */
799 {170, 250}, /* -45,-10: 665 - 835 */
800};
801
802static s16 dib0090_wbd_to_db(struct dib0090_state *state, u16 wbd)
803{
804 wbd &= 0x3ff;
805 if (wbd < state->wbd_offset)
806 wbd = 0;
807 else
808 wbd -= state->wbd_offset;
809 /* -64dB is the floor */
810 return -640 + (s16) slopes_to_scale(dib0090_wbd_slopes, ARRAY_SIZE(dib0090_wbd_slopes), wbd);
811}
812
813static void dib0090_wbd_target(struct dib0090_state *state, u32 rf)
814{
815 u16 offset = 250;
816
817 /* TODO : DAB digital N+/-1 interferer perfs : offset = 10 */
818
819 if (state->current_band == BAND_VHF)
820 offset = 650;
821#ifndef FIRMWARE_FIREFLY
822 if (state->current_band == BAND_VHF)
823 offset = state->config->wbd_vhf_offset;
824 if (state->current_band == BAND_CBAND)
825 offset = state->config->wbd_cband_offset;
826#endif
827
828 state->wbd_target = dib0090_wbd_to_db(state, state->wbd_offset + offset);
829 dprintk("wbd-target: %d dB", (u32) state->wbd_target);
830}
831
832static const int gain_reg_addr[4] = {
833 0x08, 0x0a, 0x0f, 0x01
834};
835
836static void dib0090_gain_apply(struct dib0090_state *state, s16 gain_delta, s16 top_delta, u8 force)
837{
838 u16 rf, bb, ref;
839 u16 i, v, gain_reg[4] = { 0 }, gain;
840 const u16 *g;
841
842 if (top_delta < -511)
843 top_delta = -511;
844 if (top_delta > 511)
845 top_delta = 511;
846
847 if (force) {
848 top_delta *= (1 << WBD_ALPHA);
849 gain_delta *= (1 << GAIN_ALPHA);
850 }
851
852 if (top_delta >= ((s16) (state->rf_ramp[0] << WBD_ALPHA) - state->rf_gain_limit)) /* overflow */
853 state->rf_gain_limit = state->rf_ramp[0] << WBD_ALPHA;
854 else
855 state->rf_gain_limit += top_delta;
856
857 if (state->rf_gain_limit < 0) /*underflow */
858 state->rf_gain_limit = 0;
859
860 /* use gain as a temporary variable and correct current_gain */
861 gain = ((state->rf_gain_limit >> WBD_ALPHA) + state->bb_ramp[0]) << GAIN_ALPHA;
862 if (gain_delta >= ((s16) gain - state->current_gain)) /* overflow */
863 state->current_gain = gain;
864 else
865 state->current_gain += gain_delta;
866 /* cannot be less than 0 (only if gain_delta is less than 0 we can have current_gain < 0) */
867 if (state->current_gain < 0)
868 state->current_gain = 0;
869
870 /* now split total gain to rf and bb gain */
871 gain = state->current_gain >> GAIN_ALPHA;
872
873 /* requested gain is bigger than rf gain limit - ACI/WBD adjustment */
874 if (gain > (state->rf_gain_limit >> WBD_ALPHA)) {
875 rf = state->rf_gain_limit >> WBD_ALPHA;
876 bb = gain - rf;
877 if (bb > state->bb_ramp[0])
878 bb = state->bb_ramp[0];
879 } else { /* high signal level -> all gains put on RF */
880 rf = gain;
881 bb = 0;
882 }
883
884 state->gain[0] = rf;
885 state->gain[1] = bb;
886
887 /* software ramp */
888 /* Start with RF gains */
889 g = state->rf_ramp + 1; /* point on RF LNA1 max gain */
890 ref = rf;
891 for (i = 0; i < 7; i++) { /* Go over all amplifiers => 5RF amps + 2 BB amps = 7 amps */
892 if (g[0] == 0 || ref < (g[1] - g[0])) /* if total gain of the current amp is null or this amp is not concerned because it starts to work from an higher gain value */
893 v = 0; /* force the gain to write for the current amp to be null */
894 else if (ref >= g[1]) /* Gain to set is higher than the high working point of this amp */
895 v = g[2]; /* force this amp to be full gain */
896 else /* compute the value to set to this amp because we are somewhere in his range */
897 v = ((ref - (g[1] - g[0])) * g[2]) / g[0];
898
899 if (i == 0) /* LNA 1 reg mapping */
900 gain_reg[0] = v;
901 else if (i == 1) /* LNA 2 reg mapping */
902 gain_reg[0] |= v << 7;
903 else if (i == 2) /* LNA 3 reg mapping */
904 gain_reg[1] = v;
905 else if (i == 3) /* LNA 4 reg mapping */
906 gain_reg[1] |= v << 7;
907 else if (i == 4) /* CBAND LNA reg mapping */
908 gain_reg[2] = v | state->rf_lt_def;
909 else if (i == 5) /* BB gain 1 reg mapping */
910 gain_reg[3] = v << 3;
911 else if (i == 6) /* BB gain 2 reg mapping */
912 gain_reg[3] |= v << 8;
913
914 g += 3; /* go to next gain bloc */
915
916 /* When RF is finished, start with BB */
917 if (i == 4) {
918 g = state->bb_ramp + 1; /* point on BB gain 1 max gain */
919 ref = bb;
920 }
921 }
922 gain_reg[3] |= state->bb_1_def;
923 gain_reg[3] |= ((bb % 10) * 100) / 125;
924
925#ifdef DEBUG_AGC
926 dprintk("GA CALC: DB: %3d(rf) + %3d(bb) = %3d gain_reg[0]=%04x gain_reg[1]=%04x gain_reg[2]=%04x gain_reg[0]=%04x", rf, bb, rf + bb,
927 gain_reg[0], gain_reg[1], gain_reg[2], gain_reg[3]);
928#endif
929
930 /* Write the amplifier regs */
931 for (i = 0; i < 4; i++) {
932 v = gain_reg[i];
933 if (force || state->gain_reg[i] != v) {
934 state->gain_reg[i] = v;
935 dib0090_write_reg(state, gain_reg_addr[i], v);
936 }
937 }
938}
939
940static void dib0090_set_boost(struct dib0090_state *state, int onoff)
941{
942 state->bb_1_def &= 0xdfff;
943 state->bb_1_def |= onoff << 13;
944}
945
946static void dib0090_set_rframp(struct dib0090_state *state, const u16 * cfg)
947{
948 state->rf_ramp = cfg;
949}
950
951static void dib0090_set_rframp_pwm(struct dib0090_state *state, const u16 * cfg)
952{
953 state->rf_ramp = cfg;
954
955 dib0090_write_reg(state, 0x2a, 0xffff);
956
957 dprintk("total RF gain: %ddB, step: %d", (u32) cfg[0], dib0090_read_reg(state, 0x2a));
958
959 dib0090_write_regs(state, 0x2c, cfg + 3, 6);
960 dib0090_write_regs(state, 0x3e, cfg + 9, 2);
961}
962
963static void dib0090_set_bbramp(struct dib0090_state *state, const u16 * cfg)
964{
965 state->bb_ramp = cfg;
966 dib0090_set_boost(state, cfg[0] > 500); /* we want the boost if the gain is higher that 50dB */
967}
968
969static void dib0090_set_bbramp_pwm(struct dib0090_state *state, const u16 * cfg)
970{
971 state->bb_ramp = cfg;
972
973 dib0090_set_boost(state, cfg[0] > 500); /* we want the boost if the gain is higher that 50dB */
974
975 dib0090_write_reg(state, 0x33, 0xffff);
976 dprintk("total BB gain: %ddB, step: %d", (u32) cfg[0], dib0090_read_reg(state, 0x33));
977 dib0090_write_regs(state, 0x35, cfg + 3, 4);
978}
979
980void dib0090_pwm_gain_reset(struct dvb_frontend *fe)
981{
982 struct dib0090_state *state = fe->tuner_priv;
983 /* reset the AGC */
984
985 if (state->config->use_pwm_agc) {
986#ifdef CONFIG_BAND_SBAND
987 if (state->current_band == BAND_SBAND) {
988 dib0090_set_rframp_pwm(state, rf_ramp_pwm_sband);
989 dib0090_set_bbramp_pwm(state, bb_ramp_pwm_boost);
990 } else
991#endif
992#ifdef CONFIG_BAND_CBAND
993 if (state->current_band == BAND_CBAND) {
Olivier Grenie28fafca2011-01-04 04:27:11 -0300994 if (state->identity.in_soc) {
995 dib0090_set_bbramp_pwm(state, bb_ramp_pwm_normal_socs);
996 if (state->identity.version == SOC_8090_P1G_11R1 || state->identity.version == SOC_8090_P1G_21R1)
997 dib0090_set_rframp_pwm(state, rf_ramp_pwm_cband_8090);
998 else if (state->identity.version == SOC_7090_P1G_11R1 || state->identity.version == SOC_7090_P1G_21R1)
999 dib0090_set_rframp_pwm(state, rf_ramp_pwm_cband_7090);
1000 } else {
1001 dib0090_set_rframp_pwm(state, rf_ramp_pwm_cband);
1002 dib0090_set_bbramp_pwm(state, bb_ramp_pwm_normal);
1003 }
Olivier Grenie03245a52009-12-04 13:27:57 -03001004 } else
1005#endif
1006#ifdef CONFIG_BAND_VHF
1007 if (state->current_band == BAND_VHF) {
Olivier Grenie28fafca2011-01-04 04:27:11 -03001008 if (state->identity.in_soc) {
1009 dib0090_set_bbramp_pwm(state, bb_ramp_pwm_normal_socs);
Olivier Grenie28fafca2011-01-04 04:27:11 -03001010 } else {
1011 dib0090_set_rframp_pwm(state, rf_ramp_pwm_vhf);
1012 dib0090_set_bbramp_pwm(state, bb_ramp_pwm_normal);
1013 }
Olivier Grenie03245a52009-12-04 13:27:57 -03001014 } else
1015#endif
1016 {
Olivier Grenie28fafca2011-01-04 04:27:11 -03001017 if (state->identity.in_soc) {
1018 if (state->identity.version == SOC_8090_P1G_11R1 || state->identity.version == SOC_8090_P1G_21R1)
1019 dib0090_set_rframp_pwm(state, rf_ramp_pwm_uhf_8090);
1020 else if (state->identity.version == SOC_7090_P1G_11R1 || state->identity.version == SOC_7090_P1G_21R1)
1021 dib0090_set_rframp_pwm(state, rf_ramp_pwm_uhf_7090);
1022 dib0090_set_bbramp_pwm(state, bb_ramp_pwm_normal_socs);
1023 } else {
1024 dib0090_set_rframp_pwm(state, rf_ramp_pwm_uhf);
1025 dib0090_set_bbramp_pwm(state, bb_ramp_pwm_normal);
1026 }
Olivier Grenie03245a52009-12-04 13:27:57 -03001027 }
1028
1029 if (state->rf_ramp[0] != 0)
1030 dib0090_write_reg(state, 0x32, (3 << 11));
1031 else
1032 dib0090_write_reg(state, 0x32, (0 << 11));
1033
Olivier Grenie28fafca2011-01-04 04:27:11 -03001034 dib0090_write_reg(state, 0x04, 0x01);
Olivier Grenie9c783032009-12-07 07:49:40 -03001035 dib0090_write_reg(state, 0x39, (1 << 10));
Olivier Grenie03245a52009-12-04 13:27:57 -03001036 }
1037}
Olivier Grenie28fafca2011-01-04 04:27:11 -03001038
Olivier Grenie03245a52009-12-04 13:27:57 -03001039EXPORT_SYMBOL(dib0090_pwm_gain_reset);
Olivier Grenie9c783032009-12-07 07:49:40 -03001040
Olivier Grenie28fafca2011-01-04 04:27:11 -03001041static u32 dib0090_get_slow_adc_val(struct dib0090_state *state)
1042{
1043 u16 adc_val = dib0090_read_reg(state, 0x1d);
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001044 if (state->identity.in_soc)
Olivier Grenie28fafca2011-01-04 04:27:11 -03001045 adc_val >>= 2;
Olivier Grenie28fafca2011-01-04 04:27:11 -03001046 return adc_val;
1047}
1048
Olivier Grenie03245a52009-12-04 13:27:57 -03001049int dib0090_gain_control(struct dvb_frontend *fe)
1050{
1051 struct dib0090_state *state = fe->tuner_priv;
1052 enum frontend_tune_state *tune_state = &state->tune_state;
1053 int ret = 10;
1054
1055 u16 wbd_val = 0;
1056 u8 apply_gain_immediatly = 1;
1057 s16 wbd_error = 0, adc_error = 0;
1058
1059 if (*tune_state == CT_AGC_START) {
1060 state->agc_freeze = 0;
1061 dib0090_write_reg(state, 0x04, 0x0);
1062
1063#ifdef CONFIG_BAND_SBAND
1064 if (state->current_band == BAND_SBAND) {
1065 dib0090_set_rframp(state, rf_ramp_sband);
1066 dib0090_set_bbramp(state, bb_ramp_boost);
1067 } else
1068#endif
1069#ifdef CONFIG_BAND_VHF
Olivier Grenie28fafca2011-01-04 04:27:11 -03001070 if (state->current_band == BAND_VHF && !state->identity.p1g) {
Olivier Grenie03245a52009-12-04 13:27:57 -03001071 dib0090_set_rframp(state, rf_ramp_vhf);
1072 dib0090_set_bbramp(state, bb_ramp_boost);
1073 } else
1074#endif
1075#ifdef CONFIG_BAND_CBAND
Olivier Grenie28fafca2011-01-04 04:27:11 -03001076 if (state->current_band == BAND_CBAND && !state->identity.p1g) {
Olivier Grenie03245a52009-12-04 13:27:57 -03001077 dib0090_set_rframp(state, rf_ramp_cband);
1078 dib0090_set_bbramp(state, bb_ramp_boost);
1079 } else
1080#endif
Olivier Grenie28fafca2011-01-04 04:27:11 -03001081 if ((state->current_band == BAND_CBAND || state->current_band == BAND_VHF) && state->identity.p1g) {
1082 dib0090_set_rframp(state, rf_ramp_cband_broadmatching);
1083 dib0090_set_bbramp(state, bb_ramp_boost);
1084 } else {
Olivier Grenie03245a52009-12-04 13:27:57 -03001085 dib0090_set_rframp(state, rf_ramp_uhf);
1086 dib0090_set_bbramp(state, bb_ramp_boost);
1087 }
1088
1089 dib0090_write_reg(state, 0x32, 0);
1090 dib0090_write_reg(state, 0x39, 0);
1091
1092 dib0090_wbd_target(state, state->current_rf);
1093
1094 state->rf_gain_limit = state->rf_ramp[0] << WBD_ALPHA;
1095 state->current_gain = ((state->rf_ramp[0] + state->bb_ramp[0]) / 2) << GAIN_ALPHA;
1096
1097 *tune_state = CT_AGC_STEP_0;
1098 } else if (!state->agc_freeze) {
Olivier Grenie28fafca2011-01-04 04:27:11 -03001099 s16 wbd = 0, i, cnt;
Olivier Grenie03245a52009-12-04 13:27:57 -03001100
1101 int adc;
Olivier Grenie28fafca2011-01-04 04:27:11 -03001102 wbd_val = dib0090_get_slow_adc_val(state);
Olivier Grenie03245a52009-12-04 13:27:57 -03001103
Olivier Grenie28fafca2011-01-04 04:27:11 -03001104 if (*tune_state == CT_AGC_STEP_0)
1105 cnt = 5;
1106 else
1107 cnt = 1;
1108
1109 for (i = 0; i < cnt; i++) {
1110 wbd_val = dib0090_get_slow_adc_val(state);
1111 wbd += dib0090_wbd_to_db(state, wbd_val);
1112 }
1113 wbd /= cnt;
Olivier Grenie03245a52009-12-04 13:27:57 -03001114 wbd_error = state->wbd_target - wbd;
1115
1116 if (*tune_state == CT_AGC_STEP_0) {
Olivier Grenie28fafca2011-01-04 04:27:11 -03001117 if (wbd_error < 0 && state->rf_gain_limit > 0 && !state->identity.p1g) {
Olivier Grenie03245a52009-12-04 13:27:57 -03001118#ifdef CONFIG_BAND_CBAND
1119 /* in case of CBAND tune reduce first the lt_gain2 before adjusting the RF gain */
1120 u8 ltg2 = (state->rf_lt_def >> 10) & 0x7;
1121 if (state->current_band == BAND_CBAND && ltg2) {
1122 ltg2 >>= 1;
1123 state->rf_lt_def &= ltg2 << 10; /* reduce in 3 steps from 7 to 0 */
1124 }
1125#endif
1126 } else {
1127 state->agc_step = 0;
1128 *tune_state = CT_AGC_STEP_1;
1129 }
1130 } else {
1131 /* calc the adc power */
1132 adc = state->config->get_adc_power(fe);
1133 adc = (adc * ((s32) 355774) + (((s32) 1) << 20)) >> 21; /* included in [0:-700] */
1134
1135 adc_error = (s16) (((s32) ADC_TARGET) - adc);
1136#ifdef CONFIG_STANDARD_DAB
1137 if (state->fe->dtv_property_cache.delivery_system == STANDARD_DAB)
Olivier Grenie28fafca2011-01-04 04:27:11 -03001138 adc_error -= 10;
Olivier Grenie03245a52009-12-04 13:27:57 -03001139#endif
1140#ifdef CONFIG_STANDARD_DVBT
1141 if (state->fe->dtv_property_cache.delivery_system == STANDARD_DVBT &&
Olivier Grenie28fafca2011-01-04 04:27:11 -03001142 (state->fe->dtv_property_cache.modulation == QAM_64 || state->fe->dtv_property_cache.modulation == QAM_16))
Olivier Grenie03245a52009-12-04 13:27:57 -03001143 adc_error += 60;
1144#endif
1145#ifdef CONFIG_SYS_ISDBT
1146 if ((state->fe->dtv_property_cache.delivery_system == SYS_ISDBT) && (((state->fe->dtv_property_cache.layer[0].segment_count >
Olivier Grenie28fafca2011-01-04 04:27:11 -03001147 0)
1148 &&
1149 ((state->fe->dtv_property_cache.layer[0].modulation ==
1150 QAM_64)
1151 || (state->fe->dtv_property_cache.
1152 layer[0].modulation == QAM_16)))
1153 ||
1154 ((state->fe->dtv_property_cache.layer[1].segment_count >
1155 0)
1156 &&
1157 ((state->fe->dtv_property_cache.layer[1].modulation ==
1158 QAM_64)
1159 || (state->fe->dtv_property_cache.
1160 layer[1].modulation == QAM_16)))
1161 ||
1162 ((state->fe->dtv_property_cache.layer[2].segment_count >
1163 0)
1164 &&
1165 ((state->fe->dtv_property_cache.layer[2].modulation ==
1166 QAM_64)
1167 || (state->fe->dtv_property_cache.
1168 layer[2].modulation == QAM_16)))
1169 )
1170 )
Olivier Grenie03245a52009-12-04 13:27:57 -03001171 adc_error += 60;
1172#endif
1173
1174 if (*tune_state == CT_AGC_STEP_1) { /* quickly go to the correct range of the ADC power */
1175 if (ABS(adc_error) < 50 || state->agc_step++ > 5) {
1176
1177#ifdef CONFIG_STANDARD_DAB
1178 if (state->fe->dtv_property_cache.delivery_system == STANDARD_DAB) {
1179 dib0090_write_reg(state, 0x02, (1 << 15) | (15 << 11) | (31 << 6) | (63)); /* cap value = 63 : narrow BB filter : Fc = 1.8MHz */
1180 dib0090_write_reg(state, 0x04, 0x0);
1181 } else
1182#endif
1183 {
1184 dib0090_write_reg(state, 0x02, (1 << 15) | (3 << 11) | (6 << 6) | (32));
1185 dib0090_write_reg(state, 0x04, 0x01); /*0 = 1KHz ; 1 = 150Hz ; 2 = 50Hz ; 3 = 50KHz ; 4 = servo fast */
1186 }
1187
1188 *tune_state = CT_AGC_STOP;
1189 }
1190 } else {
1191 /* everything higher than or equal to CT_AGC_STOP means tracking */
1192 ret = 100; /* 10ms interval */
1193 apply_gain_immediatly = 0;
1194 }
1195 }
1196#ifdef DEBUG_AGC
1197 dprintk
Olivier Grenie28fafca2011-01-04 04:27:11 -03001198 ("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 -03001199 (u32) *tune_state, (u32) adc, (u32) adc_error, (u32) wbd, (u32) wbd_error, (u32) wbd_val,
Olivier Grenie28fafca2011-01-04 04:27:11 -03001200 (u32) state->rf_gain_limit >> WBD_ALPHA, (s32) 200 + adc - (state->current_gain >> GAIN_ALPHA));
Olivier Grenie03245a52009-12-04 13:27:57 -03001201#endif
1202 }
1203
1204 /* apply gain */
1205 if (!state->agc_freeze)
1206 dib0090_gain_apply(state, adc_error, wbd_error, apply_gain_immediatly);
1207 return ret;
1208}
Olivier Grenie28fafca2011-01-04 04:27:11 -03001209
Olivier Grenie03245a52009-12-04 13:27:57 -03001210EXPORT_SYMBOL(dib0090_gain_control);
Olivier Grenie9c783032009-12-07 07:49:40 -03001211
Olivier Grenie03245a52009-12-04 13:27:57 -03001212void dib0090_get_current_gain(struct dvb_frontend *fe, u16 * rf, u16 * bb, u16 * rf_gain_limit, u16 * rflt)
1213{
1214 struct dib0090_state *state = fe->tuner_priv;
1215 if (rf)
1216 *rf = state->gain[0];
1217 if (bb)
1218 *bb = state->gain[1];
1219 if (rf_gain_limit)
1220 *rf_gain_limit = state->rf_gain_limit;
1221 if (rflt)
1222 *rflt = (state->rf_lt_def >> 10) & 0x7;
1223}
Olivier Grenie28fafca2011-01-04 04:27:11 -03001224
Olivier Grenie03245a52009-12-04 13:27:57 -03001225EXPORT_SYMBOL(dib0090_get_current_gain);
Olivier Grenie9c783032009-12-07 07:49:40 -03001226
Olivier Grenie28fafca2011-01-04 04:27:11 -03001227u16 dib0090_get_wbd_offset(struct dvb_frontend *fe)
Olivier Grenie03245a52009-12-04 13:27:57 -03001228{
Olivier Grenie28fafca2011-01-04 04:27:11 -03001229 struct dib0090_state *state = fe->tuner_priv;
1230 u32 f_MHz = state->fe->dtv_property_cache.frequency / 1000000;
1231 s32 current_temp = state->temperature;
1232 s32 wbd_thot, wbd_tcold;
1233 const struct dib0090_wbd_slope *wbd = state->current_wbd_table;
1234
1235 while (f_MHz > wbd->max_freq)
1236 wbd++;
1237
1238 dprintk("using wbd-table-entry with max freq %d", wbd->max_freq);
1239
1240 if (current_temp < 0)
1241 current_temp = 0;
1242 if (current_temp > 128)
1243 current_temp = 128;
1244
Olivier Grenie28fafca2011-01-04 04:27:11 -03001245 state->wbdmux &= ~(7 << 13);
1246 if (wbd->wbd_gain != 0)
1247 state->wbdmux |= (wbd->wbd_gain << 13);
1248 else
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001249 state->wbdmux |= (4 << 13);
Olivier Grenie28fafca2011-01-04 04:27:11 -03001250
1251 dib0090_write_reg(state, 0x10, state->wbdmux);
1252
Olivier Grenie28fafca2011-01-04 04:27:11 -03001253 wbd_thot = wbd->offset_hot - (((u32) wbd->slope_hot * f_MHz) >> 6);
1254 wbd_tcold = wbd->offset_cold - (((u32) wbd->slope_cold * f_MHz) >> 6);
1255
Olivier Grenie28fafca2011-01-04 04:27:11 -03001256 wbd_tcold += ((wbd_thot - wbd_tcold) * current_temp) >> 7;
1257
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001258 state->wbd_target = dib0090_wbd_to_db(state, state->wbd_offset + wbd_tcold);
Olivier Grenie28fafca2011-01-04 04:27:11 -03001259 dprintk("wbd-target: %d dB", (u32) state->wbd_target);
1260 dprintk("wbd offset applied is %d", wbd_tcold);
1261
1262 return state->wbd_offset + wbd_tcold;
Olivier Grenie03245a52009-12-04 13:27:57 -03001263}
Olivier Grenie28fafca2011-01-04 04:27:11 -03001264
Olivier Grenie03245a52009-12-04 13:27:57 -03001265EXPORT_SYMBOL(dib0090_get_wbd_offset);
Olivier Grenie9c783032009-12-07 07:49:40 -03001266
Olivier Grenie03245a52009-12-04 13:27:57 -03001267static const u16 dib0090_defaults[] = {
1268
1269 25, 0x01,
1270 0x0000,
1271 0x99a0,
1272 0x6008,
1273 0x0000,
Olivier Grenie28fafca2011-01-04 04:27:11 -03001274 0x8bcb,
Olivier Grenie03245a52009-12-04 13:27:57 -03001275 0x0000,
1276 0x0405,
1277 0x0000,
1278 0x0000,
1279 0x0000,
1280 0xb802,
1281 0x0300,
1282 0x2d12,
1283 0xbac0,
1284 0x7c00,
1285 0xdbb9,
1286 0x0954,
1287 0x0743,
1288 0x8000,
1289 0x0001,
1290 0x0040,
1291 0x0100,
1292 0x0000,
1293 0xe910,
1294 0x149e,
1295
1296 1, 0x1c,
1297 0xff2d,
1298
1299 1, 0x39,
1300 0x0000,
1301
Olivier Grenie03245a52009-12-04 13:27:57 -03001302 2, 0x1e,
1303 0x07FF,
1304 0x0007,
1305
1306 1, 0x24,
1307 EN_UHF | EN_CRYSTAL,
1308
1309 2, 0x3c,
1310 0x3ff,
1311 0x111,
1312 0
1313};
1314
Olivier Grenie28fafca2011-01-04 04:27:11 -03001315static const u16 dib0090_p1g_additionnal_defaults[] = {
Olivier Grenie28fafca2011-01-04 04:27:11 -03001316 1, 0x05,
1317 0xabcd,
1318
1319 1, 0x11,
1320 0x00b4,
1321
1322 1, 0x1c,
1323 0xfffd,
1324
1325 1, 0x40,
1326 0x108,
1327 0
1328};
1329
1330static void dib0090_set_default_config(struct dib0090_state *state, const u16 * n)
Olivier Grenie03245a52009-12-04 13:27:57 -03001331{
Olivier Grenie28fafca2011-01-04 04:27:11 -03001332 u16 l, r;
Olivier Grenie03245a52009-12-04 13:27:57 -03001333
Olivier Grenie03245a52009-12-04 13:27:57 -03001334 l = pgm_read_word(n++);
1335 while (l) {
1336 r = pgm_read_word(n++);
1337 do {
Olivier Grenie03245a52009-12-04 13:27:57 -03001338 dib0090_write_reg(state, r, pgm_read_word(n++));
1339 r++;
1340 } while (--l);
1341 l = pgm_read_word(n++);
1342 }
Olivier Grenie28fafca2011-01-04 04:27:11 -03001343}
1344
1345#define CAP_VALUE_MIN (u8) 9
1346#define CAP_VALUE_MAX (u8) 40
1347#define HR_MIN (u8) 25
1348#define HR_MAX (u8) 40
1349#define POLY_MIN (u8) 0
1350#define POLY_MAX (u8) 8
1351
1352void dib0090_set_EFUSE(struct dib0090_state *state)
1353{
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001354 u8 c, h, n;
1355 u16 e2, e4;
1356 u16 cal;
Olivier Grenie28fafca2011-01-04 04:27:11 -03001357
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001358 e2 = dib0090_read_reg(state, 0x26);
1359 e4 = dib0090_read_reg(state, 0x28);
Olivier Grenie28fafca2011-01-04 04:27:11 -03001360
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001361 if ((state->identity.version == P1D_E_F) ||
1362 (state->identity.version == P1G) || (e2 == 0xffff)) {
Olivier Grenie28fafca2011-01-04 04:27:11 -03001363
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001364 dib0090_write_reg(state, 0x22, 0x10);
1365 cal = (dib0090_read_reg(state, 0x22) >> 6) & 0x3ff;
Olivier Grenie28fafca2011-01-04 04:27:11 -03001366
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001367 if ((cal < 670) || (cal == 1023))
1368 cal = 850;
1369 n = 165 - ((cal * 10)>>6) ;
1370 e2 = e4 = (3<<12) | (34<<6) | (n);
1371 }
Olivier Grenie28fafca2011-01-04 04:27:11 -03001372
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001373 if (e2 != e4)
1374 e2 &= e4; /* Remove the redundancy */
Olivier Grenie28fafca2011-01-04 04:27:11 -03001375
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001376 if (e2 != 0xffff) {
1377 c = e2 & 0x3f;
1378 n = (e2 >> 12) & 0xf;
1379 h = (e2 >> 6) & 0x3f;
Olivier Grenie28fafca2011-01-04 04:27:11 -03001380
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001381 if ((c >= CAP_VALUE_MAX) || (c <= CAP_VALUE_MIN))
1382 c = 32;
1383 if ((h >= HR_MAX) || (h <= HR_MIN))
1384 h = 34;
1385 if ((n >= POLY_MAX) || (n <= POLY_MIN))
1386 n = 3;
Olivier Grenie28fafca2011-01-04 04:27:11 -03001387
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001388 dib0090_write_reg(state, 0x13, (h << 10)) ;
1389 e2 = (n<<11) | ((h>>2)<<6) | (c);
1390 dib0090_write_reg(state, 0x2, e2) ; /* Load the BB_2 */
1391 }
Olivier Grenie28fafca2011-01-04 04:27:11 -03001392}
1393
1394static int dib0090_reset(struct dvb_frontend *fe)
1395{
1396 struct dib0090_state *state = fe->tuner_priv;
1397
1398 dib0090_reset_digital(fe, state->config);
1399 if (dib0090_identify(fe) < 0)
1400 return -EIO;
1401
1402#ifdef CONFIG_TUNER_DIB0090_P1B_SUPPORT
1403 if (!(state->identity.version & 0x1)) /* it is P1B - reset is already done */
1404 return 0;
1405#endif
1406
1407 if (!state->identity.in_soc) {
1408 if ((dib0090_read_reg(state, 0x1a) >> 5) & 0x2)
1409 dib0090_write_reg(state, 0x1b, (EN_IQADC | EN_BB | EN_BIAS | EN_DIGCLK | EN_PLL | EN_CRYSTAL));
1410 else
1411 dib0090_write_reg(state, 0x1b, (EN_DIGCLK | EN_PLL | EN_CRYSTAL));
1412 }
1413
1414 dib0090_set_default_config(state, dib0090_defaults);
1415
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001416 if (state->identity.in_soc)
1417 dib0090_write_reg(state, 0x18, 0x2910); /* charge pump current = 0 */
Olivier Grenie28fafca2011-01-04 04:27:11 -03001418
1419 if (state->identity.p1g)
1420 dib0090_set_default_config(state, dib0090_p1g_additionnal_defaults);
1421
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001422 /* Update the efuse : Only available for KROSUS > P1C and SOC as well*/
1423 if (((state->identity.version & 0x1f) >= P1D_E_F) || (state->identity.in_soc))
1424 dib0090_set_EFUSE(state);
Olivier Grenie03245a52009-12-04 13:27:57 -03001425
1426 /* Congigure in function of the crystal */
1427 if (state->config->io.clock_khz >= 24000)
Olivier Grenie28fafca2011-01-04 04:27:11 -03001428 dib0090_write_reg(state, 0x14, 1);
Olivier Grenie03245a52009-12-04 13:27:57 -03001429 else
Olivier Grenie28fafca2011-01-04 04:27:11 -03001430 dib0090_write_reg(state, 0x14, 2);
Olivier Grenie03245a52009-12-04 13:27:57 -03001431 dprintk("Pll lock : %d", (dib0090_read_reg(state, 0x1a) >> 11) & 0x1);
1432
Olivier Grenie28fafca2011-01-04 04:27:11 -03001433 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 -03001434
1435 return 0;
1436}
1437
Olivier Grenie9c783032009-12-07 07:49:40 -03001438#define steps(u) (((u) > 15) ? ((u)-16) : (u))
Olivier Grenie03245a52009-12-04 13:27:57 -03001439#define INTERN_WAIT 10
1440static int dib0090_get_offset(struct dib0090_state *state, enum frontend_tune_state *tune_state)
1441{
1442 int ret = INTERN_WAIT * 10;
1443
1444 switch (*tune_state) {
1445 case CT_TUNER_STEP_2:
1446 /* Turns to positive */
1447 dib0090_write_reg(state, 0x1f, 0x7);
1448 *tune_state = CT_TUNER_STEP_3;
1449 break;
1450
1451 case CT_TUNER_STEP_3:
1452 state->adc_diff = dib0090_read_reg(state, 0x1d);
1453
1454 /* Turns to negative */
1455 dib0090_write_reg(state, 0x1f, 0x4);
1456 *tune_state = CT_TUNER_STEP_4;
1457 break;
1458
1459 case CT_TUNER_STEP_4:
1460 state->adc_diff -= dib0090_read_reg(state, 0x1d);
1461 *tune_state = CT_TUNER_STEP_5;
1462 ret = 0;
1463 break;
1464
1465 default:
1466 break;
1467 }
1468
1469 return ret;
1470}
1471
1472struct dc_calibration {
Olivier Grenie28fafca2011-01-04 04:27:11 -03001473 u8 addr;
1474 u8 offset;
1475 u8 pga:1;
1476 u16 bb1;
1477 u8 i:1;
Olivier Grenie03245a52009-12-04 13:27:57 -03001478};
1479
1480static const struct dc_calibration dc_table[] = {
1481 /* Step1 BB gain1= 26 with boost 1, gain 2 = 0 */
1482 {0x06, 5, 1, (1 << 13) | (0 << 8) | (26 << 3), 1},
1483 {0x07, 11, 1, (1 << 13) | (0 << 8) | (26 << 3), 0},
1484 /* Step 2 BB gain 1 = 26 with boost = 1 & gain 2 = 29 */
1485 {0x06, 0, 0, (1 << 13) | (29 << 8) | (26 << 3), 1},
1486 {0x06, 10, 0, (1 << 13) | (29 << 8) | (26 << 3), 0},
1487 {0},
1488};
1489
Olivier Grenie28fafca2011-01-04 04:27:11 -03001490static const struct dc_calibration dc_p1g_table[] = {
1491 /* Step1 BB gain1= 26 with boost 1, gain 2 = 0 */
1492 /* addr ; trim reg offset ; pga ; CTRL_BB1 value ; i or q */
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001493 {0x06, 5, 1, (1 << 13) | (0 << 8) | (15 << 3), 1},
1494 {0x07, 11, 1, (1 << 13) | (0 << 8) | (15 << 3), 0},
Olivier Grenie28fafca2011-01-04 04:27:11 -03001495 /* Step 2 BB gain 1 = 26 with boost = 1 & gain 2 = 29 */
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001496 {0x06, 0, 0, (1 << 13) | (29 << 8) | (15 << 3), 1},
1497 {0x06, 10, 0, (1 << 13) | (29 << 8) | (15 << 3), 0},
Olivier Grenie28fafca2011-01-04 04:27:11 -03001498 {0},
1499};
1500
Olivier Grenie03245a52009-12-04 13:27:57 -03001501static void dib0090_set_trim(struct dib0090_state *state)
1502{
1503 u16 *val;
1504
1505 if (state->dc->addr == 0x07)
1506 val = &state->bb7;
1507 else
1508 val = &state->bb6;
1509
1510 *val &= ~(0x1f << state->dc->offset);
1511 *val |= state->step << state->dc->offset;
1512
1513 dib0090_write_reg(state, state->dc->addr, *val);
1514}
1515
1516static int dib0090_dc_offset_calibration(struct dib0090_state *state, enum frontend_tune_state *tune_state)
1517{
1518 int ret = 0;
Olivier Grenie28fafca2011-01-04 04:27:11 -03001519 u16 reg;
Olivier Grenie03245a52009-12-04 13:27:57 -03001520
1521 switch (*tune_state) {
Olivier Grenie03245a52009-12-04 13:27:57 -03001522 case CT_TUNER_START:
Olivier Grenie28fafca2011-01-04 04:27:11 -03001523 dprintk("Start DC offset calibration");
Olivier Grenie03245a52009-12-04 13:27:57 -03001524
1525 /* force vcm2 = 0.8V */
1526 state->bb6 = 0;
1527 state->bb7 = 0x040d;
1528
Olivier Grenie28fafca2011-01-04 04:27:11 -03001529 /* the LNA AND LO are off */
1530 reg = dib0090_read_reg(state, 0x24) & 0x0ffb; /* shutdown lna and lo */
1531 dib0090_write_reg(state, 0x24, reg);
1532
1533 state->wbdmux = dib0090_read_reg(state, 0x10);
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001534 dib0090_write_reg(state, 0x10, (state->wbdmux & ~(0xff << 3)) | (0x7 << 3) | 0x3);
1535 dib0090_write_reg(state, 0x23, dib0090_read_reg(state, 0x23) & ~(1 << 14));
Olivier Grenie28fafca2011-01-04 04:27:11 -03001536
Olivier Grenie03245a52009-12-04 13:27:57 -03001537 state->dc = dc_table;
1538
Olivier Grenie28fafca2011-01-04 04:27:11 -03001539 if (state->identity.p1g)
1540 state->dc = dc_p1g_table;
Olivier Grenie03245a52009-12-04 13:27:57 -03001541 *tune_state = CT_TUNER_STEP_0;
1542
1543 /* fall through */
1544
1545 case CT_TUNER_STEP_0:
Olivier Grenie28fafca2011-01-04 04:27:11 -03001546 dprintk("Sart/continue DC calibration for %s path", (state->dc->i == 1) ? "I" : "Q");
Olivier Grenie03245a52009-12-04 13:27:57 -03001547 dib0090_write_reg(state, 0x01, state->dc->bb1);
1548 dib0090_write_reg(state, 0x07, state->bb7 | (state->dc->i << 7));
1549
1550 state->step = 0;
Olivier Grenie03245a52009-12-04 13:27:57 -03001551 state->min_adc_diff = 1023;
Olivier Grenie03245a52009-12-04 13:27:57 -03001552 *tune_state = CT_TUNER_STEP_1;
1553 ret = 50;
1554 break;
1555
1556 case CT_TUNER_STEP_1:
1557 dib0090_set_trim(state);
Olivier Grenie03245a52009-12-04 13:27:57 -03001558 *tune_state = CT_TUNER_STEP_2;
1559 break;
1560
1561 case CT_TUNER_STEP_2:
1562 case CT_TUNER_STEP_3:
1563 case CT_TUNER_STEP_4:
1564 ret = dib0090_get_offset(state, tune_state);
1565 break;
1566
1567 case CT_TUNER_STEP_5: /* found an offset */
Olivier Grenie28fafca2011-01-04 04:27:11 -03001568 dprintk("adc_diff = %d, current step= %d", (u32) state->adc_diff, state->step);
1569 if (state->step == 0 && state->adc_diff < 0) {
1570 state->min_adc_diff = -1023;
1571 dprintk("Change of sign of the minimum adc diff");
1572 }
1573
1574 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 -03001575
1576 /* first turn for this frequency */
1577 if (state->step == 0) {
1578 if (state->dc->pga && state->adc_diff < 0)
1579 state->step = 0x10;
1580 if (state->dc->pga == 0 && state->adc_diff > 0)
1581 state->step = 0x10;
1582 }
1583
Olivier Grenie28fafca2011-01-04 04:27:11 -03001584 /* Look for a change of Sign in the Adc_diff.min_adc_diff is used to STORE the setp N-1 */
1585 if ((state->adc_diff & 0x8000) == (state->min_adc_diff & 0x8000) && steps(state->step) < 15) {
1586 /* stop search when the delta the sign is changing and Steps =15 and Step=0 is force for continuance */
Olivier Grenie03245a52009-12-04 13:27:57 -03001587 state->step++;
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001588 state->min_adc_diff = state->adc_diff;
Olivier Grenie03245a52009-12-04 13:27:57 -03001589 *tune_state = CT_TUNER_STEP_1;
1590 } else {
Olivier Grenie03245a52009-12-04 13:27:57 -03001591 /* the minimum was what we have seen in the step before */
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001592 if (ABS(state->adc_diff) > ABS(state->min_adc_diff)) {
Olivier Grenie28fafca2011-01-04 04:27:11 -03001593 dprintk("Since adc_diff N = %d > adc_diff step N-1 = %d, Come back one step", state->adc_diff, state->min_adc_diff);
1594 state->step--;
1595 }
Olivier Grenie03245a52009-12-04 13:27:57 -03001596
Olivier Grenie28fafca2011-01-04 04:27:11 -03001597 dib0090_set_trim(state);
1598 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 -03001599
1600 state->dc++;
1601 if (state->dc->addr == 0) /* done */
1602 *tune_state = CT_TUNER_STEP_6;
1603 else
1604 *tune_state = CT_TUNER_STEP_0;
1605
1606 }
1607 break;
1608
1609 case CT_TUNER_STEP_6:
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001610 dib0090_write_reg(state, 0x07, state->bb7 & ~0x0008);
Olivier Grenie03245a52009-12-04 13:27:57 -03001611 dib0090_write_reg(state, 0x1f, 0x7);
1612 *tune_state = CT_TUNER_START; /* reset done -> real tuning can now begin */
Olivier Grenie28fafca2011-01-04 04:27:11 -03001613 state->calibrate &= ~DC_CAL;
Olivier Grenie03245a52009-12-04 13:27:57 -03001614 default:
1615 break;
1616 }
1617 return ret;
1618}
1619
1620static int dib0090_wbd_calibration(struct dib0090_state *state, enum frontend_tune_state *tune_state)
1621{
Olivier Grenie28fafca2011-01-04 04:27:11 -03001622 u8 wbd_gain;
1623 const struct dib0090_wbd_slope *wbd = state->current_wbd_table;
1624
Olivier Grenie03245a52009-12-04 13:27:57 -03001625 switch (*tune_state) {
1626 case CT_TUNER_START:
Olivier Grenie28fafca2011-01-04 04:27:11 -03001627 while (state->current_rf / 1000 > wbd->max_freq)
1628 wbd++;
1629 if (wbd->wbd_gain != 0)
1630 wbd_gain = wbd->wbd_gain;
1631 else {
1632 wbd_gain = 4;
1633#if defined(CONFIG_BAND_LBAND) || defined(CONFIG_BAND_SBAND)
1634 if ((state->current_band == BAND_LBAND) || (state->current_band == BAND_SBAND))
1635 wbd_gain = 2;
1636#endif
1637 }
Olivier Grenie03245a52009-12-04 13:27:57 -03001638
Olivier Grenie28fafca2011-01-04 04:27:11 -03001639 if (wbd_gain == state->wbd_calibration_gain) { /* the WBD calibration has already been done */
1640 *tune_state = CT_TUNER_START;
1641 state->calibrate &= ~WBD_CAL;
1642 return 0;
1643 }
1644
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001645 dib0090_write_reg(state, 0x10, 0x1b81 | (1 << 10) | (wbd_gain << 13) | (1 << 3));
Olivier Grenie28fafca2011-01-04 04:27:11 -03001646
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001647 dib0090_write_reg(state, 0x24, ((EN_UHF & 0x0fff) | (1 << 1)));
Olivier Grenie03245a52009-12-04 13:27:57 -03001648 *tune_state = CT_TUNER_STEP_0;
Olivier Grenie28fafca2011-01-04 04:27:11 -03001649 state->wbd_calibration_gain = wbd_gain;
Olivier Grenie03245a52009-12-04 13:27:57 -03001650 return 90; /* wait for the WBDMUX to switch and for the ADC to sample */
Olivier Grenie03245a52009-12-04 13:27:57 -03001651
Olivier Grenie28fafca2011-01-04 04:27:11 -03001652 case CT_TUNER_STEP_0:
1653 state->wbd_offset = dib0090_get_slow_adc_val(state);
1654 dprintk("WBD calibration offset = %d", state->wbd_offset);
Olivier Grenie03245a52009-12-04 13:27:57 -03001655 *tune_state = CT_TUNER_START; /* reset done -> real tuning can now begin */
Olivier Grenie28fafca2011-01-04 04:27:11 -03001656 state->calibrate &= ~WBD_CAL;
Olivier Grenie03245a52009-12-04 13:27:57 -03001657 break;
Olivier Grenie28fafca2011-01-04 04:27:11 -03001658
Olivier Grenie03245a52009-12-04 13:27:57 -03001659 default:
1660 break;
1661 }
1662 return 0;
1663}
1664
1665static void dib0090_set_bandwidth(struct dib0090_state *state)
1666{
1667 u16 tmp;
1668
1669 if (state->fe->dtv_property_cache.bandwidth_hz / 1000 <= 5000)
1670 tmp = (3 << 14);
1671 else if (state->fe->dtv_property_cache.bandwidth_hz / 1000 <= 6000)
1672 tmp = (2 << 14);
1673 else if (state->fe->dtv_property_cache.bandwidth_hz / 1000 <= 7000)
1674 tmp = (1 << 14);
1675 else
1676 tmp = (0 << 14);
1677
1678 state->bb_1_def &= 0x3fff;
1679 state->bb_1_def |= tmp;
1680
1681 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 -03001682
1683 dib0090_write_reg(state, 0x03, 0x6008); /* = 0x6008 : vcm3_trim = 1 ; filter2_gm1_trim = 8 ; filter2_cutoff_freq = 0 */
1684 dib0090_write_reg(state, 0x04, 0x1); /* 0 = 1KHz ; 1 = 50Hz ; 2 = 150Hz ; 3 = 50KHz ; 4 = servo fast */
1685 if (state->identity.in_soc) {
1686 dib0090_write_reg(state, 0x05, 0x9bcf); /* attenuator_ibias_tri = 2 ; input_stage_ibias_tr = 1 ; nc = 11 ; ext_gm_trim = 1 ; obuf_ibias_trim = 4 ; filter13_gm2_ibias_t = 15 */
1687 } else {
1688 dib0090_write_reg(state, 0x02, (5 << 11) | (8 << 6) | (22 & 0x3f)); /* 22 = cap_value */
1689 dib0090_write_reg(state, 0x05, 0xabcd); /* = 0xabcd : attenuator_ibias_tri = 2 ; input_stage_ibias_tr = 2 ; nc = 11 ; ext_gm_trim = 1 ; obuf_ibias_trim = 4 ; filter13_gm2_ibias_t = 13 */
1690 }
Olivier Grenie03245a52009-12-04 13:27:57 -03001691}
1692
1693static const struct dib0090_pll dib0090_pll_table[] = {
1694#ifdef CONFIG_BAND_CBAND
1695 {56000, 0, 9, 48, 6},
1696 {70000, 1, 9, 48, 6},
1697 {87000, 0, 8, 32, 4},
1698 {105000, 1, 8, 32, 4},
1699 {115000, 0, 7, 24, 6},
1700 {140000, 1, 7, 24, 6},
1701 {170000, 0, 6, 16, 4},
1702#endif
1703#ifdef CONFIG_BAND_VHF
1704 {200000, 1, 6, 16, 4},
1705 {230000, 0, 5, 12, 6},
1706 {280000, 1, 5, 12, 6},
1707 {340000, 0, 4, 8, 4},
1708 {380000, 1, 4, 8, 4},
1709 {450000, 0, 3, 6, 6},
1710#endif
1711#ifdef CONFIG_BAND_UHF
1712 {580000, 1, 3, 6, 6},
1713 {700000, 0, 2, 4, 4},
1714 {860000, 1, 2, 4, 4},
1715#endif
1716#ifdef CONFIG_BAND_LBAND
1717 {1800000, 1, 0, 2, 4},
1718#endif
1719#ifdef CONFIG_BAND_SBAND
1720 {2900000, 0, 14, 1, 4},
1721#endif
1722};
1723
1724static const struct dib0090_tuning dib0090_tuning_table_fm_vhf_on_cband[] = {
1725
1726#ifdef CONFIG_BAND_CBAND
1727 {184000, 4, 1, 15, 0x280, 0x2912, 0xb94e, EN_CAB},
1728 {227000, 4, 3, 15, 0x280, 0x2912, 0xb94e, EN_CAB},
1729 {380000, 4, 7, 15, 0x280, 0x2912, 0xb94e, EN_CAB},
1730#endif
1731#ifdef CONFIG_BAND_UHF
1732 {520000, 2, 0, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},
1733 {550000, 2, 2, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},
1734 {650000, 2, 3, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},
1735 {750000, 2, 5, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},
1736 {850000, 2, 6, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},
1737 {900000, 2, 7, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},
1738#endif
1739#ifdef CONFIG_BAND_LBAND
1740 {1500000, 4, 0, 20, 0x300, 0x1912, 0x82c9, EN_LBD},
1741 {1600000, 4, 1, 20, 0x300, 0x1912, 0x82c9, EN_LBD},
1742 {1800000, 4, 3, 20, 0x300, 0x1912, 0x82c9, EN_LBD},
1743#endif
1744#ifdef CONFIG_BAND_SBAND
1745 {2300000, 1, 4, 20, 0x300, 0x2d2A, 0x82c7, EN_SBD},
1746 {2900000, 1, 7, 20, 0x280, 0x2deb, 0x8347, EN_SBD},
1747#endif
1748};
1749
1750static const struct dib0090_tuning dib0090_tuning_table[] = {
1751
1752#ifdef CONFIG_BAND_CBAND
1753 {170000, 4, 1, 15, 0x280, 0x2912, 0xb94e, EN_CAB},
1754#endif
1755#ifdef CONFIG_BAND_VHF
1756 {184000, 1, 1, 15, 0x300, 0x4d12, 0xb94e, EN_VHF},
1757 {227000, 1, 3, 15, 0x300, 0x4d12, 0xb94e, EN_VHF},
1758 {380000, 1, 7, 15, 0x300, 0x4d12, 0xb94e, EN_VHF},
1759#endif
1760#ifdef CONFIG_BAND_UHF
1761 {520000, 2, 0, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},
1762 {550000, 2, 2, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},
1763 {650000, 2, 3, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},
1764 {750000, 2, 5, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},
1765 {850000, 2, 6, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},
1766 {900000, 2, 7, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},
1767#endif
1768#ifdef CONFIG_BAND_LBAND
1769 {1500000, 4, 0, 20, 0x300, 0x1912, 0x82c9, EN_LBD},
1770 {1600000, 4, 1, 20, 0x300, 0x1912, 0x82c9, EN_LBD},
1771 {1800000, 4, 3, 20, 0x300, 0x1912, 0x82c9, EN_LBD},
1772#endif
1773#ifdef CONFIG_BAND_SBAND
1774 {2300000, 1, 4, 20, 0x300, 0x2d2A, 0x82c7, EN_SBD},
1775 {2900000, 1, 7, 20, 0x280, 0x2deb, 0x8347, EN_SBD},
1776#endif
1777};
1778
Olivier Grenie28fafca2011-01-04 04:27:11 -03001779static const struct dib0090_tuning dib0090_p1g_tuning_table[] = {
Olivier Grenie28fafca2011-01-04 04:27:11 -03001780#ifdef CONFIG_BAND_CBAND
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001781 {170000, 4, 1, 0x820f, 0x300, 0x2d22, 0x82cb, EN_CAB},
Olivier Grenie28fafca2011-01-04 04:27:11 -03001782#endif
1783#ifdef CONFIG_BAND_VHF
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001784 {184000, 1, 1, 15, 0x300, 0x4d12, 0xb94e, EN_VHF},
1785 {227000, 1, 3, 15, 0x300, 0x4d12, 0xb94e, EN_VHF},
1786 {380000, 1, 7, 15, 0x300, 0x4d12, 0xb94e, EN_VHF},
Olivier Grenie28fafca2011-01-04 04:27:11 -03001787#endif
1788#ifdef CONFIG_BAND_UHF
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001789 {510000, 2, 0, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},
1790 {540000, 2, 1, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},
1791 {600000, 2, 3, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},
1792 {630000, 2, 4, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},
1793 {680000, 2, 5, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},
1794 {720000, 2, 6, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},
1795 {900000, 2, 7, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},
Olivier Grenie28fafca2011-01-04 04:27:11 -03001796#endif
1797#ifdef CONFIG_BAND_LBAND
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001798 {1500000, 4, 0, 20, 0x300, 0x1912, 0x82c9, EN_LBD},
1799 {1600000, 4, 1, 20, 0x300, 0x1912, 0x82c9, EN_LBD},
1800 {1800000, 4, 3, 20, 0x300, 0x1912, 0x82c9, EN_LBD},
Olivier Grenie28fafca2011-01-04 04:27:11 -03001801#endif
1802#ifdef CONFIG_BAND_SBAND
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001803 {2300000, 1, 4, 20, 0x300, 0x2d2A, 0x82c7, EN_SBD},
1804 {2900000, 1, 7, 20, 0x280, 0x2deb, 0x8347, EN_SBD},
Olivier Grenie28fafca2011-01-04 04:27:11 -03001805#endif
1806};
1807
1808static const struct dib0090_pll dib0090_p1g_pll_table[] = {
1809#ifdef CONFIG_BAND_CBAND
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001810 {57000, 0, 11, 48, 6},
1811 {70000, 1, 11, 48, 6},
1812 {86000, 0, 10, 32, 4},
1813 {105000, 1, 10, 32, 4},
1814 {115000, 0, 9, 24, 6},
1815 {140000, 1, 9, 24, 6},
1816 {170000, 0, 8, 16, 4},
Olivier Grenie28fafca2011-01-04 04:27:11 -03001817#endif
1818#ifdef CONFIG_BAND_VHF
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001819 {200000, 1, 8, 16, 4},
1820 {230000, 0, 7, 12, 6},
1821 {280000, 1, 7, 12, 6},
1822 {340000, 0, 6, 8, 4},
1823 {380000, 1, 6, 8, 4},
1824 {455000, 0, 5, 6, 6},
Olivier Grenie28fafca2011-01-04 04:27:11 -03001825#endif
1826#ifdef CONFIG_BAND_UHF
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001827 {580000, 1, 5, 6, 6},
1828 {680000, 0, 4, 4, 4},
1829 {860000, 1, 4, 4, 4},
Olivier Grenie28fafca2011-01-04 04:27:11 -03001830#endif
1831#ifdef CONFIG_BAND_LBAND
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001832 {1800000, 1, 2, 2, 4},
Olivier Grenie28fafca2011-01-04 04:27:11 -03001833#endif
1834#ifdef CONFIG_BAND_SBAND
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001835 {2900000, 0, 1, 1, 6},
Olivier Grenie28fafca2011-01-04 04:27:11 -03001836#endif
1837};
1838
1839static const struct dib0090_tuning dib0090_p1g_tuning_table_fm_vhf_on_cband[] = {
Olivier Grenie28fafca2011-01-04 04:27:11 -03001840#ifdef CONFIG_BAND_CBAND
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001841 {184000, 4, 3, 0x4187, 0x2c0, 0x2d22, 0x81cb, EN_CAB},
1842 {227000, 4, 3, 0x4187, 0x2c0, 0x2d22, 0x81cb, EN_CAB},
1843 {380000, 4, 3, 0x4187, 0x2c0, 0x2d22, 0x81cb, EN_CAB},
Olivier Grenie28fafca2011-01-04 04:27:11 -03001844#endif
1845#ifdef CONFIG_BAND_UHF
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001846 {520000, 2, 0, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},
1847 {550000, 2, 2, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},
1848 {650000, 2, 3, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},
1849 {750000, 2, 5, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},
1850 {850000, 2, 6, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},
1851 {900000, 2, 7, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},
Olivier Grenie28fafca2011-01-04 04:27:11 -03001852#endif
1853#ifdef CONFIG_BAND_LBAND
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001854 {1500000, 4, 0, 20, 0x300, 0x1912, 0x82c9, EN_LBD},
1855 {1600000, 4, 1, 20, 0x300, 0x1912, 0x82c9, EN_LBD},
1856 {1800000, 4, 3, 20, 0x300, 0x1912, 0x82c9, EN_LBD},
Olivier Grenie28fafca2011-01-04 04:27:11 -03001857#endif
1858#ifdef CONFIG_BAND_SBAND
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001859 {2300000, 1, 4, 20, 0x300, 0x2d2A, 0x82c7, EN_SBD},
1860 {2900000, 1, 7, 20, 0x280, 0x2deb, 0x8347, EN_SBD},
Olivier Grenie28fafca2011-01-04 04:27:11 -03001861#endif
1862};
1863
1864static const struct dib0090_tuning dib0090_tuning_table_cband_7090[] = {
Olivier Grenie28fafca2011-01-04 04:27:11 -03001865#ifdef CONFIG_BAND_CBAND
Olivier Grenie28fafca2011-01-04 04:27:11 -03001866 {300000, 4, 3, 0x018F, 0x2c0, 0x2d22, 0xb9ce, EN_CAB},
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001867 {380000, 4, 10, 0x018F, 0x2c0, 0x2d22, 0xb9ce, EN_CAB},
Olivier Grenie28fafca2011-01-04 04:27:11 -03001868 {570000, 4, 10, 0x8190, 0x2c0, 0x2d22, 0xb9ce, EN_CAB},
1869 {858000, 4, 5, 0x8190, 0x2c0, 0x2d22, 0xb9ce, EN_CAB},
1870#endif
1871};
1872
1873static int dib0090_captrim_search(struct dib0090_state *state, enum frontend_tune_state *tune_state)
1874{
1875 int ret = 0;
1876 u16 lo4 = 0xe900;
1877
1878 s16 adc_target;
1879 u16 adc;
1880 s8 step_sign;
1881 u8 force_soft_search = 0;
1882
1883 if (state->identity.version == SOC_8090_P1G_11R1 || state->identity.version == SOC_8090_P1G_21R1)
1884 force_soft_search = 1;
1885
1886 if (*tune_state == CT_TUNER_START) {
1887 dprintk("Start Captrim search : %s", (force_soft_search == 1) ? "FORCE SOFT SEARCH" : "AUTO");
1888 dib0090_write_reg(state, 0x10, 0x2B1);
1889 dib0090_write_reg(state, 0x1e, 0x0032);
1890
1891 if (!state->tuner_is_tuned) {
1892 /* prepare a complete captrim */
1893 if (!state->identity.p1g || force_soft_search)
1894 state->step = state->captrim = state->fcaptrim = 64;
1895
1896 state->current_rf = state->rf_request;
1897 } else { /* we are already tuned to this frequency - the configuration is correct */
1898 if (!state->identity.p1g || force_soft_search) {
1899 /* do a minimal captrim even if the frequency has not changed */
1900 state->step = 4;
1901 state->captrim = state->fcaptrim = dib0090_read_reg(state, 0x18) & 0x7f;
1902 }
1903 }
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001904 state->adc_diff = 3000;
Olivier Grenie28fafca2011-01-04 04:27:11 -03001905 *tune_state = CT_TUNER_STEP_0;
1906
1907 } else if (*tune_state == CT_TUNER_STEP_0) {
1908 if (state->identity.p1g && !force_soft_search) {
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001909 u8 ratio = 31;
Olivier Grenie28fafca2011-01-04 04:27:11 -03001910
1911 dib0090_write_reg(state, 0x40, (3 << 7) | (ratio << 2) | (1 << 1) | 1);
1912 dib0090_read_reg(state, 0x40);
Olivier Grenie28fafca2011-01-04 04:27:11 -03001913 ret = 50;
1914 } else {
1915 state->step /= 2;
1916 dib0090_write_reg(state, 0x18, lo4 | state->captrim);
1917
1918 if (state->identity.in_soc)
1919 ret = 25;
1920 }
1921 *tune_state = CT_TUNER_STEP_1;
1922
1923 } else if (*tune_state == CT_TUNER_STEP_1) {
1924 if (state->identity.p1g && !force_soft_search) {
1925 dib0090_write_reg(state, 0x40, 0x18c | (0 << 1) | 0);
1926 dib0090_read_reg(state, 0x40);
1927
1928 state->fcaptrim = dib0090_read_reg(state, 0x18) & 0x7F;
1929 dprintk("***Final Captrim= 0x%x", state->fcaptrim);
1930 *tune_state = CT_TUNER_STEP_3;
1931
1932 } else {
1933 /* MERGE for all krosus before P1G */
1934 adc = dib0090_get_slow_adc_val(state);
1935 dprintk("CAPTRIM=%d; ADC = %d (ADC) & %dmV", (u32) state->captrim, (u32) adc, (u32) (adc) * (u32) 1800 / (u32) 1024);
1936
1937 if (state->rest == 0 || state->identity.in_soc) { /* Just for 8090P SOCS where auto captrim HW bug : TO CHECK IN ACI for SOCS !!! if 400 for 8090p SOC => tune issue !!! */
1938 adc_target = 200;
1939 } else
1940 adc_target = 400;
1941
1942 if (adc >= adc_target) {
1943 adc -= adc_target;
1944 step_sign = -1;
1945 } else {
1946 adc = adc_target - adc;
1947 step_sign = 1;
1948 }
1949
1950 if (adc < state->adc_diff) {
1951 dprintk("CAPTRIM=%d is closer to target (%d/%d)", (u32) state->captrim, (u32) adc, (u32) state->adc_diff);
1952 state->adc_diff = adc;
1953 state->fcaptrim = state->captrim;
Olivier Grenie28fafca2011-01-04 04:27:11 -03001954 }
1955
1956 state->captrim += step_sign * state->step;
1957 if (state->step >= 1)
1958 *tune_state = CT_TUNER_STEP_0;
1959 else
1960 *tune_state = CT_TUNER_STEP_2;
1961
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001962 ret = 25;
Olivier Grenie28fafca2011-01-04 04:27:11 -03001963 }
1964 } else if (*tune_state == CT_TUNER_STEP_2) { /* this step is only used by krosus < P1G */
1965 /*write the final cptrim config */
1966 dib0090_write_reg(state, 0x18, lo4 | state->fcaptrim);
1967
1968 *tune_state = CT_TUNER_STEP_3;
1969
1970 } else if (*tune_state == CT_TUNER_STEP_3) {
1971 state->calibrate &= ~CAPTRIM_CAL;
1972 *tune_state = CT_TUNER_STEP_0;
1973 }
1974
1975 return ret;
1976}
1977
1978static int dib0090_get_temperature(struct dib0090_state *state, enum frontend_tune_state *tune_state)
1979{
1980 int ret = 15;
1981 s16 val;
1982
Olivier Grenie28fafca2011-01-04 04:27:11 -03001983 switch (*tune_state) {
1984 case CT_TUNER_START:
1985 state->wbdmux = dib0090_read_reg(state, 0x10);
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001986 dib0090_write_reg(state, 0x10, (state->wbdmux & ~(0xff << 3)) | (0x8 << 3));
Olivier Grenie28fafca2011-01-04 04:27:11 -03001987
1988 state->bias = dib0090_read_reg(state, 0x13);
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001989 dib0090_write_reg(state, 0x13, state->bias | (0x3 << 8));
Olivier Grenie28fafca2011-01-04 04:27:11 -03001990
1991 *tune_state = CT_TUNER_STEP_0;
1992 /* wait for the WBDMUX to switch and for the ADC to sample */
1993 break;
1994
1995 case CT_TUNER_STEP_0:
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001996 state->adc_diff = dib0090_get_slow_adc_val(state);
1997 dib0090_write_reg(state, 0x13, (state->bias & ~(0x3 << 8)) | (0x2 << 8));
Olivier Grenie28fafca2011-01-04 04:27:11 -03001998 *tune_state = CT_TUNER_STEP_1;
1999 break;
2000
2001 case CT_TUNER_STEP_1:
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002002 val = dib0090_get_slow_adc_val(state);
2003 state->temperature = ((s16) ((val - state->adc_diff) * 180) >> 8) + 55;
Olivier Grenie28fafca2011-01-04 04:27:11 -03002004
2005 dprintk("temperature: %d C", state->temperature - 30);
2006
2007 *tune_state = CT_TUNER_STEP_2;
2008 break;
2009
2010 case CT_TUNER_STEP_2:
Olivier Grenie28fafca2011-01-04 04:27:11 -03002011 dib0090_write_reg(state, 0x13, state->bias);
2012 dib0090_write_reg(state, 0x10, state->wbdmux); /* write back original WBDMUX */
2013
2014 *tune_state = CT_TUNER_START;
2015 state->calibrate &= ~TEMP_CAL;
2016 if (state->config->analog_output == 0)
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002017 dib0090_write_reg(state, 0x23, dib0090_read_reg(state, 0x23) | (1 << 14));
Olivier Grenie28fafca2011-01-04 04:27:11 -03002018
2019 break;
2020
2021 default:
2022 ret = 0;
2023 break;
2024 }
2025 return ret;
2026}
2027
Olivier Grenie03245a52009-12-04 13:27:57 -03002028#define WBD 0x781 /* 1 1 1 1 0000 0 0 1 */
2029static int dib0090_tune(struct dvb_frontend *fe)
2030{
2031 struct dib0090_state *state = fe->tuner_priv;
2032 const struct dib0090_tuning *tune = state->current_tune_table_index;
2033 const struct dib0090_pll *pll = state->current_pll_table_index;
2034 enum frontend_tune_state *tune_state = &state->tune_state;
2035
Olivier Grenie28fafca2011-01-04 04:27:11 -03002036 u16 lo5, lo6, Den, tmp;
Olivier Grenie03245a52009-12-04 13:27:57 -03002037 u32 FBDiv, Rest, FREF, VCOF_kHz = 0;
Olivier Grenie03245a52009-12-04 13:27:57 -03002038 int ret = 10; /* 1ms is the default delay most of the time */
2039 u8 c, i;
2040
Olivier Grenie28fafca2011-01-04 04:27:11 -03002041 /************************* VCO ***************************/
Olivier Grenie03245a52009-12-04 13:27:57 -03002042 /* Default values for FG */
2043 /* from these are needed : */
2044 /* Cp,HFdiv,VCOband,SD,Num,Den,FB and REFDiv */
2045
Olivier Grenie28fafca2011-01-04 04:27:11 -03002046 /* in any case we first need to do a calibration if needed */
2047 if (*tune_state == CT_TUNER_START) {
2048 /* deactivate DataTX before some calibrations */
2049 if (state->calibrate & (DC_CAL | TEMP_CAL | WBD_CAL))
2050 dib0090_write_reg(state, 0x23, dib0090_read_reg(state, 0x23) & ~(1 << 14));
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002051 else
2052 /* Activate DataTX in case a calibration has been done before */
2053 if (state->config->analog_output == 0)
2054 dib0090_write_reg(state, 0x23, dib0090_read_reg(state, 0x23) | (1 << 14));
Olivier Grenie03245a52009-12-04 13:27:57 -03002055 }
2056
Olivier Grenie28fafca2011-01-04 04:27:11 -03002057 if (state->calibrate & DC_CAL)
2058 return dib0090_dc_offset_calibration(state, tune_state);
2059 else if (state->calibrate & WBD_CAL) {
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002060 if (state->current_rf == 0)
Olivier Grenie28fafca2011-01-04 04:27:11 -03002061 state->current_rf = state->fe->dtv_property_cache.frequency / 1000;
Olivier Grenie28fafca2011-01-04 04:27:11 -03002062 return dib0090_wbd_calibration(state, tune_state);
2063 } else if (state->calibrate & TEMP_CAL)
2064 return dib0090_get_temperature(state, tune_state);
2065 else if (state->calibrate & CAPTRIM_CAL)
2066 return dib0090_captrim_search(state, tune_state);
2067
Olivier Grenie03245a52009-12-04 13:27:57 -03002068 if (*tune_state == CT_TUNER_START) {
Olivier Grenie28fafca2011-01-04 04:27:11 -03002069 /* if soc and AGC pwm control, disengage mux to be able to R/W access to 0x01 register to set the right filter (cutoff_freq_select) during the tune sequence, otherwise, SOC SERPAR error when accessing to 0x01 */
2070 if (state->config->use_pwm_agc && state->identity.in_soc) {
2071 tmp = dib0090_read_reg(state, 0x39);
2072 if ((tmp >> 10) & 0x1)
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002073 dib0090_write_reg(state, 0x39, tmp & ~(1 << 10));
Olivier Grenie28fafca2011-01-04 04:27:11 -03002074 }
Olivier Grenie03245a52009-12-04 13:27:57 -03002075
Olivier Grenie28fafca2011-01-04 04:27:11 -03002076 state->current_band = (u8) BAND_OF_FREQUENCY(state->fe->dtv_property_cache.frequency / 1000);
2077 state->rf_request =
2078 state->fe->dtv_property_cache.frequency / 1000 + (state->current_band ==
2079 BAND_UHF ? state->config->freq_offset_khz_uhf : state->config->
2080 freq_offset_khz_vhf);
2081
2082 /* in ISDB-T 1seg we shift tuning frequency */
2083 if ((state->fe->dtv_property_cache.delivery_system == SYS_ISDBT && state->fe->dtv_property_cache.isdbt_sb_mode == 1
2084 && state->fe->dtv_property_cache.isdbt_partial_reception == 0)) {
2085 const struct dib0090_low_if_offset_table *LUT_offset = state->config->low_if;
2086 u8 found_offset = 0;
2087 u32 margin_khz = 100;
2088
2089 if (LUT_offset != NULL) {
2090 while (LUT_offset->RF_freq != 0xffff) {
2091 if (((state->rf_request > (LUT_offset->RF_freq - margin_khz))
2092 && (state->rf_request < (LUT_offset->RF_freq + margin_khz)))
2093 && LUT_offset->std == state->fe->dtv_property_cache.delivery_system) {
2094 state->rf_request += LUT_offset->offset_khz;
2095 found_offset = 1;
2096 break;
2097 }
2098 LUT_offset++;
2099 }
2100 }
2101
2102 if (found_offset == 0)
2103 state->rf_request += 400;
2104 }
2105 if (state->current_rf != state->rf_request || (state->current_standard != state->fe->dtv_property_cache.delivery_system)) {
2106 state->tuner_is_tuned = 0;
Olivier Grenie03245a52009-12-04 13:27:57 -03002107 state->current_rf = 0;
Olivier Grenie28fafca2011-01-04 04:27:11 -03002108 state->current_standard = 0;
Olivier Grenie03245a52009-12-04 13:27:57 -03002109
Olivier Grenie28fafca2011-01-04 04:27:11 -03002110 tune = dib0090_tuning_table;
2111 if (state->identity.p1g)
2112 tune = dib0090_p1g_tuning_table;
Olivier Grenie03245a52009-12-04 13:27:57 -03002113
Olivier Grenie28fafca2011-01-04 04:27:11 -03002114 tmp = (state->identity.version >> 5) & 0x7;
2115
2116 if (state->identity.in_soc) {
2117 if (state->config->force_cband_input) { /* Use the CBAND input for all band */
2118 if (state->current_band & BAND_CBAND || state->current_band & BAND_FM || state->current_band & BAND_VHF
2119 || state->current_band & BAND_UHF) {
2120 state->current_band = BAND_CBAND;
2121 tune = dib0090_tuning_table_cband_7090;
2122 }
2123 } else { /* Use the CBAND input for all band under UHF */
2124 if (state->current_band & BAND_CBAND || state->current_band & BAND_FM || state->current_band & BAND_VHF) {
2125 state->current_band = BAND_CBAND;
2126 tune = dib0090_tuning_table_cband_7090;
2127 }
2128 }
2129 } else
2130 if (tmp == 0x4 || tmp == 0x7) {
2131 /* CBAND tuner version for VHF */
2132 if (state->current_band == BAND_FM || state->current_band == BAND_CBAND || state->current_band == BAND_VHF) {
2133 state->current_band = BAND_CBAND; /* Force CBAND */
2134
2135 tune = dib0090_tuning_table_fm_vhf_on_cband;
2136 if (state->identity.p1g)
2137 tune = dib0090_p1g_tuning_table_fm_vhf_on_cband;
2138 }
2139 }
2140
2141 pll = dib0090_pll_table;
2142 if (state->identity.p1g)
2143 pll = dib0090_p1g_pll_table;
2144
2145 /* Look for the interval */
2146 while (state->rf_request > tune->max_freq)
2147 tune++;
2148 while (state->rf_request > pll->max_freq)
2149 pll++;
2150
2151 state->current_tune_table_index = tune;
2152 state->current_pll_table_index = pll;
2153
Olivier Grenie03245a52009-12-04 13:27:57 -03002154 dib0090_write_reg(state, 0x0b, 0xb800 | (tune->switch_trim));
2155
Olivier Grenie28fafca2011-01-04 04:27:11 -03002156 VCOF_kHz = (pll->hfdiv * state->rf_request) * 2;
Olivier Grenie03245a52009-12-04 13:27:57 -03002157
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002158 FREF = state->config->io.clock_khz;
Olivier Grenie28fafca2011-01-04 04:27:11 -03002159 if (state->config->fref_clock_ratio != 0)
2160 FREF /= state->config->fref_clock_ratio;
Olivier Grenie03245a52009-12-04 13:27:57 -03002161
Olivier Grenie03245a52009-12-04 13:27:57 -03002162 FBDiv = (VCOF_kHz / pll->topresc / FREF);
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002163 Rest = (VCOF_kHz / pll->topresc) - FBDiv * FREF;
Olivier Grenie03245a52009-12-04 13:27:57 -03002164
2165 if (Rest < LPF)
2166 Rest = 0;
2167 else if (Rest < 2 * LPF)
2168 Rest = 2 * LPF;
2169 else if (Rest > (FREF - LPF)) {
2170 Rest = 0;
2171 FBDiv += 1;
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002172 } else if (Rest > (FREF - 2 * LPF))
Olivier Grenie03245a52009-12-04 13:27:57 -03002173 Rest = FREF - 2 * LPF;
2174 Rest = (Rest * 6528) / (FREF / 10);
Olivier Grenie28fafca2011-01-04 04:27:11 -03002175 state->rest = Rest;
2176
2177 /* external loop filter, otherwise:
2178 * lo5 = (0 << 15) | (0 << 12) | (0 << 11) | (3 << 9) | (4 << 6) | (3 << 4) | 4;
2179 * lo6 = 0x0e34 */
2180
2181 if (Rest == 0) {
2182 if (pll->vco_band)
2183 lo5 = 0x049f;
Olivier Grenie28fafca2011-01-04 04:27:11 -03002184 else
2185 lo5 = 0x041f;
2186 } else {
2187 if (pll->vco_band)
2188 lo5 = 0x049e;
2189 else if (state->config->analog_output)
2190 lo5 = 0x041d;
2191 else
2192 lo5 = 0x041c;
2193 }
2194
2195 if (state->identity.p1g) { /* Bias is done automatically in P1G */
2196 if (state->identity.in_soc) {
2197 if (state->identity.version == SOC_8090_P1G_11R1)
2198 lo5 = 0x46f;
2199 else
2200 lo5 = 0x42f;
2201 } else
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002202 lo5 = 0x42c;
Olivier Grenie28fafca2011-01-04 04:27:11 -03002203 }
2204
2205 lo5 |= (pll->hfdiv_code << 11) | (pll->vco_band << 7); /* bit 15 is the split to the slave, we do not do it here */
2206
Olivier Grenie28fafca2011-01-04 04:27:11 -03002207 if (!state->config->io.pll_int_loop_filt) {
2208 if (state->identity.in_soc)
2209 lo6 = 0xff98;
2210 else if (state->identity.p1g || (Rest == 0))
2211 lo6 = 0xfff8;
2212 else
2213 lo6 = 0xff28;
2214 } else
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002215 lo6 = (state->config->io.pll_int_loop_filt << 3);
Olivier Grenie03245a52009-12-04 13:27:57 -03002216
2217 Den = 1;
2218
Olivier Grenie03245a52009-12-04 13:27:57 -03002219 if (Rest > 0) {
2220 if (state->config->analog_output)
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002221 lo6 |= (1 << 2) | 2;
Olivier Grenie28fafca2011-01-04 04:27:11 -03002222 else {
2223 if (state->identity.in_soc)
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002224 lo6 |= (1 << 2) | 2;
Olivier Grenie28fafca2011-01-04 04:27:11 -03002225 else
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002226 lo6 |= (1 << 2) | 2;
Olivier Grenie28fafca2011-01-04 04:27:11 -03002227 }
Olivier Grenie03245a52009-12-04 13:27:57 -03002228 Den = 255;
2229 }
Olivier Grenie03245a52009-12-04 13:27:57 -03002230 dib0090_write_reg(state, 0x15, (u16) FBDiv);
Olivier Grenie28fafca2011-01-04 04:27:11 -03002231 if (state->config->fref_clock_ratio != 0)
2232 dib0090_write_reg(state, 0x16, (Den << 8) | state->config->fref_clock_ratio);
2233 else
2234 dib0090_write_reg(state, 0x16, (Den << 8) | 1);
Olivier Grenie03245a52009-12-04 13:27:57 -03002235 dib0090_write_reg(state, 0x17, (u16) Rest);
Olivier Grenie03245a52009-12-04 13:27:57 -03002236 dib0090_write_reg(state, 0x19, lo5);
Olivier Grenie03245a52009-12-04 13:27:57 -03002237 dib0090_write_reg(state, 0x1c, lo6);
2238
2239 lo6 = tune->tuner_enable;
2240 if (state->config->analog_output)
2241 lo6 = (lo6 & 0xff9f) | 0x2;
2242
Olivier Grenie28fafca2011-01-04 04:27:11 -03002243 dib0090_write_reg(state, 0x24, lo6 | EN_LO | state->config->use_pwm_agc * EN_CRYSTAL);
Olivier Grenie03245a52009-12-04 13:27:57 -03002244
Olivier Grenie03245a52009-12-04 13:27:57 -03002245 }
Olivier Grenie03245a52009-12-04 13:27:57 -03002246
Olivier Grenie28fafca2011-01-04 04:27:11 -03002247 state->current_rf = state->rf_request;
2248 state->current_standard = state->fe->dtv_property_cache.delivery_system;
Olivier Grenie03245a52009-12-04 13:27:57 -03002249
2250 ret = 20;
Olivier Grenie28fafca2011-01-04 04:27:11 -03002251 state->calibrate = CAPTRIM_CAL; /* captrim serach now */
2252 }
Olivier Grenie03245a52009-12-04 13:27:57 -03002253
Olivier Grenie28fafca2011-01-04 04:27:11 -03002254 else if (*tune_state == CT_TUNER_STEP_0) { /* Warning : because of captrim cal, if you change this step, change it also in _cal.c file because it is the step following captrim cal state machine */
2255 const struct dib0090_wbd_slope *wbd = state->current_wbd_table;
Olivier Grenie03245a52009-12-04 13:27:57 -03002256
Olivier Grenie28fafca2011-01-04 04:27:11 -03002257 while (state->current_rf / 1000 > wbd->max_freq)
2258 wbd++;
Olivier Grenie03245a52009-12-04 13:27:57 -03002259
Olivier Grenie03245a52009-12-04 13:27:57 -03002260 dib0090_write_reg(state, 0x1e, 0x07ff);
Olivier Grenie28fafca2011-01-04 04:27:11 -03002261 dprintk("Final Captrim: %d", (u32) state->fcaptrim);
2262 dprintk("HFDIV code: %d", (u32) pll->hfdiv_code);
2263 dprintk("VCO = %d", (u32) pll->vco_band);
2264 dprintk("VCOF in kHz: %d ((%d*%d) << 1))", (u32) ((pll->hfdiv * state->rf_request) * 2), (u32) pll->hfdiv, (u32) state->rf_request);
2265 dprintk("REFDIV: %d, FREF: %d", (u32) 1, (u32) state->config->io.clock_khz);
2266 dprintk("FBDIV: %d, Rest: %d", (u32) dib0090_read_reg(state, 0x15), (u32) dib0090_read_reg(state, 0x17));
2267 dprintk("Num: %d, Den: %d, SD: %d", (u32) dib0090_read_reg(state, 0x17), (u32) (dib0090_read_reg(state, 0x16) >> 8),
2268 (u32) dib0090_read_reg(state, 0x1c) & 0x3);
Olivier Grenie03245a52009-12-04 13:27:57 -03002269
Olivier Grenie28fafca2011-01-04 04:27:11 -03002270#define WBD 0x781 /* 1 1 1 1 0000 0 0 1 */
Olivier Grenie03245a52009-12-04 13:27:57 -03002271 c = 4;
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002272 i = 3;
Olivier Grenie28fafca2011-01-04 04:27:11 -03002273
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002274 if (wbd->wbd_gain != 0)
Olivier Grenie28fafca2011-01-04 04:27:11 -03002275 c = wbd->wbd_gain;
2276
Olivier Grenie28fafca2011-01-04 04:27:11 -03002277 state->wbdmux = (c << 13) | (i << 11) | (WBD | (state->config->use_pwm_agc << 1));
2278 dib0090_write_reg(state, 0x10, state->wbdmux);
2279
2280 if ((tune->tuner_enable == EN_CAB) && state->identity.p1g) {
2281 dprintk("P1G : The cable band is selected and lna_tune = %d", tune->lna_tune);
2282 dib0090_write_reg(state, 0x09, tune->lna_bias);
2283 dib0090_write_reg(state, 0x0b, 0xb800 | (tune->lna_tune << 6) | (tune->switch_trim));
2284 } else
2285 dib0090_write_reg(state, 0x09, (tune->lna_tune << 5) | tune->lna_bias);
2286
Olivier Grenie03245a52009-12-04 13:27:57 -03002287 dib0090_write_reg(state, 0x0c, tune->v2i);
2288 dib0090_write_reg(state, 0x0d, tune->mix);
2289 dib0090_write_reg(state, 0x0e, tune->load);
Olivier Grenie28fafca2011-01-04 04:27:11 -03002290 *tune_state = CT_TUNER_STEP_1;
Olivier Grenie03245a52009-12-04 13:27:57 -03002291
Olivier Grenie28fafca2011-01-04 04:27:11 -03002292 } else if (*tune_state == CT_TUNER_STEP_1) {
Olivier Grenie03245a52009-12-04 13:27:57 -03002293 /* initialize the lt gain register */
2294 state->rf_lt_def = 0x7c00;
Olivier Grenie03245a52009-12-04 13:27:57 -03002295
2296 dib0090_set_bandwidth(state);
2297 state->tuner_is_tuned = 1;
Olivier Grenie28fafca2011-01-04 04:27:11 -03002298
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002299 state->calibrate |= WBD_CAL;
2300 state->calibrate |= TEMP_CAL;
Olivier Grenie03245a52009-12-04 13:27:57 -03002301 *tune_state = CT_TUNER_STOP;
2302 } else
2303 ret = FE_CALLBACK_TIME_NEVER;
2304 return ret;
2305}
2306
2307static int dib0090_release(struct dvb_frontend *fe)
2308{
2309 kfree(fe->tuner_priv);
2310 fe->tuner_priv = NULL;
2311 return 0;
2312}
2313
2314enum frontend_tune_state dib0090_get_tune_state(struct dvb_frontend *fe)
2315{
2316 struct dib0090_state *state = fe->tuner_priv;
2317
2318 return state->tune_state;
2319}
Olivier Grenie28fafca2011-01-04 04:27:11 -03002320
Olivier Grenie03245a52009-12-04 13:27:57 -03002321EXPORT_SYMBOL(dib0090_get_tune_state);
2322
2323int dib0090_set_tune_state(struct dvb_frontend *fe, enum frontend_tune_state tune_state)
2324{
2325 struct dib0090_state *state = fe->tuner_priv;
2326
2327 state->tune_state = tune_state;
2328 return 0;
2329}
Olivier Grenie28fafca2011-01-04 04:27:11 -03002330
Olivier Grenie03245a52009-12-04 13:27:57 -03002331EXPORT_SYMBOL(dib0090_set_tune_state);
2332
2333static int dib0090_get_frequency(struct dvb_frontend *fe, u32 * frequency)
2334{
2335 struct dib0090_state *state = fe->tuner_priv;
2336
2337 *frequency = 1000 * state->current_rf;
2338 return 0;
2339}
2340
2341static int dib0090_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *p)
2342{
2343 struct dib0090_state *state = fe->tuner_priv;
Olivier Grenie28fafca2011-01-04 04:27:11 -03002344 u32 ret;
Olivier Grenie03245a52009-12-04 13:27:57 -03002345
2346 state->tune_state = CT_TUNER_START;
2347
2348 do {
2349 ret = dib0090_tune(fe);
2350 if (ret != FE_CALLBACK_TIME_NEVER)
2351 msleep(ret / 10);
2352 else
2353 break;
2354 } while (state->tune_state != CT_TUNER_STOP);
2355
2356 return 0;
2357}
2358
2359static const struct dvb_tuner_ops dib0090_ops = {
2360 .info = {
2361 .name = "DiBcom DiB0090",
2362 .frequency_min = 45000000,
2363 .frequency_max = 860000000,
2364 .frequency_step = 1000,
2365 },
2366 .release = dib0090_release,
2367
2368 .init = dib0090_wakeup,
2369 .sleep = dib0090_sleep,
2370 .set_params = dib0090_set_params,
2371 .get_frequency = dib0090_get_frequency,
2372};
2373
Olivier Grenie28fafca2011-01-04 04:27:11 -03002374static const struct dvb_tuner_ops dib0090_fw_ops = {
2375 .info = {
2376 .name = "DiBcom DiB0090",
2377 .frequency_min = 45000000,
2378 .frequency_max = 860000000,
2379 .frequency_step = 1000,
2380 },
2381 .release = dib0090_release,
2382
2383 .init = NULL,
2384 .sleep = NULL,
2385 .set_params = NULL,
2386 .get_frequency = NULL,
2387};
2388
2389static const struct dib0090_wbd_slope dib0090_wbd_table_default[] = {
2390 {470, 0, 250, 0, 100, 4},
2391 {860, 51, 866, 21, 375, 4},
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002392 {1700, 0, 800, 0, 850, 4},
2393 {2900, 0, 250, 0, 100, 6},
Olivier Grenie28fafca2011-01-04 04:27:11 -03002394 {0xFFFF, 0, 0, 0, 0, 0},
2395};
2396
Olivier Grenie03245a52009-12-04 13:27:57 -03002397struct dvb_frontend *dib0090_register(struct dvb_frontend *fe, struct i2c_adapter *i2c, const struct dib0090_config *config)
2398{
2399 struct dib0090_state *st = kzalloc(sizeof(struct dib0090_state), GFP_KERNEL);
2400 if (st == NULL)
2401 return NULL;
2402
2403 st->config = config;
2404 st->i2c = i2c;
2405 st->fe = fe;
2406 fe->tuner_priv = st;
2407
Olivier Grenie28fafca2011-01-04 04:27:11 -03002408 if (config->wbd == NULL)
2409 st->current_wbd_table = dib0090_wbd_table_default;
2410 else
2411 st->current_wbd_table = config->wbd;
2412
Olivier Grenie03245a52009-12-04 13:27:57 -03002413 if (dib0090_reset(fe) != 0)
2414 goto free_mem;
2415
2416 printk(KERN_INFO "DiB0090: successfully identified\n");
2417 memcpy(&fe->ops.tuner_ops, &dib0090_ops, sizeof(struct dvb_tuner_ops));
2418
2419 return fe;
2420 free_mem:
2421 kfree(st);
2422 fe->tuner_priv = NULL;
2423 return NULL;
2424}
Olivier Grenie28fafca2011-01-04 04:27:11 -03002425
Olivier Grenie03245a52009-12-04 13:27:57 -03002426EXPORT_SYMBOL(dib0090_register);
2427
Olivier Grenie28fafca2011-01-04 04:27:11 -03002428struct dvb_frontend *dib0090_fw_register(struct dvb_frontend *fe, struct i2c_adapter *i2c, const struct dib0090_config *config)
2429{
2430 struct dib0090_fw_state *st = kzalloc(sizeof(struct dib0090_fw_state), GFP_KERNEL);
2431 if (st == NULL)
2432 return NULL;
2433
2434 st->config = config;
2435 st->i2c = i2c;
2436 st->fe = fe;
2437 fe->tuner_priv = st;
2438
2439 if (dib0090_fw_reset_digital(fe, st->config) != 0)
2440 goto free_mem;
2441
2442 dprintk("DiB0090 FW: successfully identified");
2443 memcpy(&fe->ops.tuner_ops, &dib0090_fw_ops, sizeof(struct dvb_tuner_ops));
2444
2445 return fe;
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002446free_mem:
Olivier Grenie28fafca2011-01-04 04:27:11 -03002447 kfree(st);
2448 fe->tuner_priv = NULL;
2449 return NULL;
2450}
Olivier Grenie28fafca2011-01-04 04:27:11 -03002451EXPORT_SYMBOL(dib0090_fw_register);
2452
Olivier Grenie03245a52009-12-04 13:27:57 -03002453MODULE_AUTHOR("Patrick Boettcher <pboettcher@dibcom.fr>");
2454MODULE_AUTHOR("Olivier Grenie <olivier.grenie@dibcom.fr>");
2455MODULE_DESCRIPTION("Driver for the DiBcom 0090 base-band RF Tuner");
2456MODULE_LICENSE("GPL");