blob: 9030f3dc95f9b914b08a22549b021e2607737d70 [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>
Patrick Boettcher79fcce32011-08-03 12:08:21 -030030#include <linux/mutex.h>
Olivier Grenie03245a52009-12-04 13:27:57 -030031
32#include "dvb_frontend.h"
33
34#include "dib0090.h"
35#include "dibx000_common.h"
36
37static int debug;
38module_param(debug, int, 0644);
39MODULE_PARM_DESC(debug, "turn on debugging (default: 0)");
40
41#define dprintk(args...) do { \
42 if (debug) { \
43 printk(KERN_DEBUG "DiB0090: "); \
44 printk(args); \
45 printk("\n"); \
46 } \
47} while (0)
48
Olivier Grenie28fafca2011-01-04 04:27:11 -030049#define CONFIG_SYS_DVBT
Olivier Grenie03245a52009-12-04 13:27:57 -030050#define CONFIG_SYS_ISDBT
51#define CONFIG_BAND_CBAND
52#define CONFIG_BAND_VHF
53#define CONFIG_BAND_UHF
54#define CONFIG_DIB0090_USE_PWM_AGC
55
56#define EN_LNA0 0x8000
57#define EN_LNA1 0x4000
58#define EN_LNA2 0x2000
59#define EN_LNA3 0x1000
60#define EN_MIX0 0x0800
61#define EN_MIX1 0x0400
62#define EN_MIX2 0x0200
63#define EN_MIX3 0x0100
64#define EN_IQADC 0x0040
65#define EN_PLL 0x0020
66#define EN_TX 0x0010
67#define EN_BB 0x0008
68#define EN_LO 0x0004
69#define EN_BIAS 0x0001
70
71#define EN_IQANA 0x0002
72#define EN_DIGCLK 0x0080 /* not in the 0x24 reg, only in 0x1b */
73#define EN_CRYSTAL 0x0002
74
75#define EN_UHF 0x22E9
76#define EN_VHF 0x44E9
77#define EN_LBD 0x11E9
78#define EN_SBD 0x44E9
79#define EN_CAB 0x88E9
80
Olivier Grenie28fafca2011-01-04 04:27:11 -030081/* Calibration defines */
82#define DC_CAL 0x1
83#define WBD_CAL 0x2
84#define TEMP_CAL 0x4
85#define CAPTRIM_CAL 0x8
86
87#define KROSUS_PLL_LOCKED 0x800
88#define KROSUS 0x2
89
90/* Use those defines to identify SOC version */
91#define SOC 0x02
92#define SOC_7090_P1G_11R1 0x82
93#define SOC_7090_P1G_21R1 0x8a
94#define SOC_8090_P1G_11R1 0x86
95#define SOC_8090_P1G_21R1 0x8e
96
97/* else use thos ones to check */
98#define P1A_B 0x0
99#define P1C 0x1
100#define P1D_E_F 0x3
101#define P1G 0x7
102#define P1G_21R2 0xf
103
104#define MP001 0x1 /* Single 9090/8096 */
105#define MP005 0x4 /* Single Sband */
106#define MP008 0x6 /* Dual diversity VHF-UHF-LBAND */
107#define MP009 0x7 /* Dual diversity 29098 CBAND-UHF-LBAND-SBAND */
108
Olivier Grenie03245a52009-12-04 13:27:57 -0300109#define pgm_read_word(w) (*w)
110
111struct dc_calibration;
112
113struct dib0090_tuning {
114 u32 max_freq; /* for every frequency less than or equal to that field: this information is correct */
115 u8 switch_trim;
116 u8 lna_tune;
Olivier Grenie28fafca2011-01-04 04:27:11 -0300117 u16 lna_bias;
Olivier Grenie03245a52009-12-04 13:27:57 -0300118 u16 v2i;
119 u16 mix;
120 u16 load;
121 u16 tuner_enable;
122};
123
124struct dib0090_pll {
125 u32 max_freq; /* for every frequency less than or equal to that field: this information is correct */
126 u8 vco_band;
127 u8 hfdiv_code;
128 u8 hfdiv;
129 u8 topresc;
130};
131
Olivier Grenie28fafca2011-01-04 04:27:11 -0300132struct dib0090_identity {
133 u8 version;
134 u8 product;
135 u8 p1g;
136 u8 in_soc;
137};
138
Olivier Grenie03245a52009-12-04 13:27:57 -0300139struct dib0090_state {
140 struct i2c_adapter *i2c;
141 struct dvb_frontend *fe;
142 const struct dib0090_config *config;
143
144 u8 current_band;
Olivier Grenie03245a52009-12-04 13:27:57 -0300145 enum frontend_tune_state tune_state;
146 u32 current_rf;
147
148 u16 wbd_offset;
149 s16 wbd_target; /* in dB */
150
151 s16 rf_gain_limit; /* take-over-point: where to split between bb and rf gain */
152 s16 current_gain; /* keeps the currently programmed gain */
153 u8 agc_step; /* new binary search */
154
155 u16 gain[2]; /* for channel monitoring */
156
157 const u16 *rf_ramp;
158 const u16 *bb_ramp;
159
160 /* for the software AGC ramps */
161 u16 bb_1_def;
162 u16 rf_lt_def;
163 u16 gain_reg[4];
164
165 /* for the captrim/dc-offset search */
166 s8 step;
167 s16 adc_diff;
168 s16 min_adc_diff;
169
170 s8 captrim;
171 s8 fcaptrim;
172
173 const struct dc_calibration *dc;
174 u16 bb6, bb7;
175
176 const struct dib0090_tuning *current_tune_table_index;
177 const struct dib0090_pll *current_pll_table_index;
178
179 u8 tuner_is_tuned;
180 u8 agc_freeze;
181
Olivier Grenie28fafca2011-01-04 04:27:11 -0300182 struct dib0090_identity identity;
183
184 u32 rf_request;
185 u8 current_standard;
186
187 u8 calibrate;
188 u32 rest;
189 u16 bias;
190 s16 temperature;
191
192 u8 wbd_calibration_gain;
193 const struct dib0090_wbd_slope *current_wbd_table;
194 u16 wbdmux;
Olivier Grenie5a0deee2011-05-03 12:27:33 -0300195
196 /* for the I2C transfer */
197 struct i2c_msg msg[2];
198 u8 i2c_write_buffer[3];
199 u8 i2c_read_buffer[2];
Patrick Boettcher79fcce32011-08-03 12:08:21 -0300200 struct mutex i2c_buffer_lock;
Olivier Grenie28fafca2011-01-04 04:27:11 -0300201};
202
203struct dib0090_fw_state {
204 struct i2c_adapter *i2c;
205 struct dvb_frontend *fe;
206 struct dib0090_identity identity;
207 const struct dib0090_config *config;
Olivier Grenie5a0deee2011-05-03 12:27:33 -0300208
209 /* for the I2C transfer */
210 struct i2c_msg msg;
211 u8 i2c_write_buffer[2];
212 u8 i2c_read_buffer[2];
Patrick Boettcher79fcce32011-08-03 12:08:21 -0300213 struct mutex i2c_buffer_lock;
Olivier Grenie03245a52009-12-04 13:27:57 -0300214};
215
216static u16 dib0090_read_reg(struct dib0090_state *state, u8 reg)
217{
Patrick Boettcher79fcce32011-08-03 12:08:21 -0300218 u16 ret;
219
220 if (mutex_lock_interruptible(&state->i2c_buffer_lock) < 0) {
221 dprintk("could not acquire lock");
222 return 0;
223 }
224
Olivier Grenie5a0deee2011-05-03 12:27:33 -0300225 state->i2c_write_buffer[0] = reg;
226
227 memset(state->msg, 0, 2 * sizeof(struct i2c_msg));
228 state->msg[0].addr = state->config->i2c_address;
229 state->msg[0].flags = 0;
230 state->msg[0].buf = state->i2c_write_buffer;
231 state->msg[0].len = 1;
232 state->msg[1].addr = state->config->i2c_address;
233 state->msg[1].flags = I2C_M_RD;
234 state->msg[1].buf = state->i2c_read_buffer;
235 state->msg[1].len = 2;
236
237 if (i2c_transfer(state->i2c, state->msg, 2) != 2) {
Olivier Grenie03245a52009-12-04 13:27:57 -0300238 printk(KERN_WARNING "DiB0090 I2C read failed\n");
Patrick Boettcher79fcce32011-08-03 12:08:21 -0300239 ret = 0;
240 } else
241 ret = (state->i2c_read_buffer[0] << 8)
242 | state->i2c_read_buffer[1];
Olivier Grenie5a0deee2011-05-03 12:27:33 -0300243
Patrick Boettcher79fcce32011-08-03 12:08:21 -0300244 mutex_unlock(&state->i2c_buffer_lock);
245 return ret;
Olivier Grenie03245a52009-12-04 13:27:57 -0300246}
247
248static int dib0090_write_reg(struct dib0090_state *state, u32 reg, u16 val)
249{
Patrick Boettcher79fcce32011-08-03 12:08:21 -0300250 int ret;
251
252 if (mutex_lock_interruptible(&state->i2c_buffer_lock) < 0) {
253 dprintk("could not acquire lock");
254 return -EINVAL;
255 }
256
Olivier Grenie5a0deee2011-05-03 12:27:33 -0300257 state->i2c_write_buffer[0] = reg & 0xff;
258 state->i2c_write_buffer[1] = val >> 8;
259 state->i2c_write_buffer[2] = val & 0xff;
260
261 memset(state->msg, 0, sizeof(struct i2c_msg));
262 state->msg[0].addr = state->config->i2c_address;
263 state->msg[0].flags = 0;
264 state->msg[0].buf = state->i2c_write_buffer;
265 state->msg[0].len = 3;
266
267 if (i2c_transfer(state->i2c, state->msg, 1) != 1) {
Olivier Grenie28fafca2011-01-04 04:27:11 -0300268 printk(KERN_WARNING "DiB0090 I2C write failed\n");
Patrick Boettcher79fcce32011-08-03 12:08:21 -0300269 ret = -EREMOTEIO;
270 } else
271 ret = 0;
272
273 mutex_unlock(&state->i2c_buffer_lock);
274 return ret;
Olivier Grenie28fafca2011-01-04 04:27:11 -0300275}
276
277static u16 dib0090_fw_read_reg(struct dib0090_fw_state *state, u8 reg)
278{
Patrick Boettcher79fcce32011-08-03 12:08:21 -0300279 u16 ret;
280
281 if (mutex_lock_interruptible(&state->i2c_buffer_lock) < 0) {
282 dprintk("could not acquire lock");
283 return 0;
284 }
285
Olivier Grenie5a0deee2011-05-03 12:27:33 -0300286 state->i2c_write_buffer[0] = reg;
287
288 memset(&state->msg, 0, sizeof(struct i2c_msg));
289 state->msg.addr = reg;
290 state->msg.flags = I2C_M_RD;
291 state->msg.buf = state->i2c_read_buffer;
292 state->msg.len = 2;
293 if (i2c_transfer(state->i2c, &state->msg, 1) != 1) {
Olivier Grenie28fafca2011-01-04 04:27:11 -0300294 printk(KERN_WARNING "DiB0090 I2C read failed\n");
Patrick Boettcher79fcce32011-08-03 12:08:21 -0300295 ret = 0;
296 } else
297 ret = (state->i2c_read_buffer[0] << 8)
298 | state->i2c_read_buffer[1];
299
300 mutex_unlock(&state->i2c_buffer_lock);
301 return ret;
Olivier Grenie28fafca2011-01-04 04:27:11 -0300302}
303
304static int dib0090_fw_write_reg(struct dib0090_fw_state *state, u8 reg, u16 val)
305{
Patrick Boettcher79fcce32011-08-03 12:08:21 -0300306 int ret;
307
308 if (mutex_lock_interruptible(&state->i2c_buffer_lock) < 0) {
309 dprintk("could not acquire lock");
310 return -EINVAL;
311 }
312
Olivier Grenie5a0deee2011-05-03 12:27:33 -0300313 state->i2c_write_buffer[0] = val >> 8;
314 state->i2c_write_buffer[1] = val & 0xff;
315
316 memset(&state->msg, 0, sizeof(struct i2c_msg));
317 state->msg.addr = reg;
318 state->msg.flags = 0;
319 state->msg.buf = state->i2c_write_buffer;
320 state->msg.len = 2;
321 if (i2c_transfer(state->i2c, &state->msg, 1) != 1) {
Olivier Grenie03245a52009-12-04 13:27:57 -0300322 printk(KERN_WARNING "DiB0090 I2C write failed\n");
Patrick Boettcher79fcce32011-08-03 12:08:21 -0300323 ret = -EREMOTEIO;
324 } else
325 ret = 0;
326
327 mutex_unlock(&state->i2c_buffer_lock);
328 return ret;
Olivier Grenie03245a52009-12-04 13:27:57 -0300329}
330
331#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)
332#define ADC_TARGET -220
333#define GAIN_ALPHA 5
334#define WBD_ALPHA 6
335#define LPF 100
336static void dib0090_write_regs(struct dib0090_state *state, u8 r, const u16 * b, u8 c)
337{
338 do {
339 dib0090_write_reg(state, r++, *b++);
340 } while (--c);
341}
342
Olivier Grenie28fafca2011-01-04 04:27:11 -0300343static int dib0090_identify(struct dvb_frontend *fe)
Olivier Grenie03245a52009-12-04 13:27:57 -0300344{
345 struct dib0090_state *state = fe->tuner_priv;
346 u16 v;
Olivier Grenie28fafca2011-01-04 04:27:11 -0300347 struct dib0090_identity *identity = &state->identity;
Olivier Grenie03245a52009-12-04 13:27:57 -0300348
349 v = dib0090_read_reg(state, 0x1a);
350
Olivier Grenie28fafca2011-01-04 04:27:11 -0300351 identity->p1g = 0;
352 identity->in_soc = 0;
353
354 dprintk("Tuner identification (Version = 0x%04x)", v);
Olivier Grenie03245a52009-12-04 13:27:57 -0300355
356 /* without PLL lock info */
Olivier Grenie28fafca2011-01-04 04:27:11 -0300357 v &= ~KROSUS_PLL_LOCKED;
Olivier Grenie03245a52009-12-04 13:27:57 -0300358
Olivier Grenie28fafca2011-01-04 04:27:11 -0300359 identity->version = v & 0xff;
360 identity->product = (v >> 8) & 0xf;
Olivier Grenie03245a52009-12-04 13:27:57 -0300361
Olivier Grenie28fafca2011-01-04 04:27:11 -0300362 if (identity->product != KROSUS)
363 goto identification_error;
Olivier Grenie03245a52009-12-04 13:27:57 -0300364
Olivier Grenie28fafca2011-01-04 04:27:11 -0300365 if ((identity->version & 0x3) == SOC) {
366 identity->in_soc = 1;
367 switch (identity->version) {
368 case SOC_8090_P1G_11R1:
369 dprintk("SOC 8090 P1-G11R1 Has been detected");
370 identity->p1g = 1;
371 break;
372 case SOC_8090_P1G_21R1:
373 dprintk("SOC 8090 P1-G21R1 Has been detected");
374 identity->p1g = 1;
375 break;
376 case SOC_7090_P1G_11R1:
377 dprintk("SOC 7090 P1-G11R1 Has been detected");
378 identity->p1g = 1;
379 break;
380 case SOC_7090_P1G_21R1:
381 dprintk("SOC 7090 P1-G21R1 Has been detected");
382 identity->p1g = 1;
383 break;
384 default:
385 goto identification_error;
386 }
387 } else {
388 switch ((identity->version >> 5) & 0x7) {
389 case MP001:
390 dprintk("MP001 : 9090/8096");
391 break;
392 case MP005:
393 dprintk("MP005 : Single Sband");
394 break;
395 case MP008:
396 dprintk("MP008 : diversity VHF-UHF-LBAND");
397 break;
398 case MP009:
399 dprintk("MP009 : diversity 29098 CBAND-UHF-LBAND-SBAND");
400 break;
401 default:
402 goto identification_error;
403 }
404
405 switch (identity->version & 0x1f) {
406 case P1G_21R2:
407 dprintk("P1G_21R2 detected");
408 identity->p1g = 1;
409 break;
410 case P1G:
411 dprintk("P1G detected");
412 identity->p1g = 1;
413 break;
414 case P1D_E_F:
415 dprintk("P1D/E/F detected");
416 break;
417 case P1C:
418 dprintk("P1C detected");
419 break;
420 case P1A_B:
421 dprintk("P1-A/B detected: driver is deactivated - not available");
422 goto identification_error;
423 break;
424 default:
425 goto identification_error;
426 }
Olivier Grenie03245a52009-12-04 13:27:57 -0300427 }
428
Olivier Grenie28fafca2011-01-04 04:27:11 -0300429 return 0;
430
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300431identification_error:
Olivier Grenie28fafca2011-01-04 04:27:11 -0300432 return -EIO;
433}
434
435static int dib0090_fw_identify(struct dvb_frontend *fe)
436{
437 struct dib0090_fw_state *state = fe->tuner_priv;
438 struct dib0090_identity *identity = &state->identity;
439
440 u16 v = dib0090_fw_read_reg(state, 0x1a);
441 identity->p1g = 0;
442 identity->in_soc = 0;
443
444 dprintk("FE: Tuner identification (Version = 0x%04x)", v);
445
446 /* without PLL lock info */
447 v &= ~KROSUS_PLL_LOCKED;
448
449 identity->version = v & 0xff;
450 identity->product = (v >> 8) & 0xf;
451
452 if (identity->product != KROSUS)
453 goto identification_error;
454
Olivier Grenie28fafca2011-01-04 04:27:11 -0300455 if ((identity->version & 0x3) == SOC) {
456 identity->in_soc = 1;
457 switch (identity->version) {
458 case SOC_8090_P1G_11R1:
459 dprintk("SOC 8090 P1-G11R1 Has been detected");
460 identity->p1g = 1;
461 break;
462 case SOC_8090_P1G_21R1:
463 dprintk("SOC 8090 P1-G21R1 Has been detected");
464 identity->p1g = 1;
465 break;
466 case SOC_7090_P1G_11R1:
467 dprintk("SOC 7090 P1-G11R1 Has been detected");
468 identity->p1g = 1;
469 break;
470 case SOC_7090_P1G_21R1:
471 dprintk("SOC 7090 P1-G21R1 Has been detected");
472 identity->p1g = 1;
473 break;
474 default:
475 goto identification_error;
476 }
477 } else {
478 switch ((identity->version >> 5) & 0x7) {
479 case MP001:
480 dprintk("MP001 : 9090/8096");
481 break;
482 case MP005:
483 dprintk("MP005 : Single Sband");
484 break;
485 case MP008:
486 dprintk("MP008 : diversity VHF-UHF-LBAND");
487 break;
488 case MP009:
489 dprintk("MP009 : diversity 29098 CBAND-UHF-LBAND-SBAND");
490 break;
491 default:
492 goto identification_error;
493 }
494
495 switch (identity->version & 0x1f) {
496 case P1G_21R2:
497 dprintk("P1G_21R2 detected");
498 identity->p1g = 1;
499 break;
500 case P1G:
501 dprintk("P1G detected");
502 identity->p1g = 1;
503 break;
504 case P1D_E_F:
505 dprintk("P1D/E/F detected");
506 break;
507 case P1C:
508 dprintk("P1C detected");
509 break;
510 case P1A_B:
511 dprintk("P1-A/B detected: driver is deactivated - not available");
512 goto identification_error;
513 break;
514 default:
515 goto identification_error;
516 }
517 }
518
519 return 0;
520
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300521identification_error:
Olivier Grenie28fafca2011-01-04 04:27:11 -0300522 return -EIO;;
Olivier Grenie03245a52009-12-04 13:27:57 -0300523}
524
525static void dib0090_reset_digital(struct dvb_frontend *fe, const struct dib0090_config *cfg)
526{
527 struct dib0090_state *state = fe->tuner_priv;
Olivier Grenie28fafca2011-01-04 04:27:11 -0300528 u16 PllCfg, i, v;
Olivier Grenie03245a52009-12-04 13:27:57 -0300529
530 HARD_RESET(state);
531
Olivier Grenie28fafca2011-01-04 04:27:11 -0300532 dib0090_write_reg(state, 0x24, EN_PLL | EN_CRYSTAL);
Olivier Grenie03245a52009-12-04 13:27:57 -0300533 dib0090_write_reg(state, 0x1b, EN_DIGCLK | EN_PLL | EN_CRYSTAL); /* PLL, DIG_CLK and CRYSTAL remain */
534
Olivier Grenie28fafca2011-01-04 04:27:11 -0300535 if (!cfg->in_soc) {
536 /* adcClkOutRatio=8->7, release reset */
537 dib0090_write_reg(state, 0x20, ((cfg->io.adc_clock_ratio - 1) << 11) | (0 << 10) | (1 << 9) | (1 << 8) | (0 << 4) | 0);
538 if (cfg->clkoutdrive != 0)
539 dib0090_write_reg(state, 0x23, (0 << 15) | ((!cfg->analog_output) << 14) | (2 << 10) | (1 << 9) | (0 << 8)
540 | (cfg->clkoutdrive << 5) | (cfg->clkouttobamse << 4) | (0 << 2) | (0));
541 else
542 dib0090_write_reg(state, 0x23, (0 << 15) | ((!cfg->analog_output) << 14) | (2 << 10) | (1 << 9) | (0 << 8)
543 | (7 << 5) | (cfg->clkouttobamse << 4) | (0 << 2) | (0));
544 }
545
546 /* Read Pll current config * */
547 PllCfg = dib0090_read_reg(state, 0x21);
548
549 /** Reconfigure PLL if current setting is different from default setting **/
550 if ((PllCfg & 0x1FFF) != ((cfg->io.pll_range << 12) | (cfg->io.pll_loopdiv << 6) | (cfg->io.pll_prediv)) && (!cfg->in_soc)
551 && !cfg->io.pll_bypass) {
552
553 /* Set Bypass mode */
554 PllCfg |= (1 << 15);
555 dib0090_write_reg(state, 0x21, PllCfg);
556
557 /* Set Reset Pll */
558 PllCfg &= ~(1 << 13);
559 dib0090_write_reg(state, 0x21, PllCfg);
560
561 /*** Set new Pll configuration in bypass and reset state ***/
562 PllCfg = (1 << 15) | (0 << 13) | (cfg->io.pll_range << 12) | (cfg->io.pll_loopdiv << 6) | (cfg->io.pll_prediv);
563 dib0090_write_reg(state, 0x21, PllCfg);
564
565 /* Remove Reset Pll */
566 PllCfg |= (1 << 13);
567 dib0090_write_reg(state, 0x21, PllCfg);
568
569 /*** Wait for PLL lock ***/
570 i = 100;
571 do {
572 v = !!(dib0090_read_reg(state, 0x1a) & 0x800);
573 if (v)
574 break;
575 } while (--i);
576
577 if (i == 0) {
578 dprintk("Pll: Unable to lock Pll");
579 return;
580 }
581
582 /* Finally Remove Bypass mode */
583 PllCfg &= ~(1 << 15);
584 dib0090_write_reg(state, 0x21, PllCfg);
585 }
586
587 if (cfg->io.pll_bypass) {
588 PllCfg |= (cfg->io.pll_bypass << 15);
589 dib0090_write_reg(state, 0x21, PllCfg);
590 }
591}
592
593static int dib0090_fw_reset_digital(struct dvb_frontend *fe, const struct dib0090_config *cfg)
594{
595 struct dib0090_fw_state *state = fe->tuner_priv;
596 u16 PllCfg;
597 u16 v;
598 int i;
599
600 dprintk("fw reset digital");
601 HARD_RESET(state);
602
603 dib0090_fw_write_reg(state, 0x24, EN_PLL | EN_CRYSTAL);
604 dib0090_fw_write_reg(state, 0x1b, EN_DIGCLK | EN_PLL | EN_CRYSTAL); /* PLL, DIG_CLK and CRYSTAL remain */
605
606 dib0090_fw_write_reg(state, 0x20,
607 ((cfg->io.adc_clock_ratio - 1) << 11) | (0 << 10) | (1 << 9) | (1 << 8) | (cfg->data_tx_drv << 4) | cfg->ls_cfg_pad_drv);
608
609 v = (0 << 15) | ((!cfg->analog_output) << 14) | (1 << 9) | (0 << 8) | (cfg->clkouttobamse << 4) | (0 << 2) | (0);
Olivier Grenie03245a52009-12-04 13:27:57 -0300610 if (cfg->clkoutdrive != 0)
Olivier Grenie28fafca2011-01-04 04:27:11 -0300611 v |= cfg->clkoutdrive << 5;
Olivier Grenie03245a52009-12-04 13:27:57 -0300612 else
Olivier Grenie28fafca2011-01-04 04:27:11 -0300613 v |= 7 << 5;
Olivier Grenie03245a52009-12-04 13:27:57 -0300614
Olivier Grenie28fafca2011-01-04 04:27:11 -0300615 v |= 2 << 10;
616 dib0090_fw_write_reg(state, 0x23, v);
Olivier Grenie03245a52009-12-04 13:27:57 -0300617
Olivier Grenie28fafca2011-01-04 04:27:11 -0300618 /* Read Pll current config * */
619 PllCfg = dib0090_fw_read_reg(state, 0x21);
620
621 /** Reconfigure PLL if current setting is different from default setting **/
622 if ((PllCfg & 0x1FFF) != ((cfg->io.pll_range << 12) | (cfg->io.pll_loopdiv << 6) | (cfg->io.pll_prediv)) && !cfg->io.pll_bypass) {
623
624 /* Set Bypass mode */
625 PllCfg |= (1 << 15);
626 dib0090_fw_write_reg(state, 0x21, PllCfg);
627
628 /* Set Reset Pll */
629 PllCfg &= ~(1 << 13);
630 dib0090_fw_write_reg(state, 0x21, PllCfg);
631
632 /*** Set new Pll configuration in bypass and reset state ***/
633 PllCfg = (1 << 15) | (0 << 13) | (cfg->io.pll_range << 12) | (cfg->io.pll_loopdiv << 6) | (cfg->io.pll_prediv);
634 dib0090_fw_write_reg(state, 0x21, PllCfg);
635
636 /* Remove Reset Pll */
637 PllCfg |= (1 << 13);
638 dib0090_fw_write_reg(state, 0x21, PllCfg);
639
640 /*** Wait for PLL lock ***/
641 i = 100;
642 do {
643 v = !!(dib0090_fw_read_reg(state, 0x1a) & 0x800);
644 if (v)
645 break;
646 } while (--i);
647
648 if (i == 0) {
649 dprintk("Pll: Unable to lock Pll");
650 return -EIO;
651 }
652
653 /* Finally Remove Bypass mode */
654 PllCfg &= ~(1 << 15);
655 dib0090_fw_write_reg(state, 0x21, PllCfg);
656 }
657
658 if (cfg->io.pll_bypass) {
659 PllCfg |= (cfg->io.pll_bypass << 15);
660 dib0090_fw_write_reg(state, 0x21, PllCfg);
661 }
662
663 return dib0090_fw_identify(fe);
Olivier Grenie03245a52009-12-04 13:27:57 -0300664}
665
666static int dib0090_wakeup(struct dvb_frontend *fe)
667{
668 struct dib0090_state *state = fe->tuner_priv;
669 if (state->config->sleep)
670 state->config->sleep(fe, 0);
Olivier Grenie28fafca2011-01-04 04:27:11 -0300671
672 /* enable dataTX in case we have been restarted in the wrong moment */
673 dib0090_write_reg(state, 0x23, dib0090_read_reg(state, 0x23) | (1 << 14));
Olivier Grenie03245a52009-12-04 13:27:57 -0300674 return 0;
675}
676
677static int dib0090_sleep(struct dvb_frontend *fe)
678{
679 struct dib0090_state *state = fe->tuner_priv;
680 if (state->config->sleep)
681 state->config->sleep(fe, 1);
682 return 0;
683}
684
Márton Németh43e3e6d2010-01-16 14:35:03 -0300685void dib0090_dcc_freq(struct dvb_frontend *fe, u8 fast)
Olivier Grenie03245a52009-12-04 13:27:57 -0300686{
687 struct dib0090_state *state = fe->tuner_priv;
688 if (fast)
Olivier Grenie9c783032009-12-07 07:49:40 -0300689 dib0090_write_reg(state, 0x04, 0);
Olivier Grenie03245a52009-12-04 13:27:57 -0300690 else
Olivier Grenie9c783032009-12-07 07:49:40 -0300691 dib0090_write_reg(state, 0x04, 1);
Olivier Grenie03245a52009-12-04 13:27:57 -0300692}
Olivier Grenie28fafca2011-01-04 04:27:11 -0300693
Olivier Grenie03245a52009-12-04 13:27:57 -0300694EXPORT_SYMBOL(dib0090_dcc_freq);
Olivier Grenie9c783032009-12-07 07:49:40 -0300695
Olivier Grenie28fafca2011-01-04 04:27:11 -0300696static const u16 bb_ramp_pwm_normal_socs[] = {
697 550, /* max BB gain in 10th of dB */
698 (1 << 9) | 8, /* ramp_slope = 1dB of gain -> clock_ticks_per_db = clk_khz / ramp_slope -> BB_RAMP2 */
699 440,
700 (4 << 9) | 0, /* BB_RAMP3 = 26dB */
701 (0 << 9) | 208, /* BB_RAMP4 */
702 (4 << 9) | 208, /* BB_RAMP5 = 29dB */
703 (0 << 9) | 440, /* BB_RAMP6 */
704};
705
706static const u16 rf_ramp_pwm_cband_7090[] = {
707 280, /* max RF gain in 10th of dB */
708 18, /* ramp_slope = 1dB of gain -> clock_ticks_per_db = clk_khz / ramp_slope -> RF_RAMP2 */
709 504, /* ramp_max = maximum X used on the ramp */
710 (29 << 10) | 364, /* RF_RAMP5, LNA 1 = 8dB */
711 (0 << 10) | 504, /* RF_RAMP6, LNA 1 */
712 (60 << 10) | 228, /* RF_RAMP7, LNA 2 = 7.7dB */
713 (0 << 10) | 364, /* RF_RAMP8, LNA 2 */
714 (34 << 10) | 109, /* GAIN_4_1, LNA 3 = 6.8dB */
715 (0 << 10) | 228, /* GAIN_4_2, LNA 3 */
716 (37 << 10) | 0, /* RF_RAMP3, LNA 4 = 6.2dB */
717 (0 << 10) | 109, /* RF_RAMP4, LNA 4 */
718};
719
720static const u16 rf_ramp_pwm_cband_8090[] = {
721 345, /* max RF gain in 10th of dB */
722 29, /* ramp_slope = 1dB of gain -> clock_ticks_per_db = clk_khz / ramp_slope -> RF_RAMP2 */
723 1000, /* ramp_max = maximum X used on the ramp */
724 (35 << 10) | 772, /* RF_RAMP3, LNA 1 = 8dB */
725 (0 << 10) | 1000, /* RF_RAMP4, LNA 1 */
726 (58 << 10) | 496, /* RF_RAMP5, LNA 2 = 9.5dB */
727 (0 << 10) | 772, /* RF_RAMP6, LNA 2 */
728 (27 << 10) | 200, /* RF_RAMP7, LNA 3 = 10.5dB */
729 (0 << 10) | 496, /* RF_RAMP8, LNA 3 */
730 (40 << 10) | 0, /* GAIN_4_1, LNA 4 = 7dB */
731 (0 << 10) | 200, /* GAIN_4_2, LNA 4 */
732};
733
734static const u16 rf_ramp_pwm_uhf_7090[] = {
735 407, /* max RF gain in 10th of dB */
736 13, /* ramp_slope = 1dB of gain -> clock_ticks_per_db = clk_khz / ramp_slope -> RF_RAMP2 */
737 529, /* ramp_max = maximum X used on the ramp */
738 (23 << 10) | 0, /* RF_RAMP3, LNA 1 = 14.7dB */
739 (0 << 10) | 176, /* RF_RAMP4, LNA 1 */
740 (63 << 10) | 400, /* RF_RAMP5, LNA 2 = 8dB */
741 (0 << 10) | 529, /* RF_RAMP6, LNA 2 */
742 (48 << 10) | 316, /* RF_RAMP7, LNA 3 = 6.8dB */
743 (0 << 10) | 400, /* RF_RAMP8, LNA 3 */
744 (29 << 10) | 176, /* GAIN_4_1, LNA 4 = 11.5dB */
745 (0 << 10) | 316, /* GAIN_4_2, LNA 4 */
746};
747
748static const u16 rf_ramp_pwm_uhf_8090[] = {
749 388, /* max RF gain in 10th of dB */
750 26, /* ramp_slope = 1dB of gain -> clock_ticks_per_db = clk_khz / ramp_slope -> RF_RAMP2 */
751 1008, /* ramp_max = maximum X used on the ramp */
752 (11 << 10) | 0, /* RF_RAMP3, LNA 1 = 14.7dB */
753 (0 << 10) | 369, /* RF_RAMP4, LNA 1 */
754 (41 << 10) | 809, /* RF_RAMP5, LNA 2 = 8dB */
755 (0 << 10) | 1008, /* RF_RAMP6, LNA 2 */
756 (27 << 10) | 659, /* RF_RAMP7, LNA 3 = 6dB */
757 (0 << 10) | 809, /* RF_RAMP8, LNA 3 */
758 (14 << 10) | 369, /* GAIN_4_1, LNA 4 = 11.5dB */
759 (0 << 10) | 659, /* GAIN_4_2, LNA 4 */
760};
761
Olivier Grenie03245a52009-12-04 13:27:57 -0300762static const u16 rf_ramp_pwm_cband[] = {
763 0, /* max RF gain in 10th of dB */
764 0, /* ramp_slope = 1dB of gain -> clock_ticks_per_db = clk_khz / ramp_slope -> 0x2b */
765 0, /* ramp_max = maximum X used on the ramp */
766 (0 << 10) | 0, /* 0x2c, LNA 1 = 0dB */
767 (0 << 10) | 0, /* 0x2d, LNA 1 */
768 (0 << 10) | 0, /* 0x2e, LNA 2 = 0dB */
769 (0 << 10) | 0, /* 0x2f, LNA 2 */
770 (0 << 10) | 0, /* 0x30, LNA 3 = 0dB */
771 (0 << 10) | 0, /* 0x31, LNA 3 */
772 (0 << 10) | 0, /* GAIN_4_1, LNA 4 = 0dB */
773 (0 << 10) | 0, /* GAIN_4_2, LNA 4 */
774};
775
776static const u16 rf_ramp_vhf[] = {
777 412, /* max RF gain in 10th of dB */
778 132, 307, 127, /* LNA1, 13.2dB */
779 105, 412, 255, /* LNA2, 10.5dB */
780 50, 50, 127, /* LNA3, 5dB */
781 125, 175, 127, /* LNA4, 12.5dB */
782 0, 0, 127, /* CBAND, 0dB */
783};
784
785static const u16 rf_ramp_uhf[] = {
786 412, /* max RF gain in 10th of dB */
787 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 */
788 105, 412, 255, /* LNA2 : 10.5 dB */
789 50, 50, 127, /* LNA3 : 5.0 dB */
790 125, 175, 127, /* LNA4 : 12.5 dB */
791 0, 0, 127, /* CBAND : 0.0 dB */
792};
793
Olivier Grenie28fafca2011-01-04 04:27:11 -0300794static const u16 rf_ramp_cband_broadmatching[] = /* for p1G only */
795{
796 314, /* Calibrated at 200MHz order has been changed g4-g3-g2-g1 */
797 84, 314, 127, /* LNA1 */
798 80, 230, 255, /* LNA2 */
799 80, 150, 127, /* LNA3 It was measured 12dB, do not lock if 120 */
800 70, 70, 127, /* LNA4 */
801 0, 0, 127, /* CBAND */
802};
803
Olivier Grenie03245a52009-12-04 13:27:57 -0300804static const u16 rf_ramp_cband[] = {
805 332, /* max RF gain in 10th of dB */
806 132, 252, 127, /* LNA1, dB */
807 80, 332, 255, /* LNA2, dB */
808 0, 0, 127, /* LNA3, dB */
809 0, 0, 127, /* LNA4, dB */
810 120, 120, 127, /* LT1 CBAND */
811};
812
813static const u16 rf_ramp_pwm_vhf[] = {
814 404, /* max RF gain in 10th of dB */
815 25, /* ramp_slope = 1dB of gain -> clock_ticks_per_db = clk_khz / ramp_slope -> 0x2b */
816 1011, /* ramp_max = maximum X used on the ramp */
817 (6 << 10) | 417, /* 0x2c, LNA 1 = 13.2dB */
818 (0 << 10) | 756, /* 0x2d, LNA 1 */
819 (16 << 10) | 756, /* 0x2e, LNA 2 = 10.5dB */
820 (0 << 10) | 1011, /* 0x2f, LNA 2 */
821 (16 << 10) | 290, /* 0x30, LNA 3 = 5dB */
822 (0 << 10) | 417, /* 0x31, LNA 3 */
823 (7 << 10) | 0, /* GAIN_4_1, LNA 4 = 12.5dB */
824 (0 << 10) | 290, /* GAIN_4_2, LNA 4 */
825};
826
827static const u16 rf_ramp_pwm_uhf[] = {
828 404, /* max RF gain in 10th of dB */
829 25, /* ramp_slope = 1dB of gain -> clock_ticks_per_db = clk_khz / ramp_slope -> 0x2b */
830 1011, /* ramp_max = maximum X used on the ramp */
831 (6 << 10) | 417, /* 0x2c, LNA 1 = 13.2dB */
832 (0 << 10) | 756, /* 0x2d, LNA 1 */
833 (16 << 10) | 756, /* 0x2e, LNA 2 = 10.5dB */
834 (0 << 10) | 1011, /* 0x2f, LNA 2 */
835 (16 << 10) | 0, /* 0x30, LNA 3 = 5dB */
836 (0 << 10) | 127, /* 0x31, LNA 3 */
837 (7 << 10) | 127, /* GAIN_4_1, LNA 4 = 12.5dB */
838 (0 << 10) | 417, /* GAIN_4_2, LNA 4 */
839};
840
841static const u16 bb_ramp_boost[] = {
842 550, /* max BB gain in 10th of dB */
843 260, 260, 26, /* BB1, 26dB */
844 290, 550, 29, /* BB2, 29dB */
845};
846
847static const u16 bb_ramp_pwm_normal[] = {
848 500, /* max RF gain in 10th of dB */
849 8, /* ramp_slope = 1dB of gain -> clock_ticks_per_db = clk_khz / ramp_slope -> 0x34 */
850 400,
851 (2 << 9) | 0, /* 0x35 = 21dB */
852 (0 << 9) | 168, /* 0x36 */
853 (2 << 9) | 168, /* 0x37 = 29dB */
854 (0 << 9) | 400, /* 0x38 */
855};
856
857struct slope {
Olivier Grenie28fafca2011-01-04 04:27:11 -0300858 s16 range;
859 s16 slope;
Olivier Grenie03245a52009-12-04 13:27:57 -0300860};
861static u16 slopes_to_scale(const struct slope *slopes, u8 num, s16 val)
862{
863 u8 i;
864 u16 rest;
865 u16 ret = 0;
866 for (i = 0; i < num; i++) {
867 if (val > slopes[i].range)
868 rest = slopes[i].range;
869 else
870 rest = val;
871 ret += (rest * slopes[i].slope) / slopes[i].range;
872 val -= rest;
873 }
874 return ret;
875}
876
877static const struct slope dib0090_wbd_slopes[3] = {
878 {66, 120}, /* -64,-52: offset - 65 */
879 {600, 170}, /* -52,-35: 65 - 665 */
880 {170, 250}, /* -45,-10: 665 - 835 */
881};
882
883static s16 dib0090_wbd_to_db(struct dib0090_state *state, u16 wbd)
884{
885 wbd &= 0x3ff;
886 if (wbd < state->wbd_offset)
887 wbd = 0;
888 else
889 wbd -= state->wbd_offset;
890 /* -64dB is the floor */
891 return -640 + (s16) slopes_to_scale(dib0090_wbd_slopes, ARRAY_SIZE(dib0090_wbd_slopes), wbd);
892}
893
894static void dib0090_wbd_target(struct dib0090_state *state, u32 rf)
895{
896 u16 offset = 250;
897
898 /* TODO : DAB digital N+/-1 interferer perfs : offset = 10 */
899
900 if (state->current_band == BAND_VHF)
901 offset = 650;
902#ifndef FIRMWARE_FIREFLY
903 if (state->current_band == BAND_VHF)
904 offset = state->config->wbd_vhf_offset;
905 if (state->current_band == BAND_CBAND)
906 offset = state->config->wbd_cband_offset;
907#endif
908
909 state->wbd_target = dib0090_wbd_to_db(state, state->wbd_offset + offset);
910 dprintk("wbd-target: %d dB", (u32) state->wbd_target);
911}
912
913static const int gain_reg_addr[4] = {
914 0x08, 0x0a, 0x0f, 0x01
915};
916
917static void dib0090_gain_apply(struct dib0090_state *state, s16 gain_delta, s16 top_delta, u8 force)
918{
919 u16 rf, bb, ref;
920 u16 i, v, gain_reg[4] = { 0 }, gain;
921 const u16 *g;
922
923 if (top_delta < -511)
924 top_delta = -511;
925 if (top_delta > 511)
926 top_delta = 511;
927
928 if (force) {
929 top_delta *= (1 << WBD_ALPHA);
930 gain_delta *= (1 << GAIN_ALPHA);
931 }
932
933 if (top_delta >= ((s16) (state->rf_ramp[0] << WBD_ALPHA) - state->rf_gain_limit)) /* overflow */
934 state->rf_gain_limit = state->rf_ramp[0] << WBD_ALPHA;
935 else
936 state->rf_gain_limit += top_delta;
937
938 if (state->rf_gain_limit < 0) /*underflow */
939 state->rf_gain_limit = 0;
940
941 /* use gain as a temporary variable and correct current_gain */
942 gain = ((state->rf_gain_limit >> WBD_ALPHA) + state->bb_ramp[0]) << GAIN_ALPHA;
943 if (gain_delta >= ((s16) gain - state->current_gain)) /* overflow */
944 state->current_gain = gain;
945 else
946 state->current_gain += gain_delta;
947 /* cannot be less than 0 (only if gain_delta is less than 0 we can have current_gain < 0) */
948 if (state->current_gain < 0)
949 state->current_gain = 0;
950
951 /* now split total gain to rf and bb gain */
952 gain = state->current_gain >> GAIN_ALPHA;
953
954 /* requested gain is bigger than rf gain limit - ACI/WBD adjustment */
955 if (gain > (state->rf_gain_limit >> WBD_ALPHA)) {
956 rf = state->rf_gain_limit >> WBD_ALPHA;
957 bb = gain - rf;
958 if (bb > state->bb_ramp[0])
959 bb = state->bb_ramp[0];
960 } else { /* high signal level -> all gains put on RF */
961 rf = gain;
962 bb = 0;
963 }
964
965 state->gain[0] = rf;
966 state->gain[1] = bb;
967
968 /* software ramp */
969 /* Start with RF gains */
970 g = state->rf_ramp + 1; /* point on RF LNA1 max gain */
971 ref = rf;
972 for (i = 0; i < 7; i++) { /* Go over all amplifiers => 5RF amps + 2 BB amps = 7 amps */
973 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 */
974 v = 0; /* force the gain to write for the current amp to be null */
975 else if (ref >= g[1]) /* Gain to set is higher than the high working point of this amp */
976 v = g[2]; /* force this amp to be full gain */
977 else /* compute the value to set to this amp because we are somewhere in his range */
978 v = ((ref - (g[1] - g[0])) * g[2]) / g[0];
979
980 if (i == 0) /* LNA 1 reg mapping */
981 gain_reg[0] = v;
982 else if (i == 1) /* LNA 2 reg mapping */
983 gain_reg[0] |= v << 7;
984 else if (i == 2) /* LNA 3 reg mapping */
985 gain_reg[1] = v;
986 else if (i == 3) /* LNA 4 reg mapping */
987 gain_reg[1] |= v << 7;
988 else if (i == 4) /* CBAND LNA reg mapping */
989 gain_reg[2] = v | state->rf_lt_def;
990 else if (i == 5) /* BB gain 1 reg mapping */
991 gain_reg[3] = v << 3;
992 else if (i == 6) /* BB gain 2 reg mapping */
993 gain_reg[3] |= v << 8;
994
995 g += 3; /* go to next gain bloc */
996
997 /* When RF is finished, start with BB */
998 if (i == 4) {
999 g = state->bb_ramp + 1; /* point on BB gain 1 max gain */
1000 ref = bb;
1001 }
1002 }
1003 gain_reg[3] |= state->bb_1_def;
1004 gain_reg[3] |= ((bb % 10) * 100) / 125;
1005
1006#ifdef DEBUG_AGC
1007 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,
1008 gain_reg[0], gain_reg[1], gain_reg[2], gain_reg[3]);
1009#endif
1010
1011 /* Write the amplifier regs */
1012 for (i = 0; i < 4; i++) {
1013 v = gain_reg[i];
1014 if (force || state->gain_reg[i] != v) {
1015 state->gain_reg[i] = v;
1016 dib0090_write_reg(state, gain_reg_addr[i], v);
1017 }
1018 }
1019}
1020
1021static void dib0090_set_boost(struct dib0090_state *state, int onoff)
1022{
1023 state->bb_1_def &= 0xdfff;
1024 state->bb_1_def |= onoff << 13;
1025}
1026
1027static void dib0090_set_rframp(struct dib0090_state *state, const u16 * cfg)
1028{
1029 state->rf_ramp = cfg;
1030}
1031
1032static void dib0090_set_rframp_pwm(struct dib0090_state *state, const u16 * cfg)
1033{
1034 state->rf_ramp = cfg;
1035
1036 dib0090_write_reg(state, 0x2a, 0xffff);
1037
1038 dprintk("total RF gain: %ddB, step: %d", (u32) cfg[0], dib0090_read_reg(state, 0x2a));
1039
1040 dib0090_write_regs(state, 0x2c, cfg + 3, 6);
1041 dib0090_write_regs(state, 0x3e, cfg + 9, 2);
1042}
1043
1044static void dib0090_set_bbramp(struct dib0090_state *state, const u16 * cfg)
1045{
1046 state->bb_ramp = cfg;
1047 dib0090_set_boost(state, cfg[0] > 500); /* we want the boost if the gain is higher that 50dB */
1048}
1049
1050static void dib0090_set_bbramp_pwm(struct dib0090_state *state, const u16 * cfg)
1051{
1052 state->bb_ramp = cfg;
1053
1054 dib0090_set_boost(state, cfg[0] > 500); /* we want the boost if the gain is higher that 50dB */
1055
1056 dib0090_write_reg(state, 0x33, 0xffff);
1057 dprintk("total BB gain: %ddB, step: %d", (u32) cfg[0], dib0090_read_reg(state, 0x33));
1058 dib0090_write_regs(state, 0x35, cfg + 3, 4);
1059}
1060
1061void dib0090_pwm_gain_reset(struct dvb_frontend *fe)
1062{
1063 struct dib0090_state *state = fe->tuner_priv;
1064 /* reset the AGC */
1065
1066 if (state->config->use_pwm_agc) {
1067#ifdef CONFIG_BAND_SBAND
1068 if (state->current_band == BAND_SBAND) {
1069 dib0090_set_rframp_pwm(state, rf_ramp_pwm_sband);
1070 dib0090_set_bbramp_pwm(state, bb_ramp_pwm_boost);
1071 } else
1072#endif
1073#ifdef CONFIG_BAND_CBAND
1074 if (state->current_band == BAND_CBAND) {
Olivier Grenie28fafca2011-01-04 04:27:11 -03001075 if (state->identity.in_soc) {
1076 dib0090_set_bbramp_pwm(state, bb_ramp_pwm_normal_socs);
1077 if (state->identity.version == SOC_8090_P1G_11R1 || state->identity.version == SOC_8090_P1G_21R1)
1078 dib0090_set_rframp_pwm(state, rf_ramp_pwm_cband_8090);
1079 else if (state->identity.version == SOC_7090_P1G_11R1 || state->identity.version == SOC_7090_P1G_21R1)
1080 dib0090_set_rframp_pwm(state, rf_ramp_pwm_cband_7090);
1081 } else {
1082 dib0090_set_rframp_pwm(state, rf_ramp_pwm_cband);
1083 dib0090_set_bbramp_pwm(state, bb_ramp_pwm_normal);
1084 }
Olivier Grenie03245a52009-12-04 13:27:57 -03001085 } else
1086#endif
1087#ifdef CONFIG_BAND_VHF
1088 if (state->current_band == BAND_VHF) {
Olivier Grenie28fafca2011-01-04 04:27:11 -03001089 if (state->identity.in_soc) {
1090 dib0090_set_bbramp_pwm(state, bb_ramp_pwm_normal_socs);
Olivier Grenie28fafca2011-01-04 04:27:11 -03001091 } else {
1092 dib0090_set_rframp_pwm(state, rf_ramp_pwm_vhf);
1093 dib0090_set_bbramp_pwm(state, bb_ramp_pwm_normal);
1094 }
Olivier Grenie03245a52009-12-04 13:27:57 -03001095 } else
1096#endif
1097 {
Olivier Grenie28fafca2011-01-04 04:27:11 -03001098 if (state->identity.in_soc) {
1099 if (state->identity.version == SOC_8090_P1G_11R1 || state->identity.version == SOC_8090_P1G_21R1)
1100 dib0090_set_rframp_pwm(state, rf_ramp_pwm_uhf_8090);
1101 else if (state->identity.version == SOC_7090_P1G_11R1 || state->identity.version == SOC_7090_P1G_21R1)
1102 dib0090_set_rframp_pwm(state, rf_ramp_pwm_uhf_7090);
1103 dib0090_set_bbramp_pwm(state, bb_ramp_pwm_normal_socs);
1104 } else {
1105 dib0090_set_rframp_pwm(state, rf_ramp_pwm_uhf);
1106 dib0090_set_bbramp_pwm(state, bb_ramp_pwm_normal);
1107 }
Olivier Grenie03245a52009-12-04 13:27:57 -03001108 }
1109
1110 if (state->rf_ramp[0] != 0)
1111 dib0090_write_reg(state, 0x32, (3 << 11));
1112 else
1113 dib0090_write_reg(state, 0x32, (0 << 11));
1114
Olivier Grenie2e802862011-08-05 10:39:15 -03001115 dib0090_write_reg(state, 0x04, 0x03);
Olivier Grenie9c783032009-12-07 07:49:40 -03001116 dib0090_write_reg(state, 0x39, (1 << 10));
Olivier Grenie03245a52009-12-04 13:27:57 -03001117 }
1118}
Olivier Grenie28fafca2011-01-04 04:27:11 -03001119
Olivier Grenie03245a52009-12-04 13:27:57 -03001120EXPORT_SYMBOL(dib0090_pwm_gain_reset);
Olivier Grenie9c783032009-12-07 07:49:40 -03001121
Olivier Grenie2e802862011-08-05 10:39:15 -03001122void dib0090_set_dc_servo(struct dvb_frontend *fe, u8 DC_servo_cutoff)
1123{
1124 struct dib0090_state *state = fe->tuner_priv;
1125 if (DC_servo_cutoff < 4)
1126 dib0090_write_reg(state, 0x04, DC_servo_cutoff);
1127}
1128EXPORT_SYMBOL(dib0090_set_dc_servo);
1129
Olivier Grenie28fafca2011-01-04 04:27:11 -03001130static u32 dib0090_get_slow_adc_val(struct dib0090_state *state)
1131{
1132 u16 adc_val = dib0090_read_reg(state, 0x1d);
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001133 if (state->identity.in_soc)
Olivier Grenie28fafca2011-01-04 04:27:11 -03001134 adc_val >>= 2;
Olivier Grenie28fafca2011-01-04 04:27:11 -03001135 return adc_val;
1136}
1137
Olivier Grenie03245a52009-12-04 13:27:57 -03001138int dib0090_gain_control(struct dvb_frontend *fe)
1139{
1140 struct dib0090_state *state = fe->tuner_priv;
1141 enum frontend_tune_state *tune_state = &state->tune_state;
1142 int ret = 10;
1143
1144 u16 wbd_val = 0;
1145 u8 apply_gain_immediatly = 1;
1146 s16 wbd_error = 0, adc_error = 0;
1147
1148 if (*tune_state == CT_AGC_START) {
1149 state->agc_freeze = 0;
1150 dib0090_write_reg(state, 0x04, 0x0);
1151
1152#ifdef CONFIG_BAND_SBAND
1153 if (state->current_band == BAND_SBAND) {
1154 dib0090_set_rframp(state, rf_ramp_sband);
1155 dib0090_set_bbramp(state, bb_ramp_boost);
1156 } else
1157#endif
1158#ifdef CONFIG_BAND_VHF
Olivier Grenie28fafca2011-01-04 04:27:11 -03001159 if (state->current_band == BAND_VHF && !state->identity.p1g) {
Olivier Grenie03245a52009-12-04 13:27:57 -03001160 dib0090_set_rframp(state, rf_ramp_vhf);
1161 dib0090_set_bbramp(state, bb_ramp_boost);
1162 } else
1163#endif
1164#ifdef CONFIG_BAND_CBAND
Olivier Grenie28fafca2011-01-04 04:27:11 -03001165 if (state->current_band == BAND_CBAND && !state->identity.p1g) {
Olivier Grenie03245a52009-12-04 13:27:57 -03001166 dib0090_set_rframp(state, rf_ramp_cband);
1167 dib0090_set_bbramp(state, bb_ramp_boost);
1168 } else
1169#endif
Olivier Grenie28fafca2011-01-04 04:27:11 -03001170 if ((state->current_band == BAND_CBAND || state->current_band == BAND_VHF) && state->identity.p1g) {
1171 dib0090_set_rframp(state, rf_ramp_cband_broadmatching);
1172 dib0090_set_bbramp(state, bb_ramp_boost);
1173 } else {
Olivier Grenie03245a52009-12-04 13:27:57 -03001174 dib0090_set_rframp(state, rf_ramp_uhf);
1175 dib0090_set_bbramp(state, bb_ramp_boost);
1176 }
1177
1178 dib0090_write_reg(state, 0x32, 0);
1179 dib0090_write_reg(state, 0x39, 0);
1180
1181 dib0090_wbd_target(state, state->current_rf);
1182
1183 state->rf_gain_limit = state->rf_ramp[0] << WBD_ALPHA;
1184 state->current_gain = ((state->rf_ramp[0] + state->bb_ramp[0]) / 2) << GAIN_ALPHA;
1185
1186 *tune_state = CT_AGC_STEP_0;
1187 } else if (!state->agc_freeze) {
Olivier Grenie28fafca2011-01-04 04:27:11 -03001188 s16 wbd = 0, i, cnt;
Olivier Grenie03245a52009-12-04 13:27:57 -03001189
1190 int adc;
Olivier Grenie28fafca2011-01-04 04:27:11 -03001191 wbd_val = dib0090_get_slow_adc_val(state);
Olivier Grenie03245a52009-12-04 13:27:57 -03001192
Olivier Grenie28fafca2011-01-04 04:27:11 -03001193 if (*tune_state == CT_AGC_STEP_0)
1194 cnt = 5;
1195 else
1196 cnt = 1;
1197
1198 for (i = 0; i < cnt; i++) {
1199 wbd_val = dib0090_get_slow_adc_val(state);
1200 wbd += dib0090_wbd_to_db(state, wbd_val);
1201 }
1202 wbd /= cnt;
Olivier Grenie03245a52009-12-04 13:27:57 -03001203 wbd_error = state->wbd_target - wbd;
1204
1205 if (*tune_state == CT_AGC_STEP_0) {
Olivier Grenie28fafca2011-01-04 04:27:11 -03001206 if (wbd_error < 0 && state->rf_gain_limit > 0 && !state->identity.p1g) {
Olivier Grenie03245a52009-12-04 13:27:57 -03001207#ifdef CONFIG_BAND_CBAND
1208 /* in case of CBAND tune reduce first the lt_gain2 before adjusting the RF gain */
1209 u8 ltg2 = (state->rf_lt_def >> 10) & 0x7;
1210 if (state->current_band == BAND_CBAND && ltg2) {
1211 ltg2 >>= 1;
1212 state->rf_lt_def &= ltg2 << 10; /* reduce in 3 steps from 7 to 0 */
1213 }
1214#endif
1215 } else {
1216 state->agc_step = 0;
1217 *tune_state = CT_AGC_STEP_1;
1218 }
1219 } else {
1220 /* calc the adc power */
1221 adc = state->config->get_adc_power(fe);
1222 adc = (adc * ((s32) 355774) + (((s32) 1) << 20)) >> 21; /* included in [0:-700] */
1223
1224 adc_error = (s16) (((s32) ADC_TARGET) - adc);
1225#ifdef CONFIG_STANDARD_DAB
1226 if (state->fe->dtv_property_cache.delivery_system == STANDARD_DAB)
Olivier Grenie28fafca2011-01-04 04:27:11 -03001227 adc_error -= 10;
Olivier Grenie03245a52009-12-04 13:27:57 -03001228#endif
1229#ifdef CONFIG_STANDARD_DVBT
1230 if (state->fe->dtv_property_cache.delivery_system == STANDARD_DVBT &&
Olivier Grenie28fafca2011-01-04 04:27:11 -03001231 (state->fe->dtv_property_cache.modulation == QAM_64 || state->fe->dtv_property_cache.modulation == QAM_16))
Olivier Grenie03245a52009-12-04 13:27:57 -03001232 adc_error += 60;
1233#endif
1234#ifdef CONFIG_SYS_ISDBT
1235 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 -03001236 0)
1237 &&
1238 ((state->fe->dtv_property_cache.layer[0].modulation ==
1239 QAM_64)
1240 || (state->fe->dtv_property_cache.
1241 layer[0].modulation == QAM_16)))
1242 ||
1243 ((state->fe->dtv_property_cache.layer[1].segment_count >
1244 0)
1245 &&
1246 ((state->fe->dtv_property_cache.layer[1].modulation ==
1247 QAM_64)
1248 || (state->fe->dtv_property_cache.
1249 layer[1].modulation == QAM_16)))
1250 ||
1251 ((state->fe->dtv_property_cache.layer[2].segment_count >
1252 0)
1253 &&
1254 ((state->fe->dtv_property_cache.layer[2].modulation ==
1255 QAM_64)
1256 || (state->fe->dtv_property_cache.
1257 layer[2].modulation == QAM_16)))
1258 )
1259 )
Olivier Grenie03245a52009-12-04 13:27:57 -03001260 adc_error += 60;
1261#endif
1262
1263 if (*tune_state == CT_AGC_STEP_1) { /* quickly go to the correct range of the ADC power */
1264 if (ABS(adc_error) < 50 || state->agc_step++ > 5) {
1265
1266#ifdef CONFIG_STANDARD_DAB
1267 if (state->fe->dtv_property_cache.delivery_system == STANDARD_DAB) {
1268 dib0090_write_reg(state, 0x02, (1 << 15) | (15 << 11) | (31 << 6) | (63)); /* cap value = 63 : narrow BB filter : Fc = 1.8MHz */
1269 dib0090_write_reg(state, 0x04, 0x0);
1270 } else
1271#endif
1272 {
1273 dib0090_write_reg(state, 0x02, (1 << 15) | (3 << 11) | (6 << 6) | (32));
1274 dib0090_write_reg(state, 0x04, 0x01); /*0 = 1KHz ; 1 = 150Hz ; 2 = 50Hz ; 3 = 50KHz ; 4 = servo fast */
1275 }
1276
1277 *tune_state = CT_AGC_STOP;
1278 }
1279 } else {
1280 /* everything higher than or equal to CT_AGC_STOP means tracking */
1281 ret = 100; /* 10ms interval */
1282 apply_gain_immediatly = 0;
1283 }
1284 }
1285#ifdef DEBUG_AGC
1286 dprintk
Olivier Grenie28fafca2011-01-04 04:27:11 -03001287 ("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 -03001288 (u32) *tune_state, (u32) adc, (u32) adc_error, (u32) wbd, (u32) wbd_error, (u32) wbd_val,
Olivier Grenie28fafca2011-01-04 04:27:11 -03001289 (u32) state->rf_gain_limit >> WBD_ALPHA, (s32) 200 + adc - (state->current_gain >> GAIN_ALPHA));
Olivier Grenie03245a52009-12-04 13:27:57 -03001290#endif
1291 }
1292
1293 /* apply gain */
1294 if (!state->agc_freeze)
1295 dib0090_gain_apply(state, adc_error, wbd_error, apply_gain_immediatly);
1296 return ret;
1297}
Olivier Grenie28fafca2011-01-04 04:27:11 -03001298
Olivier Grenie03245a52009-12-04 13:27:57 -03001299EXPORT_SYMBOL(dib0090_gain_control);
Olivier Grenie9c783032009-12-07 07:49:40 -03001300
Olivier Grenie03245a52009-12-04 13:27:57 -03001301void dib0090_get_current_gain(struct dvb_frontend *fe, u16 * rf, u16 * bb, u16 * rf_gain_limit, u16 * rflt)
1302{
1303 struct dib0090_state *state = fe->tuner_priv;
1304 if (rf)
1305 *rf = state->gain[0];
1306 if (bb)
1307 *bb = state->gain[1];
1308 if (rf_gain_limit)
1309 *rf_gain_limit = state->rf_gain_limit;
1310 if (rflt)
1311 *rflt = (state->rf_lt_def >> 10) & 0x7;
1312}
Olivier Grenie28fafca2011-01-04 04:27:11 -03001313
Olivier Grenie03245a52009-12-04 13:27:57 -03001314EXPORT_SYMBOL(dib0090_get_current_gain);
Olivier Grenie9c783032009-12-07 07:49:40 -03001315
Olivier Grenie28fafca2011-01-04 04:27:11 -03001316u16 dib0090_get_wbd_offset(struct dvb_frontend *fe)
Olivier Grenie03245a52009-12-04 13:27:57 -03001317{
Olivier Grenie28fafca2011-01-04 04:27:11 -03001318 struct dib0090_state *state = fe->tuner_priv;
1319 u32 f_MHz = state->fe->dtv_property_cache.frequency / 1000000;
1320 s32 current_temp = state->temperature;
1321 s32 wbd_thot, wbd_tcold;
1322 const struct dib0090_wbd_slope *wbd = state->current_wbd_table;
1323
1324 while (f_MHz > wbd->max_freq)
1325 wbd++;
1326
1327 dprintk("using wbd-table-entry with max freq %d", wbd->max_freq);
1328
1329 if (current_temp < 0)
1330 current_temp = 0;
1331 if (current_temp > 128)
1332 current_temp = 128;
1333
Olivier Grenie28fafca2011-01-04 04:27:11 -03001334 state->wbdmux &= ~(7 << 13);
1335 if (wbd->wbd_gain != 0)
1336 state->wbdmux |= (wbd->wbd_gain << 13);
1337 else
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001338 state->wbdmux |= (4 << 13);
Olivier Grenie28fafca2011-01-04 04:27:11 -03001339
1340 dib0090_write_reg(state, 0x10, state->wbdmux);
1341
Olivier Grenie28fafca2011-01-04 04:27:11 -03001342 wbd_thot = wbd->offset_hot - (((u32) wbd->slope_hot * f_MHz) >> 6);
1343 wbd_tcold = wbd->offset_cold - (((u32) wbd->slope_cold * f_MHz) >> 6);
1344
Olivier Grenie28fafca2011-01-04 04:27:11 -03001345 wbd_tcold += ((wbd_thot - wbd_tcold) * current_temp) >> 7;
1346
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001347 state->wbd_target = dib0090_wbd_to_db(state, state->wbd_offset + wbd_tcold);
Olivier Grenie28fafca2011-01-04 04:27:11 -03001348 dprintk("wbd-target: %d dB", (u32) state->wbd_target);
1349 dprintk("wbd offset applied is %d", wbd_tcold);
1350
1351 return state->wbd_offset + wbd_tcold;
Olivier Grenie03245a52009-12-04 13:27:57 -03001352}
Olivier Grenie28fafca2011-01-04 04:27:11 -03001353
Olivier Grenie03245a52009-12-04 13:27:57 -03001354EXPORT_SYMBOL(dib0090_get_wbd_offset);
Olivier Grenie9c783032009-12-07 07:49:40 -03001355
Olivier Grenie03245a52009-12-04 13:27:57 -03001356static const u16 dib0090_defaults[] = {
1357
1358 25, 0x01,
1359 0x0000,
1360 0x99a0,
1361 0x6008,
1362 0x0000,
Olivier Grenie28fafca2011-01-04 04:27:11 -03001363 0x8bcb,
Olivier Grenie03245a52009-12-04 13:27:57 -03001364 0x0000,
1365 0x0405,
1366 0x0000,
1367 0x0000,
1368 0x0000,
1369 0xb802,
1370 0x0300,
1371 0x2d12,
1372 0xbac0,
1373 0x7c00,
1374 0xdbb9,
1375 0x0954,
1376 0x0743,
1377 0x8000,
1378 0x0001,
1379 0x0040,
1380 0x0100,
1381 0x0000,
1382 0xe910,
1383 0x149e,
1384
1385 1, 0x1c,
1386 0xff2d,
1387
1388 1, 0x39,
1389 0x0000,
1390
Olivier Grenie03245a52009-12-04 13:27:57 -03001391 2, 0x1e,
1392 0x07FF,
1393 0x0007,
1394
1395 1, 0x24,
1396 EN_UHF | EN_CRYSTAL,
1397
1398 2, 0x3c,
1399 0x3ff,
1400 0x111,
1401 0
1402};
1403
Olivier Grenie28fafca2011-01-04 04:27:11 -03001404static const u16 dib0090_p1g_additionnal_defaults[] = {
Olivier Grenie28fafca2011-01-04 04:27:11 -03001405 1, 0x05,
1406 0xabcd,
1407
1408 1, 0x11,
1409 0x00b4,
1410
1411 1, 0x1c,
1412 0xfffd,
1413
1414 1, 0x40,
1415 0x108,
1416 0
1417};
1418
1419static void dib0090_set_default_config(struct dib0090_state *state, const u16 * n)
Olivier Grenie03245a52009-12-04 13:27:57 -03001420{
Olivier Grenie28fafca2011-01-04 04:27:11 -03001421 u16 l, r;
Olivier Grenie03245a52009-12-04 13:27:57 -03001422
Olivier Grenie03245a52009-12-04 13:27:57 -03001423 l = pgm_read_word(n++);
1424 while (l) {
1425 r = pgm_read_word(n++);
1426 do {
Olivier Grenie03245a52009-12-04 13:27:57 -03001427 dib0090_write_reg(state, r, pgm_read_word(n++));
1428 r++;
1429 } while (--l);
1430 l = pgm_read_word(n++);
1431 }
Olivier Grenie28fafca2011-01-04 04:27:11 -03001432}
1433
1434#define CAP_VALUE_MIN (u8) 9
1435#define CAP_VALUE_MAX (u8) 40
1436#define HR_MIN (u8) 25
1437#define HR_MAX (u8) 40
1438#define POLY_MIN (u8) 0
1439#define POLY_MAX (u8) 8
1440
1441void dib0090_set_EFUSE(struct dib0090_state *state)
1442{
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001443 u8 c, h, n;
1444 u16 e2, e4;
1445 u16 cal;
Olivier Grenie28fafca2011-01-04 04:27:11 -03001446
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001447 e2 = dib0090_read_reg(state, 0x26);
1448 e4 = dib0090_read_reg(state, 0x28);
Olivier Grenie28fafca2011-01-04 04:27:11 -03001449
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001450 if ((state->identity.version == P1D_E_F) ||
1451 (state->identity.version == P1G) || (e2 == 0xffff)) {
Olivier Grenie28fafca2011-01-04 04:27:11 -03001452
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001453 dib0090_write_reg(state, 0x22, 0x10);
1454 cal = (dib0090_read_reg(state, 0x22) >> 6) & 0x3ff;
Olivier Grenie28fafca2011-01-04 04:27:11 -03001455
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001456 if ((cal < 670) || (cal == 1023))
1457 cal = 850;
1458 n = 165 - ((cal * 10)>>6) ;
1459 e2 = e4 = (3<<12) | (34<<6) | (n);
1460 }
Olivier Grenie28fafca2011-01-04 04:27:11 -03001461
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001462 if (e2 != e4)
1463 e2 &= e4; /* Remove the redundancy */
Olivier Grenie28fafca2011-01-04 04:27:11 -03001464
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001465 if (e2 != 0xffff) {
1466 c = e2 & 0x3f;
1467 n = (e2 >> 12) & 0xf;
1468 h = (e2 >> 6) & 0x3f;
Olivier Grenie28fafca2011-01-04 04:27:11 -03001469
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001470 if ((c >= CAP_VALUE_MAX) || (c <= CAP_VALUE_MIN))
1471 c = 32;
1472 if ((h >= HR_MAX) || (h <= HR_MIN))
1473 h = 34;
1474 if ((n >= POLY_MAX) || (n <= POLY_MIN))
1475 n = 3;
Olivier Grenie28fafca2011-01-04 04:27:11 -03001476
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001477 dib0090_write_reg(state, 0x13, (h << 10)) ;
1478 e2 = (n<<11) | ((h>>2)<<6) | (c);
1479 dib0090_write_reg(state, 0x2, e2) ; /* Load the BB_2 */
1480 }
Olivier Grenie28fafca2011-01-04 04:27:11 -03001481}
1482
1483static int dib0090_reset(struct dvb_frontend *fe)
1484{
1485 struct dib0090_state *state = fe->tuner_priv;
1486
1487 dib0090_reset_digital(fe, state->config);
1488 if (dib0090_identify(fe) < 0)
1489 return -EIO;
1490
1491#ifdef CONFIG_TUNER_DIB0090_P1B_SUPPORT
1492 if (!(state->identity.version & 0x1)) /* it is P1B - reset is already done */
1493 return 0;
1494#endif
1495
1496 if (!state->identity.in_soc) {
1497 if ((dib0090_read_reg(state, 0x1a) >> 5) & 0x2)
1498 dib0090_write_reg(state, 0x1b, (EN_IQADC | EN_BB | EN_BIAS | EN_DIGCLK | EN_PLL | EN_CRYSTAL));
1499 else
1500 dib0090_write_reg(state, 0x1b, (EN_DIGCLK | EN_PLL | EN_CRYSTAL));
1501 }
1502
1503 dib0090_set_default_config(state, dib0090_defaults);
1504
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001505 if (state->identity.in_soc)
1506 dib0090_write_reg(state, 0x18, 0x2910); /* charge pump current = 0 */
Olivier Grenie28fafca2011-01-04 04:27:11 -03001507
1508 if (state->identity.p1g)
1509 dib0090_set_default_config(state, dib0090_p1g_additionnal_defaults);
1510
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001511 /* Update the efuse : Only available for KROSUS > P1C and SOC as well*/
1512 if (((state->identity.version & 0x1f) >= P1D_E_F) || (state->identity.in_soc))
1513 dib0090_set_EFUSE(state);
Olivier Grenie03245a52009-12-04 13:27:57 -03001514
1515 /* Congigure in function of the crystal */
Olivier Grenie2e802862011-08-05 10:39:15 -03001516 if (state->config->force_crystal_mode != 0)
1517 dib0090_write_reg(state, 0x14,
1518 state->config->force_crystal_mode & 3);
1519 else if (state->config->io.clock_khz >= 24000)
Olivier Grenie28fafca2011-01-04 04:27:11 -03001520 dib0090_write_reg(state, 0x14, 1);
Olivier Grenie03245a52009-12-04 13:27:57 -03001521 else
Olivier Grenie28fafca2011-01-04 04:27:11 -03001522 dib0090_write_reg(state, 0x14, 2);
Olivier Grenie03245a52009-12-04 13:27:57 -03001523 dprintk("Pll lock : %d", (dib0090_read_reg(state, 0x1a) >> 11) & 0x1);
1524
Olivier Grenie28fafca2011-01-04 04:27:11 -03001525 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 -03001526
1527 return 0;
1528}
1529
Olivier Grenie9c783032009-12-07 07:49:40 -03001530#define steps(u) (((u) > 15) ? ((u)-16) : (u))
Olivier Grenie03245a52009-12-04 13:27:57 -03001531#define INTERN_WAIT 10
1532static int dib0090_get_offset(struct dib0090_state *state, enum frontend_tune_state *tune_state)
1533{
1534 int ret = INTERN_WAIT * 10;
1535
1536 switch (*tune_state) {
1537 case CT_TUNER_STEP_2:
1538 /* Turns to positive */
1539 dib0090_write_reg(state, 0x1f, 0x7);
1540 *tune_state = CT_TUNER_STEP_3;
1541 break;
1542
1543 case CT_TUNER_STEP_3:
1544 state->adc_diff = dib0090_read_reg(state, 0x1d);
1545
1546 /* Turns to negative */
1547 dib0090_write_reg(state, 0x1f, 0x4);
1548 *tune_state = CT_TUNER_STEP_4;
1549 break;
1550
1551 case CT_TUNER_STEP_4:
1552 state->adc_diff -= dib0090_read_reg(state, 0x1d);
1553 *tune_state = CT_TUNER_STEP_5;
1554 ret = 0;
1555 break;
1556
1557 default:
1558 break;
1559 }
1560
1561 return ret;
1562}
1563
1564struct dc_calibration {
Olivier Grenie28fafca2011-01-04 04:27:11 -03001565 u8 addr;
1566 u8 offset;
1567 u8 pga:1;
1568 u16 bb1;
1569 u8 i:1;
Olivier Grenie03245a52009-12-04 13:27:57 -03001570};
1571
1572static const struct dc_calibration dc_table[] = {
1573 /* Step1 BB gain1= 26 with boost 1, gain 2 = 0 */
1574 {0x06, 5, 1, (1 << 13) | (0 << 8) | (26 << 3), 1},
1575 {0x07, 11, 1, (1 << 13) | (0 << 8) | (26 << 3), 0},
1576 /* Step 2 BB gain 1 = 26 with boost = 1 & gain 2 = 29 */
1577 {0x06, 0, 0, (1 << 13) | (29 << 8) | (26 << 3), 1},
1578 {0x06, 10, 0, (1 << 13) | (29 << 8) | (26 << 3), 0},
1579 {0},
1580};
1581
Olivier Grenie28fafca2011-01-04 04:27:11 -03001582static const struct dc_calibration dc_p1g_table[] = {
1583 /* Step1 BB gain1= 26 with boost 1, gain 2 = 0 */
1584 /* addr ; trim reg offset ; pga ; CTRL_BB1 value ; i or q */
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001585 {0x06, 5, 1, (1 << 13) | (0 << 8) | (15 << 3), 1},
1586 {0x07, 11, 1, (1 << 13) | (0 << 8) | (15 << 3), 0},
Olivier Grenie28fafca2011-01-04 04:27:11 -03001587 /* Step 2 BB gain 1 = 26 with boost = 1 & gain 2 = 29 */
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001588 {0x06, 0, 0, (1 << 13) | (29 << 8) | (15 << 3), 1},
1589 {0x06, 10, 0, (1 << 13) | (29 << 8) | (15 << 3), 0},
Olivier Grenie28fafca2011-01-04 04:27:11 -03001590 {0},
1591};
1592
Olivier Grenie03245a52009-12-04 13:27:57 -03001593static void dib0090_set_trim(struct dib0090_state *state)
1594{
1595 u16 *val;
1596
1597 if (state->dc->addr == 0x07)
1598 val = &state->bb7;
1599 else
1600 val = &state->bb6;
1601
1602 *val &= ~(0x1f << state->dc->offset);
1603 *val |= state->step << state->dc->offset;
1604
1605 dib0090_write_reg(state, state->dc->addr, *val);
1606}
1607
1608static int dib0090_dc_offset_calibration(struct dib0090_state *state, enum frontend_tune_state *tune_state)
1609{
1610 int ret = 0;
Olivier Grenie28fafca2011-01-04 04:27:11 -03001611 u16 reg;
Olivier Grenie03245a52009-12-04 13:27:57 -03001612
1613 switch (*tune_state) {
Olivier Grenie03245a52009-12-04 13:27:57 -03001614 case CT_TUNER_START:
Olivier Grenie28fafca2011-01-04 04:27:11 -03001615 dprintk("Start DC offset calibration");
Olivier Grenie03245a52009-12-04 13:27:57 -03001616
1617 /* force vcm2 = 0.8V */
1618 state->bb6 = 0;
1619 state->bb7 = 0x040d;
1620
Olivier Grenie28fafca2011-01-04 04:27:11 -03001621 /* the LNA AND LO are off */
1622 reg = dib0090_read_reg(state, 0x24) & 0x0ffb; /* shutdown lna and lo */
1623 dib0090_write_reg(state, 0x24, reg);
1624
1625 state->wbdmux = dib0090_read_reg(state, 0x10);
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001626 dib0090_write_reg(state, 0x10, (state->wbdmux & ~(0xff << 3)) | (0x7 << 3) | 0x3);
1627 dib0090_write_reg(state, 0x23, dib0090_read_reg(state, 0x23) & ~(1 << 14));
Olivier Grenie28fafca2011-01-04 04:27:11 -03001628
Olivier Grenie03245a52009-12-04 13:27:57 -03001629 state->dc = dc_table;
1630
Olivier Grenie28fafca2011-01-04 04:27:11 -03001631 if (state->identity.p1g)
1632 state->dc = dc_p1g_table;
Olivier Grenie03245a52009-12-04 13:27:57 -03001633 *tune_state = CT_TUNER_STEP_0;
1634
1635 /* fall through */
1636
1637 case CT_TUNER_STEP_0:
Olivier Grenie28fafca2011-01-04 04:27:11 -03001638 dprintk("Sart/continue DC calibration for %s path", (state->dc->i == 1) ? "I" : "Q");
Olivier Grenie03245a52009-12-04 13:27:57 -03001639 dib0090_write_reg(state, 0x01, state->dc->bb1);
1640 dib0090_write_reg(state, 0x07, state->bb7 | (state->dc->i << 7));
1641
1642 state->step = 0;
Olivier Grenie03245a52009-12-04 13:27:57 -03001643 state->min_adc_diff = 1023;
Olivier Grenie03245a52009-12-04 13:27:57 -03001644 *tune_state = CT_TUNER_STEP_1;
1645 ret = 50;
1646 break;
1647
1648 case CT_TUNER_STEP_1:
1649 dib0090_set_trim(state);
Olivier Grenie03245a52009-12-04 13:27:57 -03001650 *tune_state = CT_TUNER_STEP_2;
1651 break;
1652
1653 case CT_TUNER_STEP_2:
1654 case CT_TUNER_STEP_3:
1655 case CT_TUNER_STEP_4:
1656 ret = dib0090_get_offset(state, tune_state);
1657 break;
1658
1659 case CT_TUNER_STEP_5: /* found an offset */
Olivier Grenie28fafca2011-01-04 04:27:11 -03001660 dprintk("adc_diff = %d, current step= %d", (u32) state->adc_diff, state->step);
1661 if (state->step == 0 && state->adc_diff < 0) {
1662 state->min_adc_diff = -1023;
1663 dprintk("Change of sign of the minimum adc diff");
1664 }
1665
1666 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 -03001667
1668 /* first turn for this frequency */
1669 if (state->step == 0) {
1670 if (state->dc->pga && state->adc_diff < 0)
1671 state->step = 0x10;
1672 if (state->dc->pga == 0 && state->adc_diff > 0)
1673 state->step = 0x10;
1674 }
1675
Olivier Grenie28fafca2011-01-04 04:27:11 -03001676 /* Look for a change of Sign in the Adc_diff.min_adc_diff is used to STORE the setp N-1 */
1677 if ((state->adc_diff & 0x8000) == (state->min_adc_diff & 0x8000) && steps(state->step) < 15) {
1678 /* 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 -03001679 state->step++;
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001680 state->min_adc_diff = state->adc_diff;
Olivier Grenie03245a52009-12-04 13:27:57 -03001681 *tune_state = CT_TUNER_STEP_1;
1682 } else {
Olivier Grenie03245a52009-12-04 13:27:57 -03001683 /* the minimum was what we have seen in the step before */
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001684 if (ABS(state->adc_diff) > ABS(state->min_adc_diff)) {
Olivier Grenie28fafca2011-01-04 04:27:11 -03001685 dprintk("Since adc_diff N = %d > adc_diff step N-1 = %d, Come back one step", state->adc_diff, state->min_adc_diff);
1686 state->step--;
1687 }
Olivier Grenie03245a52009-12-04 13:27:57 -03001688
Olivier Grenie28fafca2011-01-04 04:27:11 -03001689 dib0090_set_trim(state);
1690 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 -03001691
1692 state->dc++;
1693 if (state->dc->addr == 0) /* done */
1694 *tune_state = CT_TUNER_STEP_6;
1695 else
1696 *tune_state = CT_TUNER_STEP_0;
1697
1698 }
1699 break;
1700
1701 case CT_TUNER_STEP_6:
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001702 dib0090_write_reg(state, 0x07, state->bb7 & ~0x0008);
Olivier Grenie03245a52009-12-04 13:27:57 -03001703 dib0090_write_reg(state, 0x1f, 0x7);
1704 *tune_state = CT_TUNER_START; /* reset done -> real tuning can now begin */
Olivier Grenie28fafca2011-01-04 04:27:11 -03001705 state->calibrate &= ~DC_CAL;
Olivier Grenie03245a52009-12-04 13:27:57 -03001706 default:
1707 break;
1708 }
1709 return ret;
1710}
1711
1712static int dib0090_wbd_calibration(struct dib0090_state *state, enum frontend_tune_state *tune_state)
1713{
Olivier Grenie28fafca2011-01-04 04:27:11 -03001714 u8 wbd_gain;
1715 const struct dib0090_wbd_slope *wbd = state->current_wbd_table;
1716
Olivier Grenie03245a52009-12-04 13:27:57 -03001717 switch (*tune_state) {
1718 case CT_TUNER_START:
Olivier Grenie28fafca2011-01-04 04:27:11 -03001719 while (state->current_rf / 1000 > wbd->max_freq)
1720 wbd++;
1721 if (wbd->wbd_gain != 0)
1722 wbd_gain = wbd->wbd_gain;
1723 else {
1724 wbd_gain = 4;
1725#if defined(CONFIG_BAND_LBAND) || defined(CONFIG_BAND_SBAND)
1726 if ((state->current_band == BAND_LBAND) || (state->current_band == BAND_SBAND))
1727 wbd_gain = 2;
1728#endif
1729 }
Olivier Grenie03245a52009-12-04 13:27:57 -03001730
Olivier Grenie28fafca2011-01-04 04:27:11 -03001731 if (wbd_gain == state->wbd_calibration_gain) { /* the WBD calibration has already been done */
1732 *tune_state = CT_TUNER_START;
1733 state->calibrate &= ~WBD_CAL;
1734 return 0;
1735 }
1736
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001737 dib0090_write_reg(state, 0x10, 0x1b81 | (1 << 10) | (wbd_gain << 13) | (1 << 3));
Olivier Grenie28fafca2011-01-04 04:27:11 -03001738
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001739 dib0090_write_reg(state, 0x24, ((EN_UHF & 0x0fff) | (1 << 1)));
Olivier Grenie03245a52009-12-04 13:27:57 -03001740 *tune_state = CT_TUNER_STEP_0;
Olivier Grenie28fafca2011-01-04 04:27:11 -03001741 state->wbd_calibration_gain = wbd_gain;
Olivier Grenie03245a52009-12-04 13:27:57 -03001742 return 90; /* wait for the WBDMUX to switch and for the ADC to sample */
Olivier Grenie03245a52009-12-04 13:27:57 -03001743
Olivier Grenie28fafca2011-01-04 04:27:11 -03001744 case CT_TUNER_STEP_0:
1745 state->wbd_offset = dib0090_get_slow_adc_val(state);
1746 dprintk("WBD calibration offset = %d", state->wbd_offset);
Olivier Grenie03245a52009-12-04 13:27:57 -03001747 *tune_state = CT_TUNER_START; /* reset done -> real tuning can now begin */
Olivier Grenie28fafca2011-01-04 04:27:11 -03001748 state->calibrate &= ~WBD_CAL;
Olivier Grenie03245a52009-12-04 13:27:57 -03001749 break;
Olivier Grenie28fafca2011-01-04 04:27:11 -03001750
Olivier Grenie03245a52009-12-04 13:27:57 -03001751 default:
1752 break;
1753 }
1754 return 0;
1755}
1756
1757static void dib0090_set_bandwidth(struct dib0090_state *state)
1758{
1759 u16 tmp;
1760
1761 if (state->fe->dtv_property_cache.bandwidth_hz / 1000 <= 5000)
1762 tmp = (3 << 14);
1763 else if (state->fe->dtv_property_cache.bandwidth_hz / 1000 <= 6000)
1764 tmp = (2 << 14);
1765 else if (state->fe->dtv_property_cache.bandwidth_hz / 1000 <= 7000)
1766 tmp = (1 << 14);
1767 else
1768 tmp = (0 << 14);
1769
1770 state->bb_1_def &= 0x3fff;
1771 state->bb_1_def |= tmp;
1772
1773 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 -03001774
1775 dib0090_write_reg(state, 0x03, 0x6008); /* = 0x6008 : vcm3_trim = 1 ; filter2_gm1_trim = 8 ; filter2_cutoff_freq = 0 */
1776 dib0090_write_reg(state, 0x04, 0x1); /* 0 = 1KHz ; 1 = 50Hz ; 2 = 150Hz ; 3 = 50KHz ; 4 = servo fast */
1777 if (state->identity.in_soc) {
1778 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 */
1779 } else {
1780 dib0090_write_reg(state, 0x02, (5 << 11) | (8 << 6) | (22 & 0x3f)); /* 22 = cap_value */
1781 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 */
1782 }
Olivier Grenie03245a52009-12-04 13:27:57 -03001783}
1784
1785static const struct dib0090_pll dib0090_pll_table[] = {
1786#ifdef CONFIG_BAND_CBAND
1787 {56000, 0, 9, 48, 6},
1788 {70000, 1, 9, 48, 6},
1789 {87000, 0, 8, 32, 4},
1790 {105000, 1, 8, 32, 4},
1791 {115000, 0, 7, 24, 6},
1792 {140000, 1, 7, 24, 6},
1793 {170000, 0, 6, 16, 4},
1794#endif
1795#ifdef CONFIG_BAND_VHF
1796 {200000, 1, 6, 16, 4},
1797 {230000, 0, 5, 12, 6},
1798 {280000, 1, 5, 12, 6},
1799 {340000, 0, 4, 8, 4},
1800 {380000, 1, 4, 8, 4},
1801 {450000, 0, 3, 6, 6},
1802#endif
1803#ifdef CONFIG_BAND_UHF
1804 {580000, 1, 3, 6, 6},
1805 {700000, 0, 2, 4, 4},
1806 {860000, 1, 2, 4, 4},
1807#endif
1808#ifdef CONFIG_BAND_LBAND
1809 {1800000, 1, 0, 2, 4},
1810#endif
1811#ifdef CONFIG_BAND_SBAND
1812 {2900000, 0, 14, 1, 4},
1813#endif
1814};
1815
1816static const struct dib0090_tuning dib0090_tuning_table_fm_vhf_on_cband[] = {
1817
1818#ifdef CONFIG_BAND_CBAND
1819 {184000, 4, 1, 15, 0x280, 0x2912, 0xb94e, EN_CAB},
1820 {227000, 4, 3, 15, 0x280, 0x2912, 0xb94e, EN_CAB},
1821 {380000, 4, 7, 15, 0x280, 0x2912, 0xb94e, EN_CAB},
1822#endif
1823#ifdef CONFIG_BAND_UHF
1824 {520000, 2, 0, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},
1825 {550000, 2, 2, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},
1826 {650000, 2, 3, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},
1827 {750000, 2, 5, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},
1828 {850000, 2, 6, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},
1829 {900000, 2, 7, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},
1830#endif
1831#ifdef CONFIG_BAND_LBAND
1832 {1500000, 4, 0, 20, 0x300, 0x1912, 0x82c9, EN_LBD},
1833 {1600000, 4, 1, 20, 0x300, 0x1912, 0x82c9, EN_LBD},
1834 {1800000, 4, 3, 20, 0x300, 0x1912, 0x82c9, EN_LBD},
1835#endif
1836#ifdef CONFIG_BAND_SBAND
1837 {2300000, 1, 4, 20, 0x300, 0x2d2A, 0x82c7, EN_SBD},
1838 {2900000, 1, 7, 20, 0x280, 0x2deb, 0x8347, EN_SBD},
1839#endif
1840};
1841
1842static const struct dib0090_tuning dib0090_tuning_table[] = {
1843
1844#ifdef CONFIG_BAND_CBAND
1845 {170000, 4, 1, 15, 0x280, 0x2912, 0xb94e, EN_CAB},
1846#endif
1847#ifdef CONFIG_BAND_VHF
1848 {184000, 1, 1, 15, 0x300, 0x4d12, 0xb94e, EN_VHF},
1849 {227000, 1, 3, 15, 0x300, 0x4d12, 0xb94e, EN_VHF},
1850 {380000, 1, 7, 15, 0x300, 0x4d12, 0xb94e, EN_VHF},
1851#endif
1852#ifdef CONFIG_BAND_UHF
1853 {520000, 2, 0, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},
1854 {550000, 2, 2, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},
1855 {650000, 2, 3, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},
1856 {750000, 2, 5, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},
1857 {850000, 2, 6, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},
1858 {900000, 2, 7, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},
1859#endif
1860#ifdef CONFIG_BAND_LBAND
1861 {1500000, 4, 0, 20, 0x300, 0x1912, 0x82c9, EN_LBD},
1862 {1600000, 4, 1, 20, 0x300, 0x1912, 0x82c9, EN_LBD},
1863 {1800000, 4, 3, 20, 0x300, 0x1912, 0x82c9, EN_LBD},
1864#endif
1865#ifdef CONFIG_BAND_SBAND
1866 {2300000, 1, 4, 20, 0x300, 0x2d2A, 0x82c7, EN_SBD},
1867 {2900000, 1, 7, 20, 0x280, 0x2deb, 0x8347, EN_SBD},
1868#endif
1869};
1870
Olivier Grenie28fafca2011-01-04 04:27:11 -03001871static const struct dib0090_tuning dib0090_p1g_tuning_table[] = {
Olivier Grenie28fafca2011-01-04 04:27:11 -03001872#ifdef CONFIG_BAND_CBAND
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001873 {170000, 4, 1, 0x820f, 0x300, 0x2d22, 0x82cb, EN_CAB},
Olivier Grenie28fafca2011-01-04 04:27:11 -03001874#endif
1875#ifdef CONFIG_BAND_VHF
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001876 {184000, 1, 1, 15, 0x300, 0x4d12, 0xb94e, EN_VHF},
1877 {227000, 1, 3, 15, 0x300, 0x4d12, 0xb94e, EN_VHF},
1878 {380000, 1, 7, 15, 0x300, 0x4d12, 0xb94e, EN_VHF},
Olivier Grenie28fafca2011-01-04 04:27:11 -03001879#endif
1880#ifdef CONFIG_BAND_UHF
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001881 {510000, 2, 0, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},
1882 {540000, 2, 1, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},
1883 {600000, 2, 3, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},
1884 {630000, 2, 4, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},
1885 {680000, 2, 5, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},
1886 {720000, 2, 6, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},
1887 {900000, 2, 7, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},
Olivier Grenie28fafca2011-01-04 04:27:11 -03001888#endif
1889#ifdef CONFIG_BAND_LBAND
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001890 {1500000, 4, 0, 20, 0x300, 0x1912, 0x82c9, EN_LBD},
1891 {1600000, 4, 1, 20, 0x300, 0x1912, 0x82c9, EN_LBD},
1892 {1800000, 4, 3, 20, 0x300, 0x1912, 0x82c9, EN_LBD},
Olivier Grenie28fafca2011-01-04 04:27:11 -03001893#endif
1894#ifdef CONFIG_BAND_SBAND
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001895 {2300000, 1, 4, 20, 0x300, 0x2d2A, 0x82c7, EN_SBD},
1896 {2900000, 1, 7, 20, 0x280, 0x2deb, 0x8347, EN_SBD},
Olivier Grenie28fafca2011-01-04 04:27:11 -03001897#endif
1898};
1899
1900static const struct dib0090_pll dib0090_p1g_pll_table[] = {
1901#ifdef CONFIG_BAND_CBAND
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001902 {57000, 0, 11, 48, 6},
1903 {70000, 1, 11, 48, 6},
1904 {86000, 0, 10, 32, 4},
1905 {105000, 1, 10, 32, 4},
1906 {115000, 0, 9, 24, 6},
1907 {140000, 1, 9, 24, 6},
1908 {170000, 0, 8, 16, 4},
Olivier Grenie28fafca2011-01-04 04:27:11 -03001909#endif
1910#ifdef CONFIG_BAND_VHF
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001911 {200000, 1, 8, 16, 4},
1912 {230000, 0, 7, 12, 6},
1913 {280000, 1, 7, 12, 6},
1914 {340000, 0, 6, 8, 4},
1915 {380000, 1, 6, 8, 4},
1916 {455000, 0, 5, 6, 6},
Olivier Grenie28fafca2011-01-04 04:27:11 -03001917#endif
1918#ifdef CONFIG_BAND_UHF
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001919 {580000, 1, 5, 6, 6},
1920 {680000, 0, 4, 4, 4},
1921 {860000, 1, 4, 4, 4},
Olivier Grenie28fafca2011-01-04 04:27:11 -03001922#endif
1923#ifdef CONFIG_BAND_LBAND
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001924 {1800000, 1, 2, 2, 4},
Olivier Grenie28fafca2011-01-04 04:27:11 -03001925#endif
1926#ifdef CONFIG_BAND_SBAND
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001927 {2900000, 0, 1, 1, 6},
Olivier Grenie28fafca2011-01-04 04:27:11 -03001928#endif
1929};
1930
1931static const struct dib0090_tuning dib0090_p1g_tuning_table_fm_vhf_on_cband[] = {
Olivier Grenie28fafca2011-01-04 04:27:11 -03001932#ifdef CONFIG_BAND_CBAND
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001933 {184000, 4, 3, 0x4187, 0x2c0, 0x2d22, 0x81cb, EN_CAB},
1934 {227000, 4, 3, 0x4187, 0x2c0, 0x2d22, 0x81cb, EN_CAB},
1935 {380000, 4, 3, 0x4187, 0x2c0, 0x2d22, 0x81cb, EN_CAB},
Olivier Grenie28fafca2011-01-04 04:27:11 -03001936#endif
1937#ifdef CONFIG_BAND_UHF
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001938 {520000, 2, 0, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},
1939 {550000, 2, 2, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},
1940 {650000, 2, 3, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},
1941 {750000, 2, 5, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},
1942 {850000, 2, 6, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},
1943 {900000, 2, 7, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},
Olivier Grenie28fafca2011-01-04 04:27:11 -03001944#endif
1945#ifdef CONFIG_BAND_LBAND
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001946 {1500000, 4, 0, 20, 0x300, 0x1912, 0x82c9, EN_LBD},
1947 {1600000, 4, 1, 20, 0x300, 0x1912, 0x82c9, EN_LBD},
1948 {1800000, 4, 3, 20, 0x300, 0x1912, 0x82c9, EN_LBD},
Olivier Grenie28fafca2011-01-04 04:27:11 -03001949#endif
1950#ifdef CONFIG_BAND_SBAND
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001951 {2300000, 1, 4, 20, 0x300, 0x2d2A, 0x82c7, EN_SBD},
1952 {2900000, 1, 7, 20, 0x280, 0x2deb, 0x8347, EN_SBD},
Olivier Grenie28fafca2011-01-04 04:27:11 -03001953#endif
1954};
1955
1956static const struct dib0090_tuning dib0090_tuning_table_cband_7090[] = {
Olivier Grenie28fafca2011-01-04 04:27:11 -03001957#ifdef CONFIG_BAND_CBAND
Olivier Grenie28fafca2011-01-04 04:27:11 -03001958 {300000, 4, 3, 0x018F, 0x2c0, 0x2d22, 0xb9ce, EN_CAB},
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001959 {380000, 4, 10, 0x018F, 0x2c0, 0x2d22, 0xb9ce, EN_CAB},
Olivier Grenie28fafca2011-01-04 04:27:11 -03001960 {570000, 4, 10, 0x8190, 0x2c0, 0x2d22, 0xb9ce, EN_CAB},
1961 {858000, 4, 5, 0x8190, 0x2c0, 0x2d22, 0xb9ce, EN_CAB},
1962#endif
1963};
1964
1965static int dib0090_captrim_search(struct dib0090_state *state, enum frontend_tune_state *tune_state)
1966{
1967 int ret = 0;
1968 u16 lo4 = 0xe900;
1969
1970 s16 adc_target;
1971 u16 adc;
1972 s8 step_sign;
1973 u8 force_soft_search = 0;
1974
1975 if (state->identity.version == SOC_8090_P1G_11R1 || state->identity.version == SOC_8090_P1G_21R1)
1976 force_soft_search = 1;
1977
1978 if (*tune_state == CT_TUNER_START) {
1979 dprintk("Start Captrim search : %s", (force_soft_search == 1) ? "FORCE SOFT SEARCH" : "AUTO");
1980 dib0090_write_reg(state, 0x10, 0x2B1);
1981 dib0090_write_reg(state, 0x1e, 0x0032);
1982
1983 if (!state->tuner_is_tuned) {
1984 /* prepare a complete captrim */
1985 if (!state->identity.p1g || force_soft_search)
1986 state->step = state->captrim = state->fcaptrim = 64;
1987
1988 state->current_rf = state->rf_request;
1989 } else { /* we are already tuned to this frequency - the configuration is correct */
1990 if (!state->identity.p1g || force_soft_search) {
1991 /* do a minimal captrim even if the frequency has not changed */
1992 state->step = 4;
1993 state->captrim = state->fcaptrim = dib0090_read_reg(state, 0x18) & 0x7f;
1994 }
1995 }
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001996 state->adc_diff = 3000;
Olivier Grenie28fafca2011-01-04 04:27:11 -03001997 *tune_state = CT_TUNER_STEP_0;
1998
1999 } else if (*tune_state == CT_TUNER_STEP_0) {
2000 if (state->identity.p1g && !force_soft_search) {
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002001 u8 ratio = 31;
Olivier Grenie28fafca2011-01-04 04:27:11 -03002002
2003 dib0090_write_reg(state, 0x40, (3 << 7) | (ratio << 2) | (1 << 1) | 1);
2004 dib0090_read_reg(state, 0x40);
Olivier Grenie28fafca2011-01-04 04:27:11 -03002005 ret = 50;
2006 } else {
2007 state->step /= 2;
2008 dib0090_write_reg(state, 0x18, lo4 | state->captrim);
2009
2010 if (state->identity.in_soc)
2011 ret = 25;
2012 }
2013 *tune_state = CT_TUNER_STEP_1;
2014
2015 } else if (*tune_state == CT_TUNER_STEP_1) {
2016 if (state->identity.p1g && !force_soft_search) {
2017 dib0090_write_reg(state, 0x40, 0x18c | (0 << 1) | 0);
2018 dib0090_read_reg(state, 0x40);
2019
2020 state->fcaptrim = dib0090_read_reg(state, 0x18) & 0x7F;
2021 dprintk("***Final Captrim= 0x%x", state->fcaptrim);
2022 *tune_state = CT_TUNER_STEP_3;
2023
2024 } else {
2025 /* MERGE for all krosus before P1G */
2026 adc = dib0090_get_slow_adc_val(state);
2027 dprintk("CAPTRIM=%d; ADC = %d (ADC) & %dmV", (u32) state->captrim, (u32) adc, (u32) (adc) * (u32) 1800 / (u32) 1024);
2028
2029 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 !!! */
2030 adc_target = 200;
2031 } else
2032 adc_target = 400;
2033
2034 if (adc >= adc_target) {
2035 adc -= adc_target;
2036 step_sign = -1;
2037 } else {
2038 adc = adc_target - adc;
2039 step_sign = 1;
2040 }
2041
2042 if (adc < state->adc_diff) {
2043 dprintk("CAPTRIM=%d is closer to target (%d/%d)", (u32) state->captrim, (u32) adc, (u32) state->adc_diff);
2044 state->adc_diff = adc;
2045 state->fcaptrim = state->captrim;
Olivier Grenie28fafca2011-01-04 04:27:11 -03002046 }
2047
2048 state->captrim += step_sign * state->step;
2049 if (state->step >= 1)
2050 *tune_state = CT_TUNER_STEP_0;
2051 else
2052 *tune_state = CT_TUNER_STEP_2;
2053
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002054 ret = 25;
Olivier Grenie28fafca2011-01-04 04:27:11 -03002055 }
2056 } else if (*tune_state == CT_TUNER_STEP_2) { /* this step is only used by krosus < P1G */
2057 /*write the final cptrim config */
2058 dib0090_write_reg(state, 0x18, lo4 | state->fcaptrim);
2059
2060 *tune_state = CT_TUNER_STEP_3;
2061
2062 } else if (*tune_state == CT_TUNER_STEP_3) {
2063 state->calibrate &= ~CAPTRIM_CAL;
2064 *tune_state = CT_TUNER_STEP_0;
2065 }
2066
2067 return ret;
2068}
2069
2070static int dib0090_get_temperature(struct dib0090_state *state, enum frontend_tune_state *tune_state)
2071{
2072 int ret = 15;
2073 s16 val;
2074
Olivier Grenie28fafca2011-01-04 04:27:11 -03002075 switch (*tune_state) {
2076 case CT_TUNER_START:
2077 state->wbdmux = dib0090_read_reg(state, 0x10);
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002078 dib0090_write_reg(state, 0x10, (state->wbdmux & ~(0xff << 3)) | (0x8 << 3));
Olivier Grenie28fafca2011-01-04 04:27:11 -03002079
2080 state->bias = dib0090_read_reg(state, 0x13);
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002081 dib0090_write_reg(state, 0x13, state->bias | (0x3 << 8));
Olivier Grenie28fafca2011-01-04 04:27:11 -03002082
2083 *tune_state = CT_TUNER_STEP_0;
2084 /* wait for the WBDMUX to switch and for the ADC to sample */
2085 break;
2086
2087 case CT_TUNER_STEP_0:
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002088 state->adc_diff = dib0090_get_slow_adc_val(state);
2089 dib0090_write_reg(state, 0x13, (state->bias & ~(0x3 << 8)) | (0x2 << 8));
Olivier Grenie28fafca2011-01-04 04:27:11 -03002090 *tune_state = CT_TUNER_STEP_1;
2091 break;
2092
2093 case CT_TUNER_STEP_1:
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002094 val = dib0090_get_slow_adc_val(state);
2095 state->temperature = ((s16) ((val - state->adc_diff) * 180) >> 8) + 55;
Olivier Grenie28fafca2011-01-04 04:27:11 -03002096
2097 dprintk("temperature: %d C", state->temperature - 30);
2098
2099 *tune_state = CT_TUNER_STEP_2;
2100 break;
2101
2102 case CT_TUNER_STEP_2:
Olivier Grenie28fafca2011-01-04 04:27:11 -03002103 dib0090_write_reg(state, 0x13, state->bias);
2104 dib0090_write_reg(state, 0x10, state->wbdmux); /* write back original WBDMUX */
2105
2106 *tune_state = CT_TUNER_START;
2107 state->calibrate &= ~TEMP_CAL;
2108 if (state->config->analog_output == 0)
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002109 dib0090_write_reg(state, 0x23, dib0090_read_reg(state, 0x23) | (1 << 14));
Olivier Grenie28fafca2011-01-04 04:27:11 -03002110
2111 break;
2112
2113 default:
2114 ret = 0;
2115 break;
2116 }
2117 return ret;
2118}
2119
Olivier Grenie03245a52009-12-04 13:27:57 -03002120#define WBD 0x781 /* 1 1 1 1 0000 0 0 1 */
2121static int dib0090_tune(struct dvb_frontend *fe)
2122{
2123 struct dib0090_state *state = fe->tuner_priv;
2124 const struct dib0090_tuning *tune = state->current_tune_table_index;
2125 const struct dib0090_pll *pll = state->current_pll_table_index;
2126 enum frontend_tune_state *tune_state = &state->tune_state;
2127
Olivier Grenie28fafca2011-01-04 04:27:11 -03002128 u16 lo5, lo6, Den, tmp;
Olivier Grenie03245a52009-12-04 13:27:57 -03002129 u32 FBDiv, Rest, FREF, VCOF_kHz = 0;
Olivier Grenie03245a52009-12-04 13:27:57 -03002130 int ret = 10; /* 1ms is the default delay most of the time */
2131 u8 c, i;
2132
Olivier Grenie28fafca2011-01-04 04:27:11 -03002133 /************************* VCO ***************************/
Olivier Grenie03245a52009-12-04 13:27:57 -03002134 /* Default values for FG */
2135 /* from these are needed : */
2136 /* Cp,HFdiv,VCOband,SD,Num,Den,FB and REFDiv */
2137
Olivier Grenie28fafca2011-01-04 04:27:11 -03002138 /* in any case we first need to do a calibration if needed */
2139 if (*tune_state == CT_TUNER_START) {
2140 /* deactivate DataTX before some calibrations */
2141 if (state->calibrate & (DC_CAL | TEMP_CAL | WBD_CAL))
2142 dib0090_write_reg(state, 0x23, dib0090_read_reg(state, 0x23) & ~(1 << 14));
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002143 else
2144 /* Activate DataTX in case a calibration has been done before */
2145 if (state->config->analog_output == 0)
2146 dib0090_write_reg(state, 0x23, dib0090_read_reg(state, 0x23) | (1 << 14));
Olivier Grenie03245a52009-12-04 13:27:57 -03002147 }
2148
Olivier Grenie28fafca2011-01-04 04:27:11 -03002149 if (state->calibrate & DC_CAL)
2150 return dib0090_dc_offset_calibration(state, tune_state);
2151 else if (state->calibrate & WBD_CAL) {
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002152 if (state->current_rf == 0)
Olivier Grenie28fafca2011-01-04 04:27:11 -03002153 state->current_rf = state->fe->dtv_property_cache.frequency / 1000;
Olivier Grenie28fafca2011-01-04 04:27:11 -03002154 return dib0090_wbd_calibration(state, tune_state);
2155 } else if (state->calibrate & TEMP_CAL)
2156 return dib0090_get_temperature(state, tune_state);
2157 else if (state->calibrate & CAPTRIM_CAL)
2158 return dib0090_captrim_search(state, tune_state);
2159
Olivier Grenie03245a52009-12-04 13:27:57 -03002160 if (*tune_state == CT_TUNER_START) {
Olivier Grenie28fafca2011-01-04 04:27:11 -03002161 /* 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 */
2162 if (state->config->use_pwm_agc && state->identity.in_soc) {
2163 tmp = dib0090_read_reg(state, 0x39);
2164 if ((tmp >> 10) & 0x1)
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002165 dib0090_write_reg(state, 0x39, tmp & ~(1 << 10));
Olivier Grenie28fafca2011-01-04 04:27:11 -03002166 }
Olivier Grenie03245a52009-12-04 13:27:57 -03002167
Olivier Grenie28fafca2011-01-04 04:27:11 -03002168 state->current_band = (u8) BAND_OF_FREQUENCY(state->fe->dtv_property_cache.frequency / 1000);
2169 state->rf_request =
2170 state->fe->dtv_property_cache.frequency / 1000 + (state->current_band ==
2171 BAND_UHF ? state->config->freq_offset_khz_uhf : state->config->
2172 freq_offset_khz_vhf);
2173
2174 /* in ISDB-T 1seg we shift tuning frequency */
2175 if ((state->fe->dtv_property_cache.delivery_system == SYS_ISDBT && state->fe->dtv_property_cache.isdbt_sb_mode == 1
2176 && state->fe->dtv_property_cache.isdbt_partial_reception == 0)) {
2177 const struct dib0090_low_if_offset_table *LUT_offset = state->config->low_if;
2178 u8 found_offset = 0;
2179 u32 margin_khz = 100;
2180
2181 if (LUT_offset != NULL) {
2182 while (LUT_offset->RF_freq != 0xffff) {
2183 if (((state->rf_request > (LUT_offset->RF_freq - margin_khz))
2184 && (state->rf_request < (LUT_offset->RF_freq + margin_khz)))
2185 && LUT_offset->std == state->fe->dtv_property_cache.delivery_system) {
2186 state->rf_request += LUT_offset->offset_khz;
2187 found_offset = 1;
2188 break;
2189 }
2190 LUT_offset++;
2191 }
2192 }
2193
2194 if (found_offset == 0)
2195 state->rf_request += 400;
2196 }
2197 if (state->current_rf != state->rf_request || (state->current_standard != state->fe->dtv_property_cache.delivery_system)) {
2198 state->tuner_is_tuned = 0;
Olivier Grenie03245a52009-12-04 13:27:57 -03002199 state->current_rf = 0;
Olivier Grenie28fafca2011-01-04 04:27:11 -03002200 state->current_standard = 0;
Olivier Grenie03245a52009-12-04 13:27:57 -03002201
Olivier Grenie28fafca2011-01-04 04:27:11 -03002202 tune = dib0090_tuning_table;
2203 if (state->identity.p1g)
2204 tune = dib0090_p1g_tuning_table;
Olivier Grenie03245a52009-12-04 13:27:57 -03002205
Olivier Grenie28fafca2011-01-04 04:27:11 -03002206 tmp = (state->identity.version >> 5) & 0x7;
2207
2208 if (state->identity.in_soc) {
2209 if (state->config->force_cband_input) { /* Use the CBAND input for all band */
2210 if (state->current_band & BAND_CBAND || state->current_band & BAND_FM || state->current_band & BAND_VHF
2211 || state->current_band & BAND_UHF) {
2212 state->current_band = BAND_CBAND;
2213 tune = dib0090_tuning_table_cband_7090;
2214 }
2215 } else { /* Use the CBAND input for all band under UHF */
2216 if (state->current_band & BAND_CBAND || state->current_band & BAND_FM || state->current_band & BAND_VHF) {
2217 state->current_band = BAND_CBAND;
2218 tune = dib0090_tuning_table_cband_7090;
2219 }
2220 }
2221 } else
2222 if (tmp == 0x4 || tmp == 0x7) {
2223 /* CBAND tuner version for VHF */
2224 if (state->current_band == BAND_FM || state->current_band == BAND_CBAND || state->current_band == BAND_VHF) {
2225 state->current_band = BAND_CBAND; /* Force CBAND */
2226
2227 tune = dib0090_tuning_table_fm_vhf_on_cband;
2228 if (state->identity.p1g)
2229 tune = dib0090_p1g_tuning_table_fm_vhf_on_cband;
2230 }
2231 }
2232
2233 pll = dib0090_pll_table;
2234 if (state->identity.p1g)
2235 pll = dib0090_p1g_pll_table;
2236
2237 /* Look for the interval */
2238 while (state->rf_request > tune->max_freq)
2239 tune++;
2240 while (state->rf_request > pll->max_freq)
2241 pll++;
2242
2243 state->current_tune_table_index = tune;
2244 state->current_pll_table_index = pll;
2245
Olivier Grenie03245a52009-12-04 13:27:57 -03002246 dib0090_write_reg(state, 0x0b, 0xb800 | (tune->switch_trim));
2247
Olivier Grenie28fafca2011-01-04 04:27:11 -03002248 VCOF_kHz = (pll->hfdiv * state->rf_request) * 2;
Olivier Grenie03245a52009-12-04 13:27:57 -03002249
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002250 FREF = state->config->io.clock_khz;
Olivier Grenie28fafca2011-01-04 04:27:11 -03002251 if (state->config->fref_clock_ratio != 0)
2252 FREF /= state->config->fref_clock_ratio;
Olivier Grenie03245a52009-12-04 13:27:57 -03002253
Olivier Grenie03245a52009-12-04 13:27:57 -03002254 FBDiv = (VCOF_kHz / pll->topresc / FREF);
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002255 Rest = (VCOF_kHz / pll->topresc) - FBDiv * FREF;
Olivier Grenie03245a52009-12-04 13:27:57 -03002256
2257 if (Rest < LPF)
2258 Rest = 0;
2259 else if (Rest < 2 * LPF)
2260 Rest = 2 * LPF;
2261 else if (Rest > (FREF - LPF)) {
2262 Rest = 0;
2263 FBDiv += 1;
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002264 } else if (Rest > (FREF - 2 * LPF))
Olivier Grenie03245a52009-12-04 13:27:57 -03002265 Rest = FREF - 2 * LPF;
2266 Rest = (Rest * 6528) / (FREF / 10);
Olivier Grenie28fafca2011-01-04 04:27:11 -03002267 state->rest = Rest;
2268
2269 /* external loop filter, otherwise:
2270 * lo5 = (0 << 15) | (0 << 12) | (0 << 11) | (3 << 9) | (4 << 6) | (3 << 4) | 4;
2271 * lo6 = 0x0e34 */
2272
2273 if (Rest == 0) {
2274 if (pll->vco_band)
2275 lo5 = 0x049f;
Olivier Grenie28fafca2011-01-04 04:27:11 -03002276 else
2277 lo5 = 0x041f;
2278 } else {
2279 if (pll->vco_band)
2280 lo5 = 0x049e;
2281 else if (state->config->analog_output)
2282 lo5 = 0x041d;
2283 else
2284 lo5 = 0x041c;
2285 }
2286
2287 if (state->identity.p1g) { /* Bias is done automatically in P1G */
2288 if (state->identity.in_soc) {
2289 if (state->identity.version == SOC_8090_P1G_11R1)
2290 lo5 = 0x46f;
2291 else
2292 lo5 = 0x42f;
2293 } else
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002294 lo5 = 0x42c;
Olivier Grenie28fafca2011-01-04 04:27:11 -03002295 }
2296
2297 lo5 |= (pll->hfdiv_code << 11) | (pll->vco_band << 7); /* bit 15 is the split to the slave, we do not do it here */
2298
Olivier Grenie28fafca2011-01-04 04:27:11 -03002299 if (!state->config->io.pll_int_loop_filt) {
2300 if (state->identity.in_soc)
2301 lo6 = 0xff98;
2302 else if (state->identity.p1g || (Rest == 0))
2303 lo6 = 0xfff8;
2304 else
2305 lo6 = 0xff28;
2306 } else
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002307 lo6 = (state->config->io.pll_int_loop_filt << 3);
Olivier Grenie03245a52009-12-04 13:27:57 -03002308
2309 Den = 1;
2310
Olivier Grenie03245a52009-12-04 13:27:57 -03002311 if (Rest > 0) {
2312 if (state->config->analog_output)
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002313 lo6 |= (1 << 2) | 2;
Olivier Grenie28fafca2011-01-04 04:27:11 -03002314 else {
2315 if (state->identity.in_soc)
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002316 lo6 |= (1 << 2) | 2;
Olivier Grenie28fafca2011-01-04 04:27:11 -03002317 else
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002318 lo6 |= (1 << 2) | 2;
Olivier Grenie28fafca2011-01-04 04:27:11 -03002319 }
Olivier Grenie03245a52009-12-04 13:27:57 -03002320 Den = 255;
2321 }
Olivier Grenie03245a52009-12-04 13:27:57 -03002322 dib0090_write_reg(state, 0x15, (u16) FBDiv);
Olivier Grenie28fafca2011-01-04 04:27:11 -03002323 if (state->config->fref_clock_ratio != 0)
2324 dib0090_write_reg(state, 0x16, (Den << 8) | state->config->fref_clock_ratio);
2325 else
2326 dib0090_write_reg(state, 0x16, (Den << 8) | 1);
Olivier Grenie03245a52009-12-04 13:27:57 -03002327 dib0090_write_reg(state, 0x17, (u16) Rest);
Olivier Grenie03245a52009-12-04 13:27:57 -03002328 dib0090_write_reg(state, 0x19, lo5);
Olivier Grenie03245a52009-12-04 13:27:57 -03002329 dib0090_write_reg(state, 0x1c, lo6);
2330
2331 lo6 = tune->tuner_enable;
2332 if (state->config->analog_output)
2333 lo6 = (lo6 & 0xff9f) | 0x2;
2334
Olivier Grenie28fafca2011-01-04 04:27:11 -03002335 dib0090_write_reg(state, 0x24, lo6 | EN_LO | state->config->use_pwm_agc * EN_CRYSTAL);
Olivier Grenie03245a52009-12-04 13:27:57 -03002336
Olivier Grenie03245a52009-12-04 13:27:57 -03002337 }
Olivier Grenie03245a52009-12-04 13:27:57 -03002338
Olivier Grenie28fafca2011-01-04 04:27:11 -03002339 state->current_rf = state->rf_request;
2340 state->current_standard = state->fe->dtv_property_cache.delivery_system;
Olivier Grenie03245a52009-12-04 13:27:57 -03002341
2342 ret = 20;
Olivier Grenie28fafca2011-01-04 04:27:11 -03002343 state->calibrate = CAPTRIM_CAL; /* captrim serach now */
2344 }
Olivier Grenie03245a52009-12-04 13:27:57 -03002345
Olivier Grenie28fafca2011-01-04 04:27:11 -03002346 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 */
2347 const struct dib0090_wbd_slope *wbd = state->current_wbd_table;
Olivier Grenie03245a52009-12-04 13:27:57 -03002348
Olivier Grenie28fafca2011-01-04 04:27:11 -03002349 while (state->current_rf / 1000 > wbd->max_freq)
2350 wbd++;
Olivier Grenie03245a52009-12-04 13:27:57 -03002351
Olivier Grenie03245a52009-12-04 13:27:57 -03002352 dib0090_write_reg(state, 0x1e, 0x07ff);
Olivier Grenie28fafca2011-01-04 04:27:11 -03002353 dprintk("Final Captrim: %d", (u32) state->fcaptrim);
2354 dprintk("HFDIV code: %d", (u32) pll->hfdiv_code);
2355 dprintk("VCO = %d", (u32) pll->vco_band);
2356 dprintk("VCOF in kHz: %d ((%d*%d) << 1))", (u32) ((pll->hfdiv * state->rf_request) * 2), (u32) pll->hfdiv, (u32) state->rf_request);
2357 dprintk("REFDIV: %d, FREF: %d", (u32) 1, (u32) state->config->io.clock_khz);
2358 dprintk("FBDIV: %d, Rest: %d", (u32) dib0090_read_reg(state, 0x15), (u32) dib0090_read_reg(state, 0x17));
2359 dprintk("Num: %d, Den: %d, SD: %d", (u32) dib0090_read_reg(state, 0x17), (u32) (dib0090_read_reg(state, 0x16) >> 8),
2360 (u32) dib0090_read_reg(state, 0x1c) & 0x3);
Olivier Grenie03245a52009-12-04 13:27:57 -03002361
Olivier Grenie28fafca2011-01-04 04:27:11 -03002362#define WBD 0x781 /* 1 1 1 1 0000 0 0 1 */
Olivier Grenie03245a52009-12-04 13:27:57 -03002363 c = 4;
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002364 i = 3;
Olivier Grenie28fafca2011-01-04 04:27:11 -03002365
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002366 if (wbd->wbd_gain != 0)
Olivier Grenie28fafca2011-01-04 04:27:11 -03002367 c = wbd->wbd_gain;
2368
Olivier Grenie28fafca2011-01-04 04:27:11 -03002369 state->wbdmux = (c << 13) | (i << 11) | (WBD | (state->config->use_pwm_agc << 1));
2370 dib0090_write_reg(state, 0x10, state->wbdmux);
2371
2372 if ((tune->tuner_enable == EN_CAB) && state->identity.p1g) {
2373 dprintk("P1G : The cable band is selected and lna_tune = %d", tune->lna_tune);
2374 dib0090_write_reg(state, 0x09, tune->lna_bias);
2375 dib0090_write_reg(state, 0x0b, 0xb800 | (tune->lna_tune << 6) | (tune->switch_trim));
2376 } else
2377 dib0090_write_reg(state, 0x09, (tune->lna_tune << 5) | tune->lna_bias);
2378
Olivier Grenie03245a52009-12-04 13:27:57 -03002379 dib0090_write_reg(state, 0x0c, tune->v2i);
2380 dib0090_write_reg(state, 0x0d, tune->mix);
2381 dib0090_write_reg(state, 0x0e, tune->load);
Olivier Grenie28fafca2011-01-04 04:27:11 -03002382 *tune_state = CT_TUNER_STEP_1;
Olivier Grenie03245a52009-12-04 13:27:57 -03002383
Olivier Grenie28fafca2011-01-04 04:27:11 -03002384 } else if (*tune_state == CT_TUNER_STEP_1) {
Olivier Grenie03245a52009-12-04 13:27:57 -03002385 /* initialize the lt gain register */
2386 state->rf_lt_def = 0x7c00;
Olivier Grenie03245a52009-12-04 13:27:57 -03002387
2388 dib0090_set_bandwidth(state);
2389 state->tuner_is_tuned = 1;
Olivier Grenie28fafca2011-01-04 04:27:11 -03002390
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002391 state->calibrate |= WBD_CAL;
2392 state->calibrate |= TEMP_CAL;
Olivier Grenie03245a52009-12-04 13:27:57 -03002393 *tune_state = CT_TUNER_STOP;
2394 } else
2395 ret = FE_CALLBACK_TIME_NEVER;
2396 return ret;
2397}
2398
2399static int dib0090_release(struct dvb_frontend *fe)
2400{
2401 kfree(fe->tuner_priv);
2402 fe->tuner_priv = NULL;
2403 return 0;
2404}
2405
2406enum frontend_tune_state dib0090_get_tune_state(struct dvb_frontend *fe)
2407{
2408 struct dib0090_state *state = fe->tuner_priv;
2409
2410 return state->tune_state;
2411}
Olivier Grenie28fafca2011-01-04 04:27:11 -03002412
Olivier Grenie03245a52009-12-04 13:27:57 -03002413EXPORT_SYMBOL(dib0090_get_tune_state);
2414
2415int dib0090_set_tune_state(struct dvb_frontend *fe, enum frontend_tune_state tune_state)
2416{
2417 struct dib0090_state *state = fe->tuner_priv;
2418
2419 state->tune_state = tune_state;
2420 return 0;
2421}
Olivier Grenie28fafca2011-01-04 04:27:11 -03002422
Olivier Grenie03245a52009-12-04 13:27:57 -03002423EXPORT_SYMBOL(dib0090_set_tune_state);
2424
2425static int dib0090_get_frequency(struct dvb_frontend *fe, u32 * frequency)
2426{
2427 struct dib0090_state *state = fe->tuner_priv;
2428
2429 *frequency = 1000 * state->current_rf;
2430 return 0;
2431}
2432
2433static int dib0090_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *p)
2434{
2435 struct dib0090_state *state = fe->tuner_priv;
Olivier Grenie28fafca2011-01-04 04:27:11 -03002436 u32 ret;
Olivier Grenie03245a52009-12-04 13:27:57 -03002437
2438 state->tune_state = CT_TUNER_START;
2439
2440 do {
2441 ret = dib0090_tune(fe);
2442 if (ret != FE_CALLBACK_TIME_NEVER)
2443 msleep(ret / 10);
2444 else
2445 break;
2446 } while (state->tune_state != CT_TUNER_STOP);
2447
2448 return 0;
2449}
2450
2451static const struct dvb_tuner_ops dib0090_ops = {
2452 .info = {
2453 .name = "DiBcom DiB0090",
2454 .frequency_min = 45000000,
2455 .frequency_max = 860000000,
2456 .frequency_step = 1000,
2457 },
2458 .release = dib0090_release,
2459
2460 .init = dib0090_wakeup,
2461 .sleep = dib0090_sleep,
2462 .set_params = dib0090_set_params,
2463 .get_frequency = dib0090_get_frequency,
2464};
2465
Olivier Grenie28fafca2011-01-04 04:27:11 -03002466static const struct dvb_tuner_ops dib0090_fw_ops = {
2467 .info = {
2468 .name = "DiBcom DiB0090",
2469 .frequency_min = 45000000,
2470 .frequency_max = 860000000,
2471 .frequency_step = 1000,
2472 },
2473 .release = dib0090_release,
2474
2475 .init = NULL,
2476 .sleep = NULL,
2477 .set_params = NULL,
2478 .get_frequency = NULL,
2479};
2480
2481static const struct dib0090_wbd_slope dib0090_wbd_table_default[] = {
2482 {470, 0, 250, 0, 100, 4},
2483 {860, 51, 866, 21, 375, 4},
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002484 {1700, 0, 800, 0, 850, 4},
2485 {2900, 0, 250, 0, 100, 6},
Olivier Grenie28fafca2011-01-04 04:27:11 -03002486 {0xFFFF, 0, 0, 0, 0, 0},
2487};
2488
Olivier Grenie03245a52009-12-04 13:27:57 -03002489struct dvb_frontend *dib0090_register(struct dvb_frontend *fe, struct i2c_adapter *i2c, const struct dib0090_config *config)
2490{
2491 struct dib0090_state *st = kzalloc(sizeof(struct dib0090_state), GFP_KERNEL);
2492 if (st == NULL)
2493 return NULL;
2494
2495 st->config = config;
2496 st->i2c = i2c;
2497 st->fe = fe;
Patrick Boettcher79fcce32011-08-03 12:08:21 -03002498 mutex_init(&st->i2c_buffer_lock);
Olivier Grenie03245a52009-12-04 13:27:57 -03002499 fe->tuner_priv = st;
2500
Olivier Grenie28fafca2011-01-04 04:27:11 -03002501 if (config->wbd == NULL)
2502 st->current_wbd_table = dib0090_wbd_table_default;
2503 else
2504 st->current_wbd_table = config->wbd;
2505
Olivier Grenie03245a52009-12-04 13:27:57 -03002506 if (dib0090_reset(fe) != 0)
2507 goto free_mem;
2508
2509 printk(KERN_INFO "DiB0090: successfully identified\n");
2510 memcpy(&fe->ops.tuner_ops, &dib0090_ops, sizeof(struct dvb_tuner_ops));
2511
2512 return fe;
2513 free_mem:
2514 kfree(st);
2515 fe->tuner_priv = NULL;
2516 return NULL;
2517}
Olivier Grenie28fafca2011-01-04 04:27:11 -03002518
Olivier Grenie03245a52009-12-04 13:27:57 -03002519EXPORT_SYMBOL(dib0090_register);
2520
Olivier Grenie28fafca2011-01-04 04:27:11 -03002521struct dvb_frontend *dib0090_fw_register(struct dvb_frontend *fe, struct i2c_adapter *i2c, const struct dib0090_config *config)
2522{
2523 struct dib0090_fw_state *st = kzalloc(sizeof(struct dib0090_fw_state), GFP_KERNEL);
2524 if (st == NULL)
2525 return NULL;
2526
2527 st->config = config;
2528 st->i2c = i2c;
2529 st->fe = fe;
Patrick Boettcher79fcce32011-08-03 12:08:21 -03002530 mutex_init(&st->i2c_buffer_lock);
Olivier Grenie28fafca2011-01-04 04:27:11 -03002531 fe->tuner_priv = st;
2532
2533 if (dib0090_fw_reset_digital(fe, st->config) != 0)
2534 goto free_mem;
2535
2536 dprintk("DiB0090 FW: successfully identified");
2537 memcpy(&fe->ops.tuner_ops, &dib0090_fw_ops, sizeof(struct dvb_tuner_ops));
2538
2539 return fe;
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002540free_mem:
Olivier Grenie28fafca2011-01-04 04:27:11 -03002541 kfree(st);
2542 fe->tuner_priv = NULL;
2543 return NULL;
2544}
Olivier Grenie28fafca2011-01-04 04:27:11 -03002545EXPORT_SYMBOL(dib0090_fw_register);
2546
Olivier Grenie03245a52009-12-04 13:27:57 -03002547MODULE_AUTHOR("Patrick Boettcher <pboettcher@dibcom.fr>");
2548MODULE_AUTHOR("Olivier Grenie <olivier.grenie@dibcom.fr>");
2549MODULE_DESCRIPTION("Driver for the DiBcom 0090 base-band RF Tuner");
2550MODULE_LICENSE("GPL");