blob: d879dc0607f42c50617f125800a4c0b88f6d7d50 [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:
Jesper Juhlf1ed3212012-02-26 18:57:13 -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);
Olivier Grenie28fafca2011-01-04 04:27:11 -0300531 dib0090_write_reg(state, 0x24, EN_PLL | EN_CRYSTAL);
Olivier Grenieaedabf72012-12-31 10:38:44 -0300532 if (cfg->in_soc)
533 return;
Olivier Grenie03245a52009-12-04 13:27:57 -0300534
Olivier Grenieaedabf72012-12-31 10:38:44 -0300535 dib0090_write_reg(state, 0x1b, EN_DIGCLK | EN_PLL | EN_CRYSTAL); /* PLL, DIG_CLK and CRYSTAL remain */
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));
Olivier Grenie28fafca2011-01-04 04:27:11 -0300544
545 /* Read Pll current config * */
546 PllCfg = dib0090_read_reg(state, 0x21);
547
548 /** Reconfigure PLL if current setting is different from default setting **/
549 if ((PllCfg & 0x1FFF) != ((cfg->io.pll_range << 12) | (cfg->io.pll_loopdiv << 6) | (cfg->io.pll_prediv)) && (!cfg->in_soc)
550 && !cfg->io.pll_bypass) {
551
552 /* Set Bypass mode */
553 PllCfg |= (1 << 15);
554 dib0090_write_reg(state, 0x21, PllCfg);
555
556 /* Set Reset Pll */
557 PllCfg &= ~(1 << 13);
558 dib0090_write_reg(state, 0x21, PllCfg);
559
560 /*** Set new Pll configuration in bypass and reset state ***/
561 PllCfg = (1 << 15) | (0 << 13) | (cfg->io.pll_range << 12) | (cfg->io.pll_loopdiv << 6) | (cfg->io.pll_prediv);
562 dib0090_write_reg(state, 0x21, PllCfg);
563
564 /* Remove Reset Pll */
565 PllCfg |= (1 << 13);
566 dib0090_write_reg(state, 0x21, PllCfg);
567
568 /*** Wait for PLL lock ***/
569 i = 100;
570 do {
571 v = !!(dib0090_read_reg(state, 0x1a) & 0x800);
572 if (v)
573 break;
574 } while (--i);
575
576 if (i == 0) {
577 dprintk("Pll: Unable to lock Pll");
578 return;
579 }
580
581 /* Finally Remove Bypass mode */
582 PllCfg &= ~(1 << 15);
583 dib0090_write_reg(state, 0x21, PllCfg);
584 }
585
586 if (cfg->io.pll_bypass) {
587 PllCfg |= (cfg->io.pll_bypass << 15);
588 dib0090_write_reg(state, 0x21, PllCfg);
589 }
590}
591
592static int dib0090_fw_reset_digital(struct dvb_frontend *fe, const struct dib0090_config *cfg)
593{
594 struct dib0090_fw_state *state = fe->tuner_priv;
595 u16 PllCfg;
596 u16 v;
597 int i;
598
599 dprintk("fw reset digital");
600 HARD_RESET(state);
601
602 dib0090_fw_write_reg(state, 0x24, EN_PLL | EN_CRYSTAL);
603 dib0090_fw_write_reg(state, 0x1b, EN_DIGCLK | EN_PLL | EN_CRYSTAL); /* PLL, DIG_CLK and CRYSTAL remain */
604
605 dib0090_fw_write_reg(state, 0x20,
606 ((cfg->io.adc_clock_ratio - 1) << 11) | (0 << 10) | (1 << 9) | (1 << 8) | (cfg->data_tx_drv << 4) | cfg->ls_cfg_pad_drv);
607
608 v = (0 << 15) | ((!cfg->analog_output) << 14) | (1 << 9) | (0 << 8) | (cfg->clkouttobamse << 4) | (0 << 2) | (0);
Olivier Grenie03245a52009-12-04 13:27:57 -0300609 if (cfg->clkoutdrive != 0)
Olivier Grenie28fafca2011-01-04 04:27:11 -0300610 v |= cfg->clkoutdrive << 5;
Olivier Grenie03245a52009-12-04 13:27:57 -0300611 else
Olivier Grenie28fafca2011-01-04 04:27:11 -0300612 v |= 7 << 5;
Olivier Grenie03245a52009-12-04 13:27:57 -0300613
Olivier Grenie28fafca2011-01-04 04:27:11 -0300614 v |= 2 << 10;
615 dib0090_fw_write_reg(state, 0x23, v);
Olivier Grenie03245a52009-12-04 13:27:57 -0300616
Olivier Grenie28fafca2011-01-04 04:27:11 -0300617 /* Read Pll current config * */
618 PllCfg = dib0090_fw_read_reg(state, 0x21);
619
620 /** Reconfigure PLL if current setting is different from default setting **/
621 if ((PllCfg & 0x1FFF) != ((cfg->io.pll_range << 12) | (cfg->io.pll_loopdiv << 6) | (cfg->io.pll_prediv)) && !cfg->io.pll_bypass) {
622
623 /* Set Bypass mode */
624 PllCfg |= (1 << 15);
625 dib0090_fw_write_reg(state, 0x21, PllCfg);
626
627 /* Set Reset Pll */
628 PllCfg &= ~(1 << 13);
629 dib0090_fw_write_reg(state, 0x21, PllCfg);
630
631 /*** Set new Pll configuration in bypass and reset state ***/
632 PllCfg = (1 << 15) | (0 << 13) | (cfg->io.pll_range << 12) | (cfg->io.pll_loopdiv << 6) | (cfg->io.pll_prediv);
633 dib0090_fw_write_reg(state, 0x21, PllCfg);
634
635 /* Remove Reset Pll */
636 PllCfg |= (1 << 13);
637 dib0090_fw_write_reg(state, 0x21, PllCfg);
638
639 /*** Wait for PLL lock ***/
640 i = 100;
641 do {
642 v = !!(dib0090_fw_read_reg(state, 0x1a) & 0x800);
643 if (v)
644 break;
645 } while (--i);
646
647 if (i == 0) {
648 dprintk("Pll: Unable to lock Pll");
649 return -EIO;
650 }
651
652 /* Finally Remove Bypass mode */
653 PllCfg &= ~(1 << 15);
654 dib0090_fw_write_reg(state, 0x21, PllCfg);
655 }
656
657 if (cfg->io.pll_bypass) {
658 PllCfg |= (cfg->io.pll_bypass << 15);
659 dib0090_fw_write_reg(state, 0x21, PllCfg);
660 }
661
662 return dib0090_fw_identify(fe);
Olivier Grenie03245a52009-12-04 13:27:57 -0300663}
664
665static int dib0090_wakeup(struct dvb_frontend *fe)
666{
667 struct dib0090_state *state = fe->tuner_priv;
668 if (state->config->sleep)
669 state->config->sleep(fe, 0);
Olivier Grenie28fafca2011-01-04 04:27:11 -0300670
671 /* enable dataTX in case we have been restarted in the wrong moment */
672 dib0090_write_reg(state, 0x23, dib0090_read_reg(state, 0x23) | (1 << 14));
Olivier Grenie03245a52009-12-04 13:27:57 -0300673 return 0;
674}
675
676static int dib0090_sleep(struct dvb_frontend *fe)
677{
678 struct dib0090_state *state = fe->tuner_priv;
679 if (state->config->sleep)
680 state->config->sleep(fe, 1);
681 return 0;
682}
683
Márton Németh43e3e6d2010-01-16 14:35:03 -0300684void dib0090_dcc_freq(struct dvb_frontend *fe, u8 fast)
Olivier Grenie03245a52009-12-04 13:27:57 -0300685{
686 struct dib0090_state *state = fe->tuner_priv;
687 if (fast)
Olivier Grenie9c783032009-12-07 07:49:40 -0300688 dib0090_write_reg(state, 0x04, 0);
Olivier Grenie03245a52009-12-04 13:27:57 -0300689 else
Olivier Grenie9c783032009-12-07 07:49:40 -0300690 dib0090_write_reg(state, 0x04, 1);
Olivier Grenie03245a52009-12-04 13:27:57 -0300691}
Olivier Grenie28fafca2011-01-04 04:27:11 -0300692
Olivier Grenie03245a52009-12-04 13:27:57 -0300693EXPORT_SYMBOL(dib0090_dcc_freq);
Olivier Grenie9c783032009-12-07 07:49:40 -0300694
Olivier Grenie28fafca2011-01-04 04:27:11 -0300695static const u16 bb_ramp_pwm_normal_socs[] = {
Olivier Grenieaedabf72012-12-31 10:38:44 -0300696 550, /* max BB gain in 10th of dB */
697 (1<<9) | 8, /* ramp_slope = 1dB of gain -> clock_ticks_per_db = clk_khz / ramp_slope -> BB_RAMP2 */
Olivier Grenie28fafca2011-01-04 04:27:11 -0300698 440,
Olivier Grenieaedabf72012-12-31 10:38:44 -0300699 (4 << 9) | 0, /* BB_RAMP3 = 26dB */
700 (0 << 9) | 208, /* BB_RAMP4 */
701 (4 << 9) | 208, /* BB_RAMP5 = 29dB */
702 (0 << 9) | 440, /* BB_RAMP6 */
Olivier Grenie28fafca2011-01-04 04:27:11 -0300703};
704
Olivier Grenieaedabf72012-12-31 10:38:44 -0300705static const u16 rf_ramp_pwm_cband_7090p[] = {
706 280, /* max RF gain in 10th of dB */
707 18, /* ramp_slope = 1dB of gain -> clock_ticks_per_db = clk_khz / ramp_slope -> RF_RAMP2 */
708 504, /* ramp_max = maximum X used on the ramp */
709 (29 << 10) | 364, /* RF_RAMP5, LNA 1 = 8dB */
710 (0 << 10) | 504, /* RF_RAMP6, LNA 1 */
711 (60 << 10) | 228, /* RF_RAMP7, LNA 2 = 7.7dB */
712 (0 << 10) | 364, /* RF_RAMP8, LNA 2 */
713 (34 << 10) | 109, /* GAIN_4_1, LNA 3 = 6.8dB */
714 (0 << 10) | 228, /* GAIN_4_2, LNA 3 */
715 (37 << 10) | 0, /* RF_RAMP3, LNA 4 = 6.2dB */
716 (0 << 10) | 109, /* RF_RAMP4, LNA 4 */
Olivier Grenie28fafca2011-01-04 04:27:11 -0300717};
718
Olivier Grenieaedabf72012-12-31 10:38:44 -0300719static const u16 rf_ramp_pwm_cband_7090e_sensitivity[] = {
720 186, /* max RF gain in 10th of dB */
721 40, /* ramp_slope = 1dB of gain -> clock_ticks_per_db = clk_khz / ramp_slope -> RF_RAMP2 */
722 746, /* ramp_max = maximum X used on the ramp */
723 (10 << 10) | 345, /* RF_RAMP5, LNA 1 = 10dB */
724 (0 << 10) | 746, /* RF_RAMP6, LNA 1 */
725 (0 << 10) | 0, /* RF_RAMP7, LNA 2 = 0 dB */
726 (0 << 10) | 0, /* RF_RAMP8, LNA 2 */
727 (28 << 10) | 200, /* GAIN_4_1, LNA 3 = 6.8dB */ /* 3.61 dB */
728 (0 << 10) | 345, /* GAIN_4_2, LNA 3 */
729 (20 << 10) | 0, /* RF_RAMP3, LNA 4 = 6.2dB */ /* 4.96 dB */
730 (0 << 10) | 200, /* RF_RAMP4, LNA 4 */
Olivier Grenie6724a2f2011-08-05 13:49:33 -0300731};
732
Olivier Grenieaedabf72012-12-31 10:38:44 -0300733static const u16 rf_ramp_pwm_cband_7090e_aci[] = {
734 86, /* max RF gain in 10th of dB */
735 40, /* ramp_slope = 1dB of gain -> clock_ticks_per_db = clk_khz / ramp_slope -> RF_RAMP2 */
736 345, /* ramp_max = maximum X used on the ramp */
737 (0 << 10) | 0, /* RF_RAMP5, LNA 1 = 8dB */ /* 7.47 dB */
738 (0 << 10) | 0, /* RF_RAMP6, LNA 1 */
739 (0 << 10) | 0, /* RF_RAMP7, LNA 2 = 0 dB */
740 (0 << 10) | 0, /* RF_RAMP8, LNA 2 */
741 (28 << 10) | 200, /* GAIN_4_1, LNA 3 = 6.8dB */ /* 3.61 dB */
742 (0 << 10) | 345, /* GAIN_4_2, LNA 3 */
743 (20 << 10) | 0, /* RF_RAMP3, LNA 4 = 6.2dB */ /* 4.96 dB */
744 (0 << 10) | 200, /* RF_RAMP4, LNA 4 */
Olivier Grenie6724a2f2011-08-05 13:49:33 -0300745};
746
Olivier Grenie28fafca2011-01-04 04:27:11 -0300747static const u16 rf_ramp_pwm_cband_8090[] = {
Olivier Grenieaedabf72012-12-31 10:38:44 -0300748 345, /* max RF gain in 10th of dB */
749 29, /* ramp_slope = 1dB of gain -> clock_ticks_per_db = clk_khz / ramp_slope -> RF_RAMP2 */
750 1000, /* ramp_max = maximum X used on the ramp */
751 (35 << 10) | 772, /* RF_RAMP3, LNA 1 = 8dB */
752 (0 << 10) | 1000, /* RF_RAMP4, LNA 1 */
753 (58 << 10) | 496, /* RF_RAMP5, LNA 2 = 9.5dB */
754 (0 << 10) | 772, /* RF_RAMP6, LNA 2 */
755 (27 << 10) | 200, /* RF_RAMP7, LNA 3 = 10.5dB */
756 (0 << 10) | 496, /* RF_RAMP8, LNA 3 */
757 (40 << 10) | 0, /* GAIN_4_1, LNA 4 = 7dB */
758 (0 << 10) | 200, /* GAIN_4_2, LNA 4 */
Olivier Grenie28fafca2011-01-04 04:27:11 -0300759};
760
761static const u16 rf_ramp_pwm_uhf_7090[] = {
Olivier Grenieaedabf72012-12-31 10:38:44 -0300762 407, /* max RF gain in 10th of dB */
763 13, /* ramp_slope = 1dB of gain -> clock_ticks_per_db = clk_khz / ramp_slope -> RF_RAMP2 */
764 529, /* ramp_max = maximum X used on the ramp */
765 (23 << 10) | 0, /* RF_RAMP3, LNA 1 = 14.7dB */
766 (0 << 10) | 176, /* RF_RAMP4, LNA 1 */
767 (63 << 10) | 400, /* RF_RAMP5, LNA 2 = 8dB */
768 (0 << 10) | 529, /* RF_RAMP6, LNA 2 */
769 (48 << 10) | 316, /* RF_RAMP7, LNA 3 = 6.8dB */
770 (0 << 10) | 400, /* RF_RAMP8, LNA 3 */
771 (29 << 10) | 176, /* GAIN_4_1, LNA 4 = 11.5dB */
772 (0 << 10) | 316, /* GAIN_4_2, LNA 4 */
Olivier Grenie28fafca2011-01-04 04:27:11 -0300773};
774
775static const u16 rf_ramp_pwm_uhf_8090[] = {
Olivier Grenieaedabf72012-12-31 10:38:44 -0300776 388, /* max RF gain in 10th of dB */
777 26, /* ramp_slope = 1dB of gain -> clock_ticks_per_db = clk_khz / ramp_slope -> RF_RAMP2 */
778 1008, /* ramp_max = maximum X used on the ramp */
779 (11 << 10) | 0, /* RF_RAMP3, LNA 1 = 14.7dB */
780 (0 << 10) | 369, /* RF_RAMP4, LNA 1 */
781 (41 << 10) | 809, /* RF_RAMP5, LNA 2 = 8dB */
782 (0 << 10) | 1008, /* RF_RAMP6, LNA 2 */
783 (27 << 10) | 659, /* RF_RAMP7, LNA 3 = 6dB */
784 (0 << 10) | 809, /* RF_RAMP8, LNA 3 */
785 (14 << 10) | 369, /* GAIN_4_1, LNA 4 = 11.5dB */
786 (0 << 10) | 659, /* GAIN_4_2, LNA 4 */
787};
788
789/* GENERAL PWM ramp definition for all other Krosus */
790static const u16 bb_ramp_pwm_normal[] = {
791 500, /* max BB gain in 10th of dB */
792 8, /* ramp_slope = 1dB of gain -> clock_ticks_per_db = clk_khz / ramp_slope -> BB_RAMP2 */
793 400,
794 (2 << 9) | 0, /* BB_RAMP3 = 21dB */
795 (0 << 9) | 168, /* BB_RAMP4 */
796 (2 << 9) | 168, /* BB_RAMP5 = 29dB */
797 (0 << 9) | 400, /* BB_RAMP6 */
798};
799
800static const u16 bb_ramp_pwm_boost[] = {
801 550, /* max BB gain in 10th of dB */
802 8, /* ramp_slope = 1dB of gain -> clock_ticks_per_db = clk_khz / ramp_slope -> BB_RAMP2 */
803 440,
804 (2 << 9) | 0, /* BB_RAMP3 = 26dB */
805 (0 << 9) | 208, /* BB_RAMP4 */
806 (2 << 9) | 208, /* BB_RAMP5 = 29dB */
807 (0 << 9) | 440, /* BB_RAMP6 */
Olivier Grenie28fafca2011-01-04 04:27:11 -0300808};
809
Olivier Grenie03245a52009-12-04 13:27:57 -0300810static const u16 rf_ramp_pwm_cband[] = {
Olivier Grenieaedabf72012-12-31 10:38:44 -0300811 314, /* max RF gain in 10th of dB */
812 33, /* ramp_slope = 1dB of gain -> clock_ticks_per_db = clk_khz / ramp_slope -> RF_RAMP2 */
813 1023, /* ramp_max = maximum X used on the ramp */
814 (8 << 10) | 743, /* RF_RAMP3, LNA 1 = 0dB */
815 (0 << 10) | 1023, /* RF_RAMP4, LNA 1 */
816 (15 << 10) | 469, /* RF_RAMP5, LNA 2 = 0dB */
817 (0 << 10) | 742, /* RF_RAMP6, LNA 2 */
818 (9 << 10) | 234, /* RF_RAMP7, LNA 3 = 0dB */
819 (0 << 10) | 468, /* RF_RAMP8, LNA 3 */
820 (9 << 10) | 0, /* GAIN_4_1, LNA 4 = 0dB */
821 (0 << 10) | 233, /* GAIN_4_2, LNA 4 */
Olivier Grenie03245a52009-12-04 13:27:57 -0300822};
823
824static const u16 rf_ramp_pwm_vhf[] = {
Olivier Grenieaedabf72012-12-31 10:38:44 -0300825 398, /* max RF gain in 10th of dB */
826 24, /* ramp_slope = 1dB of gain -> clock_ticks_per_db = clk_khz / ramp_slope -> RF_RAMP2 */
827 954, /* ramp_max = maximum X used on the ramp */
828 (7 << 10) | 0, /* RF_RAMP3, LNA 1 = 13.2dB */
829 (0 << 10) | 290, /* RF_RAMP4, LNA 1 */
830 (16 << 10) | 699, /* RF_RAMP5, LNA 2 = 10.5dB */
831 (0 << 10) | 954, /* RF_RAMP6, LNA 2 */
832 (17 << 10) | 580, /* RF_RAMP7, LNA 3 = 5dB */
833 (0 << 10) | 699, /* RF_RAMP8, LNA 3 */
834 (7 << 10) | 290, /* GAIN_4_1, LNA 4 = 12.5dB */
835 (0 << 10) | 580, /* GAIN_4_2, LNA 4 */
Olivier Grenie03245a52009-12-04 13:27:57 -0300836};
837
838static const u16 rf_ramp_pwm_uhf[] = {
Olivier Grenieaedabf72012-12-31 10:38:44 -0300839 398, /* max RF gain in 10th of dB */
840 24, /* ramp_slope = 1dB of gain -> clock_ticks_per_db = clk_khz / ramp_slope -> RF_RAMP2 */
841 954, /* ramp_max = maximum X used on the ramp */
842 (7 << 10) | 0, /* RF_RAMP3, LNA 1 = 13.2dB */
843 (0 << 10) | 290, /* RF_RAMP4, LNA 1 */
844 (16 << 10) | 699, /* RF_RAMP5, LNA 2 = 10.5dB */
845 (0 << 10) | 954, /* RF_RAMP6, LNA 2 */
846 (17 << 10) | 580, /* RF_RAMP7, LNA 3 = 5dB */
847 (0 << 10) | 699, /* RF_RAMP8, LNA 3 */
848 (7 << 10) | 290, /* GAIN_4_1, LNA 4 = 12.5dB */
849 (0 << 10) | 580, /* GAIN_4_2, LNA 4 */
Olivier Grenie03245a52009-12-04 13:27:57 -0300850};
851
Olivier Grenieaedabf72012-12-31 10:38:44 -0300852static const u16 rf_ramp_pwm_sband[] = {
853 253, /* max RF gain in 10th of dB */
854 38, /* ramp_slope = 1dB of gain -> clock_ticks_per_db = clk_khz / ramp_slope -> RF_RAMP2 */
855 961,
856 (4 << 10) | 0, /* RF_RAMP3, LNA 1 = 14.1dB */
857 (0 << 10) | 508, /* RF_RAMP4, LNA 1 */
858 (9 << 10) | 508, /* RF_RAMP5, LNA 2 = 11.2dB */
859 (0 << 10) | 961, /* RF_RAMP6, LNA 2 */
860 (0 << 10) | 0, /* RF_RAMP7, LNA 3 = 0dB */
861 (0 << 10) | 0, /* RF_RAMP8, LNA 3 */
862 (0 << 10) | 0, /* GAIN_4_1, LNA 4 = 0dB */
863 (0 << 10) | 0, /* GAIN_4_2, LNA 4 */
Olivier Grenie03245a52009-12-04 13:27:57 -0300864};
865
866struct slope {
Olivier Grenie28fafca2011-01-04 04:27:11 -0300867 s16 range;
868 s16 slope;
Olivier Grenie03245a52009-12-04 13:27:57 -0300869};
870static u16 slopes_to_scale(const struct slope *slopes, u8 num, s16 val)
871{
872 u8 i;
873 u16 rest;
874 u16 ret = 0;
875 for (i = 0; i < num; i++) {
876 if (val > slopes[i].range)
877 rest = slopes[i].range;
878 else
879 rest = val;
880 ret += (rest * slopes[i].slope) / slopes[i].range;
881 val -= rest;
882 }
883 return ret;
884}
885
886static const struct slope dib0090_wbd_slopes[3] = {
887 {66, 120}, /* -64,-52: offset - 65 */
888 {600, 170}, /* -52,-35: 65 - 665 */
889 {170, 250}, /* -45,-10: 665 - 835 */
890};
891
892static s16 dib0090_wbd_to_db(struct dib0090_state *state, u16 wbd)
893{
894 wbd &= 0x3ff;
895 if (wbd < state->wbd_offset)
896 wbd = 0;
897 else
898 wbd -= state->wbd_offset;
899 /* -64dB is the floor */
900 return -640 + (s16) slopes_to_scale(dib0090_wbd_slopes, ARRAY_SIZE(dib0090_wbd_slopes), wbd);
901}
902
903static void dib0090_wbd_target(struct dib0090_state *state, u32 rf)
904{
905 u16 offset = 250;
906
907 /* TODO : DAB digital N+/-1 interferer perfs : offset = 10 */
908
909 if (state->current_band == BAND_VHF)
910 offset = 650;
911#ifndef FIRMWARE_FIREFLY
912 if (state->current_band == BAND_VHF)
913 offset = state->config->wbd_vhf_offset;
914 if (state->current_band == BAND_CBAND)
915 offset = state->config->wbd_cband_offset;
916#endif
917
918 state->wbd_target = dib0090_wbd_to_db(state, state->wbd_offset + offset);
919 dprintk("wbd-target: %d dB", (u32) state->wbd_target);
920}
921
922static const int gain_reg_addr[4] = {
923 0x08, 0x0a, 0x0f, 0x01
924};
925
926static void dib0090_gain_apply(struct dib0090_state *state, s16 gain_delta, s16 top_delta, u8 force)
927{
928 u16 rf, bb, ref;
929 u16 i, v, gain_reg[4] = { 0 }, gain;
930 const u16 *g;
931
932 if (top_delta < -511)
933 top_delta = -511;
934 if (top_delta > 511)
935 top_delta = 511;
936
937 if (force) {
938 top_delta *= (1 << WBD_ALPHA);
939 gain_delta *= (1 << GAIN_ALPHA);
940 }
941
942 if (top_delta >= ((s16) (state->rf_ramp[0] << WBD_ALPHA) - state->rf_gain_limit)) /* overflow */
943 state->rf_gain_limit = state->rf_ramp[0] << WBD_ALPHA;
944 else
945 state->rf_gain_limit += top_delta;
946
947 if (state->rf_gain_limit < 0) /*underflow */
948 state->rf_gain_limit = 0;
949
950 /* use gain as a temporary variable and correct current_gain */
951 gain = ((state->rf_gain_limit >> WBD_ALPHA) + state->bb_ramp[0]) << GAIN_ALPHA;
952 if (gain_delta >= ((s16) gain - state->current_gain)) /* overflow */
953 state->current_gain = gain;
954 else
955 state->current_gain += gain_delta;
956 /* cannot be less than 0 (only if gain_delta is less than 0 we can have current_gain < 0) */
957 if (state->current_gain < 0)
958 state->current_gain = 0;
959
960 /* now split total gain to rf and bb gain */
961 gain = state->current_gain >> GAIN_ALPHA;
962
963 /* requested gain is bigger than rf gain limit - ACI/WBD adjustment */
964 if (gain > (state->rf_gain_limit >> WBD_ALPHA)) {
965 rf = state->rf_gain_limit >> WBD_ALPHA;
966 bb = gain - rf;
967 if (bb > state->bb_ramp[0])
968 bb = state->bb_ramp[0];
969 } else { /* high signal level -> all gains put on RF */
970 rf = gain;
971 bb = 0;
972 }
973
974 state->gain[0] = rf;
975 state->gain[1] = bb;
976
977 /* software ramp */
978 /* Start with RF gains */
979 g = state->rf_ramp + 1; /* point on RF LNA1 max gain */
980 ref = rf;
981 for (i = 0; i < 7; i++) { /* Go over all amplifiers => 5RF amps + 2 BB amps = 7 amps */
982 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 */
983 v = 0; /* force the gain to write for the current amp to be null */
984 else if (ref >= g[1]) /* Gain to set is higher than the high working point of this amp */
985 v = g[2]; /* force this amp to be full gain */
986 else /* compute the value to set to this amp because we are somewhere in his range */
987 v = ((ref - (g[1] - g[0])) * g[2]) / g[0];
988
989 if (i == 0) /* LNA 1 reg mapping */
990 gain_reg[0] = v;
991 else if (i == 1) /* LNA 2 reg mapping */
992 gain_reg[0] |= v << 7;
993 else if (i == 2) /* LNA 3 reg mapping */
994 gain_reg[1] = v;
995 else if (i == 3) /* LNA 4 reg mapping */
996 gain_reg[1] |= v << 7;
997 else if (i == 4) /* CBAND LNA reg mapping */
998 gain_reg[2] = v | state->rf_lt_def;
999 else if (i == 5) /* BB gain 1 reg mapping */
1000 gain_reg[3] = v << 3;
1001 else if (i == 6) /* BB gain 2 reg mapping */
1002 gain_reg[3] |= v << 8;
1003
1004 g += 3; /* go to next gain bloc */
1005
1006 /* When RF is finished, start with BB */
1007 if (i == 4) {
1008 g = state->bb_ramp + 1; /* point on BB gain 1 max gain */
1009 ref = bb;
1010 }
1011 }
1012 gain_reg[3] |= state->bb_1_def;
1013 gain_reg[3] |= ((bb % 10) * 100) / 125;
1014
1015#ifdef DEBUG_AGC
1016 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,
1017 gain_reg[0], gain_reg[1], gain_reg[2], gain_reg[3]);
1018#endif
1019
1020 /* Write the amplifier regs */
1021 for (i = 0; i < 4; i++) {
1022 v = gain_reg[i];
1023 if (force || state->gain_reg[i] != v) {
1024 state->gain_reg[i] = v;
1025 dib0090_write_reg(state, gain_reg_addr[i], v);
1026 }
1027 }
1028}
1029
1030static void dib0090_set_boost(struct dib0090_state *state, int onoff)
1031{
1032 state->bb_1_def &= 0xdfff;
1033 state->bb_1_def |= onoff << 13;
1034}
1035
1036static void dib0090_set_rframp(struct dib0090_state *state, const u16 * cfg)
1037{
1038 state->rf_ramp = cfg;
1039}
1040
1041static void dib0090_set_rframp_pwm(struct dib0090_state *state, const u16 * cfg)
1042{
1043 state->rf_ramp = cfg;
1044
1045 dib0090_write_reg(state, 0x2a, 0xffff);
1046
1047 dprintk("total RF gain: %ddB, step: %d", (u32) cfg[0], dib0090_read_reg(state, 0x2a));
1048
1049 dib0090_write_regs(state, 0x2c, cfg + 3, 6);
1050 dib0090_write_regs(state, 0x3e, cfg + 9, 2);
1051}
1052
1053static void dib0090_set_bbramp(struct dib0090_state *state, const u16 * cfg)
1054{
1055 state->bb_ramp = cfg;
1056 dib0090_set_boost(state, cfg[0] > 500); /* we want the boost if the gain is higher that 50dB */
1057}
1058
1059static void dib0090_set_bbramp_pwm(struct dib0090_state *state, const u16 * cfg)
1060{
1061 state->bb_ramp = cfg;
1062
1063 dib0090_set_boost(state, cfg[0] > 500); /* we want the boost if the gain is higher that 50dB */
1064
1065 dib0090_write_reg(state, 0x33, 0xffff);
1066 dprintk("total BB gain: %ddB, step: %d", (u32) cfg[0], dib0090_read_reg(state, 0x33));
1067 dib0090_write_regs(state, 0x35, cfg + 3, 4);
1068}
1069
1070void dib0090_pwm_gain_reset(struct dvb_frontend *fe)
1071{
1072 struct dib0090_state *state = fe->tuner_priv;
Olivier Grenieaedabf72012-12-31 10:38:44 -03001073 u16 *bb_ramp = (u16 *)&bb_ramp_pwm_normal; /* default baseband config */
1074 u16 *rf_ramp = NULL;
1075 u8 en_pwm_rf_mux = 1;
Olivier Grenie03245a52009-12-04 13:27:57 -03001076
Olivier Grenieaedabf72012-12-31 10:38:44 -03001077 /* reset the AGC */
Olivier Grenie03245a52009-12-04 13:27:57 -03001078 if (state->config->use_pwm_agc) {
Olivier Grenie03245a52009-12-04 13:27:57 -03001079 if (state->current_band == BAND_CBAND) {
Olivier Grenie28fafca2011-01-04 04:27:11 -03001080 if (state->identity.in_soc) {
Olivier Grenieaedabf72012-12-31 10:38:44 -03001081 bb_ramp = (u16 *)&bb_ramp_pwm_normal_socs;
Olivier Grenie28fafca2011-01-04 04:27:11 -03001082 if (state->identity.version == SOC_8090_P1G_11R1 || state->identity.version == SOC_8090_P1G_21R1)
Olivier Grenieaedabf72012-12-31 10:38:44 -03001083 rf_ramp = (u16 *)&rf_ramp_pwm_cband_8090;
1084 else if (state->identity.version == SOC_7090_P1G_11R1 || state->identity.version == SOC_7090_P1G_21R1) {
Olivier Grenie6724a2f2011-08-05 13:49:33 -03001085 if (state->config->is_dib7090e) {
1086 if (state->rf_ramp == NULL)
Olivier Grenieaedabf72012-12-31 10:38:44 -03001087 rf_ramp = (u16 *)&rf_ramp_pwm_cband_7090e_sensitivity;
Olivier Grenie6724a2f2011-08-05 13:49:33 -03001088 else
Olivier Grenieaedabf72012-12-31 10:38:44 -03001089 rf_ramp = (u16 *)state->rf_ramp;
Olivier Grenie6724a2f2011-08-05 13:49:33 -03001090 } else
Olivier Grenieaedabf72012-12-31 10:38:44 -03001091 rf_ramp = (u16 *)&rf_ramp_pwm_cband_7090p;
Olivier Grenie6724a2f2011-08-05 13:49:33 -03001092 }
Olivier Grenieaedabf72012-12-31 10:38:44 -03001093 } else
1094 rf_ramp = (u16 *)&rf_ramp_pwm_cband;
Olivier Grenie03245a52009-12-04 13:27:57 -03001095 } else
Olivier Grenie03245a52009-12-04 13:27:57 -03001096
Olivier Grenieaedabf72012-12-31 10:38:44 -03001097 if (state->current_band == BAND_VHF) {
1098 if (state->identity.in_soc) {
1099 bb_ramp = (u16 *)&bb_ramp_pwm_normal_socs;
1100 /* rf_ramp = &rf_ramp_pwm_vhf_socs; */ /* TODO */
1101 } else
1102 rf_ramp = (u16 *)&rf_ramp_pwm_vhf;
1103 } else if (state->current_band == BAND_UHF) {
1104 if (state->identity.in_soc) {
1105 bb_ramp = (u16 *)&bb_ramp_pwm_normal_socs;
1106 if (state->identity.version == SOC_8090_P1G_11R1 || state->identity.version == SOC_8090_P1G_21R1)
1107 rf_ramp = (u16 *)&rf_ramp_pwm_uhf_8090;
1108 else if (state->identity.version == SOC_7090_P1G_11R1 || state->identity.version == SOC_7090_P1G_21R1)
1109 rf_ramp = (u16 *)&rf_ramp_pwm_uhf_7090;
1110 } else
1111 rf_ramp = (u16 *)&rf_ramp_pwm_uhf;
1112 }
1113 if (rf_ramp)
1114 dib0090_set_rframp_pwm(state, rf_ramp);
1115 dib0090_set_bbramp_pwm(state, bb_ramp);
1116
1117 /* activate the ramp generator using PWM control */
Mauro Carvalho Chehab57bcbde2016-02-27 07:51:09 -03001118 if (state->rf_ramp)
Mauro Carvalho Chehabe76bea92016-02-22 11:12:41 -03001119 dprintk("ramp RF gain = %d BAND = %s version = %d",
1120 state->rf_ramp[0],
1121 (state->current_band == BAND_CBAND) ? "CBAND" : "NOT CBAND",
1122 state->identity.version & 0x1f);
Olivier Grenieaedabf72012-12-31 10:38:44 -03001123
Hans Verkuil5848adb2016-04-15 12:35:33 -03001124 if (rf_ramp && ((state->rf_ramp && state->rf_ramp[0] == 0) ||
Mauro Carvalho Chehabe76bea92016-02-22 11:12:41 -03001125 (state->current_band == BAND_CBAND &&
1126 (state->identity.version & 0x1f) <= P1D_E_F))) {
Olivier Grenieaedabf72012-12-31 10:38:44 -03001127 dprintk("DE-Engage mux for direct gain reg control");
1128 en_pwm_rf_mux = 0;
1129 } else
1130 dprintk("Engage mux for PWM control");
1131
1132 dib0090_write_reg(state, 0x32, (en_pwm_rf_mux << 12) | (en_pwm_rf_mux << 11));
1133
1134 /* Set fast servo cutoff to start AGC; 0 = 1KHz ; 1 = 50Hz ; 2 = 150Hz ; 3 = 50KHz ; 4 = servo fast*/
1135 if (state->identity.version == SOC_7090_P1G_11R1 || state->identity.version == SOC_7090_P1G_21R1)
1136 dib0090_write_reg(state, 0x04, 3);
Olivier Grenie03245a52009-12-04 13:27:57 -03001137 else
Olivier Grenieaedabf72012-12-31 10:38:44 -03001138 dib0090_write_reg(state, 0x04, 1);
1139 dib0090_write_reg(state, 0x39, (1 << 10)); /* 0 gain by default */
Olivier Grenie03245a52009-12-04 13:27:57 -03001140 }
1141}
Olivier Grenie03245a52009-12-04 13:27:57 -03001142EXPORT_SYMBOL(dib0090_pwm_gain_reset);
Olivier Grenie9c783032009-12-07 07:49:40 -03001143
Olivier Grenie2e802862011-08-05 10:39:15 -03001144void dib0090_set_dc_servo(struct dvb_frontend *fe, u8 DC_servo_cutoff)
1145{
1146 struct dib0090_state *state = fe->tuner_priv;
1147 if (DC_servo_cutoff < 4)
1148 dib0090_write_reg(state, 0x04, DC_servo_cutoff);
1149}
1150EXPORT_SYMBOL(dib0090_set_dc_servo);
1151
Olivier Grenie28fafca2011-01-04 04:27:11 -03001152static u32 dib0090_get_slow_adc_val(struct dib0090_state *state)
1153{
1154 u16 adc_val = dib0090_read_reg(state, 0x1d);
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001155 if (state->identity.in_soc)
Olivier Grenie28fafca2011-01-04 04:27:11 -03001156 adc_val >>= 2;
Olivier Grenie28fafca2011-01-04 04:27:11 -03001157 return adc_val;
1158}
1159
Olivier Grenie03245a52009-12-04 13:27:57 -03001160int dib0090_gain_control(struct dvb_frontend *fe)
1161{
1162 struct dib0090_state *state = fe->tuner_priv;
1163 enum frontend_tune_state *tune_state = &state->tune_state;
1164 int ret = 10;
1165
1166 u16 wbd_val = 0;
1167 u8 apply_gain_immediatly = 1;
1168 s16 wbd_error = 0, adc_error = 0;
1169
1170 if (*tune_state == CT_AGC_START) {
1171 state->agc_freeze = 0;
1172 dib0090_write_reg(state, 0x04, 0x0);
1173
1174#ifdef CONFIG_BAND_SBAND
1175 if (state->current_band == BAND_SBAND) {
1176 dib0090_set_rframp(state, rf_ramp_sband);
1177 dib0090_set_bbramp(state, bb_ramp_boost);
1178 } else
1179#endif
1180#ifdef CONFIG_BAND_VHF
Olivier Grenie28fafca2011-01-04 04:27:11 -03001181 if (state->current_band == BAND_VHF && !state->identity.p1g) {
Olivier Grenieaedabf72012-12-31 10:38:44 -03001182 dib0090_set_rframp(state, rf_ramp_pwm_vhf);
1183 dib0090_set_bbramp(state, bb_ramp_pwm_normal);
Olivier Grenie03245a52009-12-04 13:27:57 -03001184 } else
1185#endif
1186#ifdef CONFIG_BAND_CBAND
Olivier Grenie28fafca2011-01-04 04:27:11 -03001187 if (state->current_band == BAND_CBAND && !state->identity.p1g) {
Olivier Grenieaedabf72012-12-31 10:38:44 -03001188 dib0090_set_rframp(state, rf_ramp_pwm_cband);
1189 dib0090_set_bbramp(state, bb_ramp_pwm_normal);
Olivier Grenie03245a52009-12-04 13:27:57 -03001190 } else
1191#endif
Olivier Grenie28fafca2011-01-04 04:27:11 -03001192 if ((state->current_band == BAND_CBAND || state->current_band == BAND_VHF) && state->identity.p1g) {
Olivier Grenieaedabf72012-12-31 10:38:44 -03001193 dib0090_set_rframp(state, rf_ramp_pwm_cband_7090p);
1194 dib0090_set_bbramp(state, bb_ramp_pwm_normal_socs);
Olivier Grenie28fafca2011-01-04 04:27:11 -03001195 } else {
Olivier Grenieaedabf72012-12-31 10:38:44 -03001196 dib0090_set_rframp(state, rf_ramp_pwm_uhf);
1197 dib0090_set_bbramp(state, bb_ramp_pwm_normal);
Olivier Grenie03245a52009-12-04 13:27:57 -03001198 }
1199
1200 dib0090_write_reg(state, 0x32, 0);
1201 dib0090_write_reg(state, 0x39, 0);
1202
1203 dib0090_wbd_target(state, state->current_rf);
1204
1205 state->rf_gain_limit = state->rf_ramp[0] << WBD_ALPHA;
1206 state->current_gain = ((state->rf_ramp[0] + state->bb_ramp[0]) / 2) << GAIN_ALPHA;
1207
1208 *tune_state = CT_AGC_STEP_0;
1209 } else if (!state->agc_freeze) {
Olivier Grenie28fafca2011-01-04 04:27:11 -03001210 s16 wbd = 0, i, cnt;
Olivier Grenie03245a52009-12-04 13:27:57 -03001211
1212 int adc;
Olivier Grenie28fafca2011-01-04 04:27:11 -03001213 wbd_val = dib0090_get_slow_adc_val(state);
Olivier Grenie03245a52009-12-04 13:27:57 -03001214
Olivier Grenie28fafca2011-01-04 04:27:11 -03001215 if (*tune_state == CT_AGC_STEP_0)
1216 cnt = 5;
1217 else
1218 cnt = 1;
1219
1220 for (i = 0; i < cnt; i++) {
1221 wbd_val = dib0090_get_slow_adc_val(state);
1222 wbd += dib0090_wbd_to_db(state, wbd_val);
1223 }
1224 wbd /= cnt;
Olivier Grenie03245a52009-12-04 13:27:57 -03001225 wbd_error = state->wbd_target - wbd;
1226
1227 if (*tune_state == CT_AGC_STEP_0) {
Olivier Grenie28fafca2011-01-04 04:27:11 -03001228 if (wbd_error < 0 && state->rf_gain_limit > 0 && !state->identity.p1g) {
Olivier Grenie03245a52009-12-04 13:27:57 -03001229#ifdef CONFIG_BAND_CBAND
1230 /* in case of CBAND tune reduce first the lt_gain2 before adjusting the RF gain */
1231 u8 ltg2 = (state->rf_lt_def >> 10) & 0x7;
1232 if (state->current_band == BAND_CBAND && ltg2) {
1233 ltg2 >>= 1;
1234 state->rf_lt_def &= ltg2 << 10; /* reduce in 3 steps from 7 to 0 */
1235 }
1236#endif
1237 } else {
1238 state->agc_step = 0;
1239 *tune_state = CT_AGC_STEP_1;
1240 }
1241 } else {
1242 /* calc the adc power */
1243 adc = state->config->get_adc_power(fe);
1244 adc = (adc * ((s32) 355774) + (((s32) 1) << 20)) >> 21; /* included in [0:-700] */
1245
1246 adc_error = (s16) (((s32) ADC_TARGET) - adc);
1247#ifdef CONFIG_STANDARD_DAB
1248 if (state->fe->dtv_property_cache.delivery_system == STANDARD_DAB)
Olivier Grenie28fafca2011-01-04 04:27:11 -03001249 adc_error -= 10;
Olivier Grenie03245a52009-12-04 13:27:57 -03001250#endif
1251#ifdef CONFIG_STANDARD_DVBT
1252 if (state->fe->dtv_property_cache.delivery_system == STANDARD_DVBT &&
Olivier Grenie28fafca2011-01-04 04:27:11 -03001253 (state->fe->dtv_property_cache.modulation == QAM_64 || state->fe->dtv_property_cache.modulation == QAM_16))
Olivier Grenie03245a52009-12-04 13:27:57 -03001254 adc_error += 60;
1255#endif
1256#ifdef CONFIG_SYS_ISDBT
1257 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 -03001258 0)
1259 &&
1260 ((state->fe->dtv_property_cache.layer[0].modulation ==
1261 QAM_64)
1262 || (state->fe->dtv_property_cache.
1263 layer[0].modulation == QAM_16)))
1264 ||
1265 ((state->fe->dtv_property_cache.layer[1].segment_count >
1266 0)
1267 &&
1268 ((state->fe->dtv_property_cache.layer[1].modulation ==
1269 QAM_64)
1270 || (state->fe->dtv_property_cache.
1271 layer[1].modulation == QAM_16)))
1272 ||
1273 ((state->fe->dtv_property_cache.layer[2].segment_count >
1274 0)
1275 &&
1276 ((state->fe->dtv_property_cache.layer[2].modulation ==
1277 QAM_64)
1278 || (state->fe->dtv_property_cache.
1279 layer[2].modulation == QAM_16)))
1280 )
1281 )
Olivier Grenie03245a52009-12-04 13:27:57 -03001282 adc_error += 60;
1283#endif
1284
1285 if (*tune_state == CT_AGC_STEP_1) { /* quickly go to the correct range of the ADC power */
1286 if (ABS(adc_error) < 50 || state->agc_step++ > 5) {
1287
1288#ifdef CONFIG_STANDARD_DAB
1289 if (state->fe->dtv_property_cache.delivery_system == STANDARD_DAB) {
1290 dib0090_write_reg(state, 0x02, (1 << 15) | (15 << 11) | (31 << 6) | (63)); /* cap value = 63 : narrow BB filter : Fc = 1.8MHz */
1291 dib0090_write_reg(state, 0x04, 0x0);
1292 } else
1293#endif
1294 {
1295 dib0090_write_reg(state, 0x02, (1 << 15) | (3 << 11) | (6 << 6) | (32));
1296 dib0090_write_reg(state, 0x04, 0x01); /*0 = 1KHz ; 1 = 150Hz ; 2 = 50Hz ; 3 = 50KHz ; 4 = servo fast */
1297 }
1298
1299 *tune_state = CT_AGC_STOP;
1300 }
1301 } else {
1302 /* everything higher than or equal to CT_AGC_STOP means tracking */
1303 ret = 100; /* 10ms interval */
1304 apply_gain_immediatly = 0;
1305 }
1306 }
1307#ifdef DEBUG_AGC
1308 dprintk
Olivier Grenie28fafca2011-01-04 04:27:11 -03001309 ("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 -03001310 (u32) *tune_state, (u32) adc, (u32) adc_error, (u32) wbd, (u32) wbd_error, (u32) wbd_val,
Olivier Grenie28fafca2011-01-04 04:27:11 -03001311 (u32) state->rf_gain_limit >> WBD_ALPHA, (s32) 200 + adc - (state->current_gain >> GAIN_ALPHA));
Olivier Grenie03245a52009-12-04 13:27:57 -03001312#endif
1313 }
1314
1315 /* apply gain */
1316 if (!state->agc_freeze)
1317 dib0090_gain_apply(state, adc_error, wbd_error, apply_gain_immediatly);
1318 return ret;
1319}
Olivier Grenie28fafca2011-01-04 04:27:11 -03001320
Olivier Grenie03245a52009-12-04 13:27:57 -03001321EXPORT_SYMBOL(dib0090_gain_control);
Olivier Grenie9c783032009-12-07 07:49:40 -03001322
Olivier Grenie03245a52009-12-04 13:27:57 -03001323void dib0090_get_current_gain(struct dvb_frontend *fe, u16 * rf, u16 * bb, u16 * rf_gain_limit, u16 * rflt)
1324{
1325 struct dib0090_state *state = fe->tuner_priv;
1326 if (rf)
1327 *rf = state->gain[0];
1328 if (bb)
1329 *bb = state->gain[1];
1330 if (rf_gain_limit)
1331 *rf_gain_limit = state->rf_gain_limit;
1332 if (rflt)
1333 *rflt = (state->rf_lt_def >> 10) & 0x7;
1334}
Olivier Grenie28fafca2011-01-04 04:27:11 -03001335
Olivier Grenie03245a52009-12-04 13:27:57 -03001336EXPORT_SYMBOL(dib0090_get_current_gain);
Olivier Grenie9c783032009-12-07 07:49:40 -03001337
Olivier Grenie6724a2f2011-08-05 13:49:33 -03001338u16 dib0090_get_wbd_target(struct dvb_frontend *fe)
Olivier Grenie03245a52009-12-04 13:27:57 -03001339{
Olivier Grenie28fafca2011-01-04 04:27:11 -03001340 struct dib0090_state *state = fe->tuner_priv;
1341 u32 f_MHz = state->fe->dtv_property_cache.frequency / 1000000;
1342 s32 current_temp = state->temperature;
1343 s32 wbd_thot, wbd_tcold;
1344 const struct dib0090_wbd_slope *wbd = state->current_wbd_table;
1345
1346 while (f_MHz > wbd->max_freq)
1347 wbd++;
1348
1349 dprintk("using wbd-table-entry with max freq %d", wbd->max_freq);
1350
1351 if (current_temp < 0)
1352 current_temp = 0;
1353 if (current_temp > 128)
1354 current_temp = 128;
1355
Olivier Grenie28fafca2011-01-04 04:27:11 -03001356 state->wbdmux &= ~(7 << 13);
1357 if (wbd->wbd_gain != 0)
1358 state->wbdmux |= (wbd->wbd_gain << 13);
1359 else
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001360 state->wbdmux |= (4 << 13);
Olivier Grenie28fafca2011-01-04 04:27:11 -03001361
1362 dib0090_write_reg(state, 0x10, state->wbdmux);
1363
Olivier Grenie28fafca2011-01-04 04:27:11 -03001364 wbd_thot = wbd->offset_hot - (((u32) wbd->slope_hot * f_MHz) >> 6);
1365 wbd_tcold = wbd->offset_cold - (((u32) wbd->slope_cold * f_MHz) >> 6);
1366
Olivier Grenie28fafca2011-01-04 04:27:11 -03001367 wbd_tcold += ((wbd_thot - wbd_tcold) * current_temp) >> 7;
1368
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001369 state->wbd_target = dib0090_wbd_to_db(state, state->wbd_offset + wbd_tcold);
Olivier Grenie28fafca2011-01-04 04:27:11 -03001370 dprintk("wbd-target: %d dB", (u32) state->wbd_target);
1371 dprintk("wbd offset applied is %d", wbd_tcold);
1372
1373 return state->wbd_offset + wbd_tcold;
Olivier Grenie03245a52009-12-04 13:27:57 -03001374}
Olivier Grenie6724a2f2011-08-05 13:49:33 -03001375EXPORT_SYMBOL(dib0090_get_wbd_target);
Olivier Grenie28fafca2011-01-04 04:27:11 -03001376
Olivier Grenie6724a2f2011-08-05 13:49:33 -03001377u16 dib0090_get_wbd_offset(struct dvb_frontend *fe)
1378{
1379 struct dib0090_state *state = fe->tuner_priv;
1380 return state->wbd_offset;
1381}
Olivier Grenie03245a52009-12-04 13:27:57 -03001382EXPORT_SYMBOL(dib0090_get_wbd_offset);
Olivier Grenie9c783032009-12-07 07:49:40 -03001383
Olivier Grenie6724a2f2011-08-05 13:49:33 -03001384int dib0090_set_switch(struct dvb_frontend *fe, u8 sw1, u8 sw2, u8 sw3)
1385{
1386 struct dib0090_state *state = fe->tuner_priv;
1387
1388 dib0090_write_reg(state, 0x0b, (dib0090_read_reg(state, 0x0b) & 0xfff8)
1389 | ((sw3 & 1) << 2) | ((sw2 & 1) << 1) | (sw1 & 1));
1390
1391 return 0;
1392}
1393EXPORT_SYMBOL(dib0090_set_switch);
1394
1395int dib0090_set_vga(struct dvb_frontend *fe, u8 onoff)
1396{
1397 struct dib0090_state *state = fe->tuner_priv;
1398
1399 dib0090_write_reg(state, 0x09, (dib0090_read_reg(state, 0x09) & 0x7fff)
1400 | ((onoff & 1) << 15));
1401 return 0;
1402}
1403EXPORT_SYMBOL(dib0090_set_vga);
1404
1405int dib0090_update_rframp_7090(struct dvb_frontend *fe, u8 cfg_sensitivity)
1406{
1407 struct dib0090_state *state = fe->tuner_priv;
1408
1409 if ((!state->identity.p1g) || (!state->identity.in_soc)
1410 || ((state->identity.version != SOC_7090_P1G_21R1)
1411 && (state->identity.version != SOC_7090_P1G_11R1))) {
1412 dprintk("%s() function can only be used for dib7090P", __func__);
1413 return -ENODEV;
1414 }
1415
1416 if (cfg_sensitivity)
1417 state->rf_ramp = (const u16 *)&rf_ramp_pwm_cband_7090e_sensitivity;
1418 else
1419 state->rf_ramp = (const u16 *)&rf_ramp_pwm_cband_7090e_aci;
1420 dib0090_pwm_gain_reset(fe);
1421
1422 return 0;
1423}
1424EXPORT_SYMBOL(dib0090_update_rframp_7090);
1425
Olivier Grenie03245a52009-12-04 13:27:57 -03001426static const u16 dib0090_defaults[] = {
1427
1428 25, 0x01,
1429 0x0000,
1430 0x99a0,
1431 0x6008,
1432 0x0000,
Olivier Grenie28fafca2011-01-04 04:27:11 -03001433 0x8bcb,
Olivier Grenie03245a52009-12-04 13:27:57 -03001434 0x0000,
1435 0x0405,
1436 0x0000,
1437 0x0000,
1438 0x0000,
1439 0xb802,
1440 0x0300,
1441 0x2d12,
1442 0xbac0,
1443 0x7c00,
1444 0xdbb9,
1445 0x0954,
1446 0x0743,
1447 0x8000,
1448 0x0001,
1449 0x0040,
1450 0x0100,
1451 0x0000,
1452 0xe910,
1453 0x149e,
1454
1455 1, 0x1c,
1456 0xff2d,
1457
1458 1, 0x39,
1459 0x0000,
1460
Olivier Grenie03245a52009-12-04 13:27:57 -03001461 2, 0x1e,
1462 0x07FF,
1463 0x0007,
1464
1465 1, 0x24,
1466 EN_UHF | EN_CRYSTAL,
1467
1468 2, 0x3c,
1469 0x3ff,
1470 0x111,
1471 0
1472};
1473
Olivier Grenie28fafca2011-01-04 04:27:11 -03001474static const u16 dib0090_p1g_additionnal_defaults[] = {
Olivier Grenie28fafca2011-01-04 04:27:11 -03001475 1, 0x05,
1476 0xabcd,
1477
1478 1, 0x11,
1479 0x00b4,
1480
1481 1, 0x1c,
1482 0xfffd,
1483
1484 1, 0x40,
1485 0x108,
1486 0
1487};
1488
1489static void dib0090_set_default_config(struct dib0090_state *state, const u16 * n)
Olivier Grenie03245a52009-12-04 13:27:57 -03001490{
Olivier Grenie28fafca2011-01-04 04:27:11 -03001491 u16 l, r;
Olivier Grenie03245a52009-12-04 13:27:57 -03001492
Olivier Grenie03245a52009-12-04 13:27:57 -03001493 l = pgm_read_word(n++);
1494 while (l) {
1495 r = pgm_read_word(n++);
1496 do {
Olivier Grenie03245a52009-12-04 13:27:57 -03001497 dib0090_write_reg(state, r, pgm_read_word(n++));
1498 r++;
1499 } while (--l);
1500 l = pgm_read_word(n++);
1501 }
Olivier Grenie28fafca2011-01-04 04:27:11 -03001502}
1503
1504#define CAP_VALUE_MIN (u8) 9
1505#define CAP_VALUE_MAX (u8) 40
1506#define HR_MIN (u8) 25
1507#define HR_MAX (u8) 40
1508#define POLY_MIN (u8) 0
1509#define POLY_MAX (u8) 8
1510
Olivier Greniea685dbb2011-08-05 14:10:40 -03001511static void dib0090_set_EFUSE(struct dib0090_state *state)
Olivier Grenie28fafca2011-01-04 04:27:11 -03001512{
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001513 u8 c, h, n;
1514 u16 e2, e4;
1515 u16 cal;
Olivier Grenie28fafca2011-01-04 04:27:11 -03001516
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001517 e2 = dib0090_read_reg(state, 0x26);
1518 e4 = dib0090_read_reg(state, 0x28);
Olivier Grenie28fafca2011-01-04 04:27:11 -03001519
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001520 if ((state->identity.version == P1D_E_F) ||
1521 (state->identity.version == P1G) || (e2 == 0xffff)) {
Olivier Grenie28fafca2011-01-04 04:27:11 -03001522
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001523 dib0090_write_reg(state, 0x22, 0x10);
1524 cal = (dib0090_read_reg(state, 0x22) >> 6) & 0x3ff;
Olivier Grenie28fafca2011-01-04 04:27:11 -03001525
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001526 if ((cal < 670) || (cal == 1023))
1527 cal = 850;
1528 n = 165 - ((cal * 10)>>6) ;
1529 e2 = e4 = (3<<12) | (34<<6) | (n);
1530 }
Olivier Grenie28fafca2011-01-04 04:27:11 -03001531
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001532 if (e2 != e4)
1533 e2 &= e4; /* Remove the redundancy */
Olivier Grenie28fafca2011-01-04 04:27:11 -03001534
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001535 if (e2 != 0xffff) {
1536 c = e2 & 0x3f;
1537 n = (e2 >> 12) & 0xf;
1538 h = (e2 >> 6) & 0x3f;
Olivier Grenie28fafca2011-01-04 04:27:11 -03001539
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001540 if ((c >= CAP_VALUE_MAX) || (c <= CAP_VALUE_MIN))
1541 c = 32;
Olivier Grenieaedabf72012-12-31 10:38:44 -03001542 else
1543 c += 14;
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001544 if ((h >= HR_MAX) || (h <= HR_MIN))
1545 h = 34;
1546 if ((n >= POLY_MAX) || (n <= POLY_MIN))
1547 n = 3;
Olivier Grenie28fafca2011-01-04 04:27:11 -03001548
Mauro Carvalho Chehab751dc8c2013-04-25 15:30:40 -03001549 dib0090_write_reg(state, 0x13, (h << 10));
1550 e2 = (n << 11) | ((h >> 2)<<6) | c;
1551 dib0090_write_reg(state, 0x2, e2); /* Load the BB_2 */
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001552 }
Olivier Grenie28fafca2011-01-04 04:27:11 -03001553}
1554
1555static int dib0090_reset(struct dvb_frontend *fe)
1556{
1557 struct dib0090_state *state = fe->tuner_priv;
1558
1559 dib0090_reset_digital(fe, state->config);
1560 if (dib0090_identify(fe) < 0)
1561 return -EIO;
1562
1563#ifdef CONFIG_TUNER_DIB0090_P1B_SUPPORT
1564 if (!(state->identity.version & 0x1)) /* it is P1B - reset is already done */
1565 return 0;
1566#endif
1567
1568 if (!state->identity.in_soc) {
1569 if ((dib0090_read_reg(state, 0x1a) >> 5) & 0x2)
1570 dib0090_write_reg(state, 0x1b, (EN_IQADC | EN_BB | EN_BIAS | EN_DIGCLK | EN_PLL | EN_CRYSTAL));
1571 else
1572 dib0090_write_reg(state, 0x1b, (EN_DIGCLK | EN_PLL | EN_CRYSTAL));
1573 }
1574
1575 dib0090_set_default_config(state, dib0090_defaults);
1576
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001577 if (state->identity.in_soc)
1578 dib0090_write_reg(state, 0x18, 0x2910); /* charge pump current = 0 */
Olivier Grenie28fafca2011-01-04 04:27:11 -03001579
1580 if (state->identity.p1g)
1581 dib0090_set_default_config(state, dib0090_p1g_additionnal_defaults);
1582
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001583 /* Update the efuse : Only available for KROSUS > P1C and SOC as well*/
1584 if (((state->identity.version & 0x1f) >= P1D_E_F) || (state->identity.in_soc))
1585 dib0090_set_EFUSE(state);
Olivier Grenie03245a52009-12-04 13:27:57 -03001586
1587 /* Congigure in function of the crystal */
Olivier Grenie2e802862011-08-05 10:39:15 -03001588 if (state->config->force_crystal_mode != 0)
1589 dib0090_write_reg(state, 0x14,
1590 state->config->force_crystal_mode & 3);
1591 else if (state->config->io.clock_khz >= 24000)
Olivier Grenie28fafca2011-01-04 04:27:11 -03001592 dib0090_write_reg(state, 0x14, 1);
Olivier Grenie03245a52009-12-04 13:27:57 -03001593 else
Olivier Grenie28fafca2011-01-04 04:27:11 -03001594 dib0090_write_reg(state, 0x14, 2);
Olivier Grenie03245a52009-12-04 13:27:57 -03001595 dprintk("Pll lock : %d", (dib0090_read_reg(state, 0x1a) >> 11) & 0x1);
1596
Olivier Grenie28fafca2011-01-04 04:27:11 -03001597 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 -03001598
1599 return 0;
1600}
1601
Olivier Grenie9c783032009-12-07 07:49:40 -03001602#define steps(u) (((u) > 15) ? ((u)-16) : (u))
Olivier Grenie03245a52009-12-04 13:27:57 -03001603#define INTERN_WAIT 10
1604static int dib0090_get_offset(struct dib0090_state *state, enum frontend_tune_state *tune_state)
1605{
1606 int ret = INTERN_WAIT * 10;
1607
1608 switch (*tune_state) {
1609 case CT_TUNER_STEP_2:
1610 /* Turns to positive */
1611 dib0090_write_reg(state, 0x1f, 0x7);
1612 *tune_state = CT_TUNER_STEP_3;
1613 break;
1614
1615 case CT_TUNER_STEP_3:
1616 state->adc_diff = dib0090_read_reg(state, 0x1d);
1617
1618 /* Turns to negative */
1619 dib0090_write_reg(state, 0x1f, 0x4);
1620 *tune_state = CT_TUNER_STEP_4;
1621 break;
1622
1623 case CT_TUNER_STEP_4:
1624 state->adc_diff -= dib0090_read_reg(state, 0x1d);
1625 *tune_state = CT_TUNER_STEP_5;
1626 ret = 0;
1627 break;
1628
1629 default:
1630 break;
1631 }
1632
1633 return ret;
1634}
1635
1636struct dc_calibration {
Olivier Grenie28fafca2011-01-04 04:27:11 -03001637 u8 addr;
1638 u8 offset;
1639 u8 pga:1;
1640 u16 bb1;
1641 u8 i:1;
Olivier Grenie03245a52009-12-04 13:27:57 -03001642};
1643
1644static const struct dc_calibration dc_table[] = {
1645 /* Step1 BB gain1= 26 with boost 1, gain 2 = 0 */
1646 {0x06, 5, 1, (1 << 13) | (0 << 8) | (26 << 3), 1},
1647 {0x07, 11, 1, (1 << 13) | (0 << 8) | (26 << 3), 0},
1648 /* Step 2 BB gain 1 = 26 with boost = 1 & gain 2 = 29 */
1649 {0x06, 0, 0, (1 << 13) | (29 << 8) | (26 << 3), 1},
1650 {0x06, 10, 0, (1 << 13) | (29 << 8) | (26 << 3), 0},
1651 {0},
1652};
1653
Olivier Grenie28fafca2011-01-04 04:27:11 -03001654static const struct dc_calibration dc_p1g_table[] = {
1655 /* Step1 BB gain1= 26 with boost 1, gain 2 = 0 */
1656 /* addr ; trim reg offset ; pga ; CTRL_BB1 value ; i or q */
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001657 {0x06, 5, 1, (1 << 13) | (0 << 8) | (15 << 3), 1},
1658 {0x07, 11, 1, (1 << 13) | (0 << 8) | (15 << 3), 0},
Olivier Grenie28fafca2011-01-04 04:27:11 -03001659 /* Step 2 BB gain 1 = 26 with boost = 1 & gain 2 = 29 */
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001660 {0x06, 0, 0, (1 << 13) | (29 << 8) | (15 << 3), 1},
1661 {0x06, 10, 0, (1 << 13) | (29 << 8) | (15 << 3), 0},
Olivier Grenie28fafca2011-01-04 04:27:11 -03001662 {0},
1663};
1664
Olivier Grenie03245a52009-12-04 13:27:57 -03001665static void dib0090_set_trim(struct dib0090_state *state)
1666{
1667 u16 *val;
1668
1669 if (state->dc->addr == 0x07)
1670 val = &state->bb7;
1671 else
1672 val = &state->bb6;
1673
1674 *val &= ~(0x1f << state->dc->offset);
1675 *val |= state->step << state->dc->offset;
1676
1677 dib0090_write_reg(state, state->dc->addr, *val);
1678}
1679
1680static int dib0090_dc_offset_calibration(struct dib0090_state *state, enum frontend_tune_state *tune_state)
1681{
1682 int ret = 0;
Olivier Grenie28fafca2011-01-04 04:27:11 -03001683 u16 reg;
Olivier Grenie03245a52009-12-04 13:27:57 -03001684
1685 switch (*tune_state) {
Olivier Grenie03245a52009-12-04 13:27:57 -03001686 case CT_TUNER_START:
Olivier Grenie28fafca2011-01-04 04:27:11 -03001687 dprintk("Start DC offset calibration");
Olivier Grenie03245a52009-12-04 13:27:57 -03001688
1689 /* force vcm2 = 0.8V */
1690 state->bb6 = 0;
1691 state->bb7 = 0x040d;
1692
Olivier Grenie28fafca2011-01-04 04:27:11 -03001693 /* the LNA AND LO are off */
1694 reg = dib0090_read_reg(state, 0x24) & 0x0ffb; /* shutdown lna and lo */
1695 dib0090_write_reg(state, 0x24, reg);
1696
1697 state->wbdmux = dib0090_read_reg(state, 0x10);
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001698 dib0090_write_reg(state, 0x10, (state->wbdmux & ~(0xff << 3)) | (0x7 << 3) | 0x3);
1699 dib0090_write_reg(state, 0x23, dib0090_read_reg(state, 0x23) & ~(1 << 14));
Olivier Grenie28fafca2011-01-04 04:27:11 -03001700
Olivier Grenie03245a52009-12-04 13:27:57 -03001701 state->dc = dc_table;
1702
Olivier Grenie28fafca2011-01-04 04:27:11 -03001703 if (state->identity.p1g)
1704 state->dc = dc_p1g_table;
Olivier Grenie03245a52009-12-04 13:27:57 -03001705
1706 /* fall through */
Olivier Grenie03245a52009-12-04 13:27:57 -03001707 case CT_TUNER_STEP_0:
Mauro Carvalho Chehab91aff0c2015-06-05 08:27:18 -03001708 dprintk("Start/continue DC calibration for %s path", (state->dc->i == 1) ? "I" : "Q");
Olivier Grenie03245a52009-12-04 13:27:57 -03001709 dib0090_write_reg(state, 0x01, state->dc->bb1);
1710 dib0090_write_reg(state, 0x07, state->bb7 | (state->dc->i << 7));
1711
1712 state->step = 0;
Olivier Grenie03245a52009-12-04 13:27:57 -03001713 state->min_adc_diff = 1023;
Olivier Grenie03245a52009-12-04 13:27:57 -03001714 *tune_state = CT_TUNER_STEP_1;
1715 ret = 50;
1716 break;
1717
1718 case CT_TUNER_STEP_1:
1719 dib0090_set_trim(state);
Olivier Grenie03245a52009-12-04 13:27:57 -03001720 *tune_state = CT_TUNER_STEP_2;
1721 break;
1722
1723 case CT_TUNER_STEP_2:
1724 case CT_TUNER_STEP_3:
1725 case CT_TUNER_STEP_4:
1726 ret = dib0090_get_offset(state, tune_state);
1727 break;
1728
1729 case CT_TUNER_STEP_5: /* found an offset */
Olivier Grenie28fafca2011-01-04 04:27:11 -03001730 dprintk("adc_diff = %d, current step= %d", (u32) state->adc_diff, state->step);
1731 if (state->step == 0 && state->adc_diff < 0) {
1732 state->min_adc_diff = -1023;
1733 dprintk("Change of sign of the minimum adc diff");
1734 }
1735
1736 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 -03001737
1738 /* first turn for this frequency */
1739 if (state->step == 0) {
1740 if (state->dc->pga && state->adc_diff < 0)
1741 state->step = 0x10;
1742 if (state->dc->pga == 0 && state->adc_diff > 0)
1743 state->step = 0x10;
1744 }
1745
Olivier Grenie28fafca2011-01-04 04:27:11 -03001746 /* Look for a change of Sign in the Adc_diff.min_adc_diff is used to STORE the setp N-1 */
1747 if ((state->adc_diff & 0x8000) == (state->min_adc_diff & 0x8000) && steps(state->step) < 15) {
1748 /* 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 -03001749 state->step++;
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001750 state->min_adc_diff = state->adc_diff;
Olivier Grenie03245a52009-12-04 13:27:57 -03001751 *tune_state = CT_TUNER_STEP_1;
1752 } else {
Olivier Grenie03245a52009-12-04 13:27:57 -03001753 /* the minimum was what we have seen in the step before */
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001754 if (ABS(state->adc_diff) > ABS(state->min_adc_diff)) {
Olivier Grenie28fafca2011-01-04 04:27:11 -03001755 dprintk("Since adc_diff N = %d > adc_diff step N-1 = %d, Come back one step", state->adc_diff, state->min_adc_diff);
1756 state->step--;
1757 }
Olivier Grenie03245a52009-12-04 13:27:57 -03001758
Olivier Grenie28fafca2011-01-04 04:27:11 -03001759 dib0090_set_trim(state);
1760 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 -03001761
1762 state->dc++;
1763 if (state->dc->addr == 0) /* done */
1764 *tune_state = CT_TUNER_STEP_6;
1765 else
1766 *tune_state = CT_TUNER_STEP_0;
1767
1768 }
1769 break;
1770
1771 case CT_TUNER_STEP_6:
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001772 dib0090_write_reg(state, 0x07, state->bb7 & ~0x0008);
Olivier Grenie03245a52009-12-04 13:27:57 -03001773 dib0090_write_reg(state, 0x1f, 0x7);
1774 *tune_state = CT_TUNER_START; /* reset done -> real tuning can now begin */
Olivier Grenie28fafca2011-01-04 04:27:11 -03001775 state->calibrate &= ~DC_CAL;
Olivier Grenie03245a52009-12-04 13:27:57 -03001776 default:
1777 break;
1778 }
1779 return ret;
1780}
1781
1782static int dib0090_wbd_calibration(struct dib0090_state *state, enum frontend_tune_state *tune_state)
1783{
Olivier Grenie28fafca2011-01-04 04:27:11 -03001784 u8 wbd_gain;
1785 const struct dib0090_wbd_slope *wbd = state->current_wbd_table;
1786
Olivier Grenie03245a52009-12-04 13:27:57 -03001787 switch (*tune_state) {
1788 case CT_TUNER_START:
Olivier Grenie28fafca2011-01-04 04:27:11 -03001789 while (state->current_rf / 1000 > wbd->max_freq)
1790 wbd++;
1791 if (wbd->wbd_gain != 0)
1792 wbd_gain = wbd->wbd_gain;
1793 else {
1794 wbd_gain = 4;
1795#if defined(CONFIG_BAND_LBAND) || defined(CONFIG_BAND_SBAND)
1796 if ((state->current_band == BAND_LBAND) || (state->current_band == BAND_SBAND))
1797 wbd_gain = 2;
1798#endif
1799 }
Olivier Grenie03245a52009-12-04 13:27:57 -03001800
Olivier Grenie28fafca2011-01-04 04:27:11 -03001801 if (wbd_gain == state->wbd_calibration_gain) { /* the WBD calibration has already been done */
1802 *tune_state = CT_TUNER_START;
1803 state->calibrate &= ~WBD_CAL;
1804 return 0;
1805 }
1806
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001807 dib0090_write_reg(state, 0x10, 0x1b81 | (1 << 10) | (wbd_gain << 13) | (1 << 3));
Olivier Grenie28fafca2011-01-04 04:27:11 -03001808
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001809 dib0090_write_reg(state, 0x24, ((EN_UHF & 0x0fff) | (1 << 1)));
Olivier Grenie03245a52009-12-04 13:27:57 -03001810 *tune_state = CT_TUNER_STEP_0;
Olivier Grenie28fafca2011-01-04 04:27:11 -03001811 state->wbd_calibration_gain = wbd_gain;
Olivier Grenie03245a52009-12-04 13:27:57 -03001812 return 90; /* wait for the WBDMUX to switch and for the ADC to sample */
Olivier Grenie03245a52009-12-04 13:27:57 -03001813
Olivier Grenie28fafca2011-01-04 04:27:11 -03001814 case CT_TUNER_STEP_0:
1815 state->wbd_offset = dib0090_get_slow_adc_val(state);
1816 dprintk("WBD calibration offset = %d", state->wbd_offset);
Olivier Grenie03245a52009-12-04 13:27:57 -03001817 *tune_state = CT_TUNER_START; /* reset done -> real tuning can now begin */
Olivier Grenie28fafca2011-01-04 04:27:11 -03001818 state->calibrate &= ~WBD_CAL;
Olivier Grenie03245a52009-12-04 13:27:57 -03001819 break;
Olivier Grenie28fafca2011-01-04 04:27:11 -03001820
Olivier Grenie03245a52009-12-04 13:27:57 -03001821 default:
1822 break;
1823 }
1824 return 0;
1825}
1826
1827static void dib0090_set_bandwidth(struct dib0090_state *state)
1828{
1829 u16 tmp;
1830
1831 if (state->fe->dtv_property_cache.bandwidth_hz / 1000 <= 5000)
1832 tmp = (3 << 14);
1833 else if (state->fe->dtv_property_cache.bandwidth_hz / 1000 <= 6000)
1834 tmp = (2 << 14);
1835 else if (state->fe->dtv_property_cache.bandwidth_hz / 1000 <= 7000)
1836 tmp = (1 << 14);
1837 else
1838 tmp = (0 << 14);
1839
1840 state->bb_1_def &= 0x3fff;
1841 state->bb_1_def |= tmp;
1842
1843 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 -03001844
1845 dib0090_write_reg(state, 0x03, 0x6008); /* = 0x6008 : vcm3_trim = 1 ; filter2_gm1_trim = 8 ; filter2_cutoff_freq = 0 */
1846 dib0090_write_reg(state, 0x04, 0x1); /* 0 = 1KHz ; 1 = 50Hz ; 2 = 150Hz ; 3 = 50KHz ; 4 = servo fast */
1847 if (state->identity.in_soc) {
1848 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 */
1849 } else {
1850 dib0090_write_reg(state, 0x02, (5 << 11) | (8 << 6) | (22 & 0x3f)); /* 22 = cap_value */
1851 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 */
1852 }
Olivier Grenie03245a52009-12-04 13:27:57 -03001853}
1854
1855static const struct dib0090_pll dib0090_pll_table[] = {
1856#ifdef CONFIG_BAND_CBAND
1857 {56000, 0, 9, 48, 6},
1858 {70000, 1, 9, 48, 6},
1859 {87000, 0, 8, 32, 4},
1860 {105000, 1, 8, 32, 4},
1861 {115000, 0, 7, 24, 6},
1862 {140000, 1, 7, 24, 6},
1863 {170000, 0, 6, 16, 4},
1864#endif
1865#ifdef CONFIG_BAND_VHF
1866 {200000, 1, 6, 16, 4},
1867 {230000, 0, 5, 12, 6},
1868 {280000, 1, 5, 12, 6},
1869 {340000, 0, 4, 8, 4},
1870 {380000, 1, 4, 8, 4},
1871 {450000, 0, 3, 6, 6},
1872#endif
1873#ifdef CONFIG_BAND_UHF
1874 {580000, 1, 3, 6, 6},
1875 {700000, 0, 2, 4, 4},
1876 {860000, 1, 2, 4, 4},
1877#endif
1878#ifdef CONFIG_BAND_LBAND
1879 {1800000, 1, 0, 2, 4},
1880#endif
1881#ifdef CONFIG_BAND_SBAND
1882 {2900000, 0, 14, 1, 4},
1883#endif
1884};
1885
1886static const struct dib0090_tuning dib0090_tuning_table_fm_vhf_on_cband[] = {
1887
1888#ifdef CONFIG_BAND_CBAND
1889 {184000, 4, 1, 15, 0x280, 0x2912, 0xb94e, EN_CAB},
1890 {227000, 4, 3, 15, 0x280, 0x2912, 0xb94e, EN_CAB},
1891 {380000, 4, 7, 15, 0x280, 0x2912, 0xb94e, EN_CAB},
1892#endif
1893#ifdef CONFIG_BAND_UHF
1894 {520000, 2, 0, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},
1895 {550000, 2, 2, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},
1896 {650000, 2, 3, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},
1897 {750000, 2, 5, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},
1898 {850000, 2, 6, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},
1899 {900000, 2, 7, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},
1900#endif
1901#ifdef CONFIG_BAND_LBAND
1902 {1500000, 4, 0, 20, 0x300, 0x1912, 0x82c9, EN_LBD},
1903 {1600000, 4, 1, 20, 0x300, 0x1912, 0x82c9, EN_LBD},
1904 {1800000, 4, 3, 20, 0x300, 0x1912, 0x82c9, EN_LBD},
1905#endif
1906#ifdef CONFIG_BAND_SBAND
1907 {2300000, 1, 4, 20, 0x300, 0x2d2A, 0x82c7, EN_SBD},
1908 {2900000, 1, 7, 20, 0x280, 0x2deb, 0x8347, EN_SBD},
1909#endif
1910};
1911
1912static const struct dib0090_tuning dib0090_tuning_table[] = {
1913
1914#ifdef CONFIG_BAND_CBAND
1915 {170000, 4, 1, 15, 0x280, 0x2912, 0xb94e, EN_CAB},
1916#endif
1917#ifdef CONFIG_BAND_VHF
1918 {184000, 1, 1, 15, 0x300, 0x4d12, 0xb94e, EN_VHF},
1919 {227000, 1, 3, 15, 0x300, 0x4d12, 0xb94e, EN_VHF},
1920 {380000, 1, 7, 15, 0x300, 0x4d12, 0xb94e, EN_VHF},
1921#endif
1922#ifdef CONFIG_BAND_UHF
1923 {520000, 2, 0, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},
1924 {550000, 2, 2, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},
1925 {650000, 2, 3, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},
1926 {750000, 2, 5, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},
1927 {850000, 2, 6, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},
1928 {900000, 2, 7, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},
1929#endif
1930#ifdef CONFIG_BAND_LBAND
1931 {1500000, 4, 0, 20, 0x300, 0x1912, 0x82c9, EN_LBD},
1932 {1600000, 4, 1, 20, 0x300, 0x1912, 0x82c9, EN_LBD},
1933 {1800000, 4, 3, 20, 0x300, 0x1912, 0x82c9, EN_LBD},
1934#endif
1935#ifdef CONFIG_BAND_SBAND
1936 {2300000, 1, 4, 20, 0x300, 0x2d2A, 0x82c7, EN_SBD},
1937 {2900000, 1, 7, 20, 0x280, 0x2deb, 0x8347, EN_SBD},
1938#endif
1939};
1940
Olivier Grenie28fafca2011-01-04 04:27:11 -03001941static const struct dib0090_tuning dib0090_p1g_tuning_table[] = {
Olivier Grenie28fafca2011-01-04 04:27:11 -03001942#ifdef CONFIG_BAND_CBAND
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001943 {170000, 4, 1, 0x820f, 0x300, 0x2d22, 0x82cb, EN_CAB},
Olivier Grenie28fafca2011-01-04 04:27:11 -03001944#endif
1945#ifdef CONFIG_BAND_VHF
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001946 {184000, 1, 1, 15, 0x300, 0x4d12, 0xb94e, EN_VHF},
1947 {227000, 1, 3, 15, 0x300, 0x4d12, 0xb94e, EN_VHF},
1948 {380000, 1, 7, 15, 0x300, 0x4d12, 0xb94e, EN_VHF},
Olivier Grenie28fafca2011-01-04 04:27:11 -03001949#endif
1950#ifdef CONFIG_BAND_UHF
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001951 {510000, 2, 0, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},
1952 {540000, 2, 1, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},
1953 {600000, 2, 3, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},
1954 {630000, 2, 4, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},
1955 {680000, 2, 5, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},
1956 {720000, 2, 6, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},
1957 {900000, 2, 7, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},
Olivier Grenie28fafca2011-01-04 04:27:11 -03001958#endif
1959#ifdef CONFIG_BAND_LBAND
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001960 {1500000, 4, 0, 20, 0x300, 0x1912, 0x82c9, EN_LBD},
1961 {1600000, 4, 1, 20, 0x300, 0x1912, 0x82c9, EN_LBD},
1962 {1800000, 4, 3, 20, 0x300, 0x1912, 0x82c9, EN_LBD},
Olivier Grenie28fafca2011-01-04 04:27:11 -03001963#endif
1964#ifdef CONFIG_BAND_SBAND
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001965 {2300000, 1, 4, 20, 0x300, 0x2d2A, 0x82c7, EN_SBD},
1966 {2900000, 1, 7, 20, 0x280, 0x2deb, 0x8347, EN_SBD},
Olivier Grenie28fafca2011-01-04 04:27:11 -03001967#endif
1968};
1969
1970static const struct dib0090_pll dib0090_p1g_pll_table[] = {
1971#ifdef CONFIG_BAND_CBAND
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001972 {57000, 0, 11, 48, 6},
1973 {70000, 1, 11, 48, 6},
1974 {86000, 0, 10, 32, 4},
1975 {105000, 1, 10, 32, 4},
1976 {115000, 0, 9, 24, 6},
1977 {140000, 1, 9, 24, 6},
1978 {170000, 0, 8, 16, 4},
Olivier Grenie28fafca2011-01-04 04:27:11 -03001979#endif
1980#ifdef CONFIG_BAND_VHF
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001981 {200000, 1, 8, 16, 4},
1982 {230000, 0, 7, 12, 6},
1983 {280000, 1, 7, 12, 6},
1984 {340000, 0, 6, 8, 4},
1985 {380000, 1, 6, 8, 4},
1986 {455000, 0, 5, 6, 6},
Olivier Grenie28fafca2011-01-04 04:27:11 -03001987#endif
1988#ifdef CONFIG_BAND_UHF
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001989 {580000, 1, 5, 6, 6},
1990 {680000, 0, 4, 4, 4},
1991 {860000, 1, 4, 4, 4},
Olivier Grenie28fafca2011-01-04 04:27:11 -03001992#endif
1993#ifdef CONFIG_BAND_LBAND
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001994 {1800000, 1, 2, 2, 4},
Olivier Grenie28fafca2011-01-04 04:27:11 -03001995#endif
1996#ifdef CONFIG_BAND_SBAND
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001997 {2900000, 0, 1, 1, 6},
Olivier Grenie28fafca2011-01-04 04:27:11 -03001998#endif
1999};
2000
2001static const struct dib0090_tuning dib0090_p1g_tuning_table_fm_vhf_on_cband[] = {
Olivier Grenie28fafca2011-01-04 04:27:11 -03002002#ifdef CONFIG_BAND_CBAND
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002003 {184000, 4, 3, 0x4187, 0x2c0, 0x2d22, 0x81cb, EN_CAB},
2004 {227000, 4, 3, 0x4187, 0x2c0, 0x2d22, 0x81cb, EN_CAB},
2005 {380000, 4, 3, 0x4187, 0x2c0, 0x2d22, 0x81cb, EN_CAB},
Olivier Grenie28fafca2011-01-04 04:27:11 -03002006#endif
2007#ifdef CONFIG_BAND_UHF
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002008 {520000, 2, 0, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},
2009 {550000, 2, 2, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},
2010 {650000, 2, 3, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},
2011 {750000, 2, 5, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},
2012 {850000, 2, 6, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},
2013 {900000, 2, 7, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},
Olivier Grenie28fafca2011-01-04 04:27:11 -03002014#endif
2015#ifdef CONFIG_BAND_LBAND
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002016 {1500000, 4, 0, 20, 0x300, 0x1912, 0x82c9, EN_LBD},
2017 {1600000, 4, 1, 20, 0x300, 0x1912, 0x82c9, EN_LBD},
2018 {1800000, 4, 3, 20, 0x300, 0x1912, 0x82c9, EN_LBD},
Olivier Grenie28fafca2011-01-04 04:27:11 -03002019#endif
2020#ifdef CONFIG_BAND_SBAND
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002021 {2300000, 1, 4, 20, 0x300, 0x2d2A, 0x82c7, EN_SBD},
2022 {2900000, 1, 7, 20, 0x280, 0x2deb, 0x8347, EN_SBD},
Olivier Grenie28fafca2011-01-04 04:27:11 -03002023#endif
2024};
2025
2026static const struct dib0090_tuning dib0090_tuning_table_cband_7090[] = {
Olivier Grenie28fafca2011-01-04 04:27:11 -03002027#ifdef CONFIG_BAND_CBAND
Olivier Grenie28fafca2011-01-04 04:27:11 -03002028 {300000, 4, 3, 0x018F, 0x2c0, 0x2d22, 0xb9ce, EN_CAB},
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002029 {380000, 4, 10, 0x018F, 0x2c0, 0x2d22, 0xb9ce, EN_CAB},
Olivier Grenie28fafca2011-01-04 04:27:11 -03002030 {570000, 4, 10, 0x8190, 0x2c0, 0x2d22, 0xb9ce, EN_CAB},
2031 {858000, 4, 5, 0x8190, 0x2c0, 0x2d22, 0xb9ce, EN_CAB},
2032#endif
2033};
2034
Olivier Grenie6724a2f2011-08-05 13:49:33 -03002035static const struct dib0090_tuning dib0090_tuning_table_cband_7090e_sensitivity[] = {
2036#ifdef CONFIG_BAND_CBAND
2037 { 300000, 0 , 3, 0x8105, 0x2c0, 0x2d12, 0xb84e, EN_CAB },
2038 { 380000, 0 , 10, 0x810F, 0x2c0, 0x2d12, 0xb84e, EN_CAB },
2039 { 600000, 0 , 10, 0x815E, 0x280, 0x2d12, 0xb84e, EN_CAB },
2040 { 660000, 0 , 5, 0x85E3, 0x280, 0x2d12, 0xb84e, EN_CAB },
2041 { 720000, 0 , 5, 0x852E, 0x280, 0x2d12, 0xb84e, EN_CAB },
2042 { 860000, 0 , 4, 0x85E5, 0x280, 0x2d12, 0xb84e, EN_CAB },
2043#endif
2044};
2045
2046int dib0090_update_tuning_table_7090(struct dvb_frontend *fe,
2047 u8 cfg_sensitivity)
2048{
2049 struct dib0090_state *state = fe->tuner_priv;
2050 const struct dib0090_tuning *tune =
2051 dib0090_tuning_table_cband_7090e_sensitivity;
2052 const struct dib0090_tuning dib0090_tuning_table_cband_7090e_aci[] = {
2053 { 300000, 0 , 3, 0x8165, 0x2c0, 0x2d12, 0xb84e, EN_CAB },
2054 { 650000, 0 , 4, 0x815B, 0x280, 0x2d12, 0xb84e, EN_CAB },
2055 { 860000, 0 , 5, 0x84EF, 0x280, 0x2d12, 0xb84e, EN_CAB },
2056 };
2057
2058 if ((!state->identity.p1g) || (!state->identity.in_soc)
2059 || ((state->identity.version != SOC_7090_P1G_21R1)
2060 && (state->identity.version != SOC_7090_P1G_11R1))) {
2061 dprintk("%s() function can only be used for dib7090", __func__);
2062 return -ENODEV;
2063 }
2064
2065 if (cfg_sensitivity)
2066 tune = dib0090_tuning_table_cband_7090e_sensitivity;
2067 else
2068 tune = dib0090_tuning_table_cband_7090e_aci;
2069
2070 while (state->rf_request > tune->max_freq)
2071 tune++;
2072
2073 dib0090_write_reg(state, 0x09, (dib0090_read_reg(state, 0x09) & 0x8000)
2074 | (tune->lna_bias & 0x7fff));
2075 dib0090_write_reg(state, 0x0b, (dib0090_read_reg(state, 0x0b) & 0xf83f)
2076 | ((tune->lna_tune << 6) & 0x07c0));
2077 return 0;
2078}
2079EXPORT_SYMBOL(dib0090_update_tuning_table_7090);
2080
Olivier Grenie28fafca2011-01-04 04:27:11 -03002081static int dib0090_captrim_search(struct dib0090_state *state, enum frontend_tune_state *tune_state)
2082{
2083 int ret = 0;
2084 u16 lo4 = 0xe900;
2085
2086 s16 adc_target;
2087 u16 adc;
2088 s8 step_sign;
2089 u8 force_soft_search = 0;
2090
2091 if (state->identity.version == SOC_8090_P1G_11R1 || state->identity.version == SOC_8090_P1G_21R1)
2092 force_soft_search = 1;
2093
2094 if (*tune_state == CT_TUNER_START) {
2095 dprintk("Start Captrim search : %s", (force_soft_search == 1) ? "FORCE SOFT SEARCH" : "AUTO");
2096 dib0090_write_reg(state, 0x10, 0x2B1);
2097 dib0090_write_reg(state, 0x1e, 0x0032);
2098
2099 if (!state->tuner_is_tuned) {
2100 /* prepare a complete captrim */
2101 if (!state->identity.p1g || force_soft_search)
2102 state->step = state->captrim = state->fcaptrim = 64;
2103
2104 state->current_rf = state->rf_request;
2105 } else { /* we are already tuned to this frequency - the configuration is correct */
2106 if (!state->identity.p1g || force_soft_search) {
2107 /* do a minimal captrim even if the frequency has not changed */
2108 state->step = 4;
2109 state->captrim = state->fcaptrim = dib0090_read_reg(state, 0x18) & 0x7f;
2110 }
2111 }
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002112 state->adc_diff = 3000;
Olivier Grenie28fafca2011-01-04 04:27:11 -03002113 *tune_state = CT_TUNER_STEP_0;
2114
2115 } else if (*tune_state == CT_TUNER_STEP_0) {
2116 if (state->identity.p1g && !force_soft_search) {
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002117 u8 ratio = 31;
Olivier Grenie28fafca2011-01-04 04:27:11 -03002118
2119 dib0090_write_reg(state, 0x40, (3 << 7) | (ratio << 2) | (1 << 1) | 1);
2120 dib0090_read_reg(state, 0x40);
Olivier Grenie28fafca2011-01-04 04:27:11 -03002121 ret = 50;
2122 } else {
2123 state->step /= 2;
2124 dib0090_write_reg(state, 0x18, lo4 | state->captrim);
2125
2126 if (state->identity.in_soc)
2127 ret = 25;
2128 }
2129 *tune_state = CT_TUNER_STEP_1;
2130
2131 } else if (*tune_state == CT_TUNER_STEP_1) {
2132 if (state->identity.p1g && !force_soft_search) {
2133 dib0090_write_reg(state, 0x40, 0x18c | (0 << 1) | 0);
2134 dib0090_read_reg(state, 0x40);
2135
2136 state->fcaptrim = dib0090_read_reg(state, 0x18) & 0x7F;
2137 dprintk("***Final Captrim= 0x%x", state->fcaptrim);
2138 *tune_state = CT_TUNER_STEP_3;
2139
2140 } else {
2141 /* MERGE for all krosus before P1G */
2142 adc = dib0090_get_slow_adc_val(state);
2143 dprintk("CAPTRIM=%d; ADC = %d (ADC) & %dmV", (u32) state->captrim, (u32) adc, (u32) (adc) * (u32) 1800 / (u32) 1024);
2144
2145 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 !!! */
2146 adc_target = 200;
2147 } else
2148 adc_target = 400;
2149
2150 if (adc >= adc_target) {
2151 adc -= adc_target;
2152 step_sign = -1;
2153 } else {
2154 adc = adc_target - adc;
2155 step_sign = 1;
2156 }
2157
2158 if (adc < state->adc_diff) {
2159 dprintk("CAPTRIM=%d is closer to target (%d/%d)", (u32) state->captrim, (u32) adc, (u32) state->adc_diff);
2160 state->adc_diff = adc;
2161 state->fcaptrim = state->captrim;
Olivier Grenie28fafca2011-01-04 04:27:11 -03002162 }
2163
2164 state->captrim += step_sign * state->step;
2165 if (state->step >= 1)
2166 *tune_state = CT_TUNER_STEP_0;
2167 else
2168 *tune_state = CT_TUNER_STEP_2;
2169
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002170 ret = 25;
Olivier Grenie28fafca2011-01-04 04:27:11 -03002171 }
2172 } else if (*tune_state == CT_TUNER_STEP_2) { /* this step is only used by krosus < P1G */
2173 /*write the final cptrim config */
2174 dib0090_write_reg(state, 0x18, lo4 | state->fcaptrim);
2175
2176 *tune_state = CT_TUNER_STEP_3;
2177
2178 } else if (*tune_state == CT_TUNER_STEP_3) {
2179 state->calibrate &= ~CAPTRIM_CAL;
2180 *tune_state = CT_TUNER_STEP_0;
2181 }
2182
2183 return ret;
2184}
2185
2186static int dib0090_get_temperature(struct dib0090_state *state, enum frontend_tune_state *tune_state)
2187{
2188 int ret = 15;
2189 s16 val;
2190
Olivier Grenie28fafca2011-01-04 04:27:11 -03002191 switch (*tune_state) {
2192 case CT_TUNER_START:
2193 state->wbdmux = dib0090_read_reg(state, 0x10);
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002194 dib0090_write_reg(state, 0x10, (state->wbdmux & ~(0xff << 3)) | (0x8 << 3));
Olivier Grenie28fafca2011-01-04 04:27:11 -03002195
2196 state->bias = dib0090_read_reg(state, 0x13);
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002197 dib0090_write_reg(state, 0x13, state->bias | (0x3 << 8));
Olivier Grenie28fafca2011-01-04 04:27:11 -03002198
2199 *tune_state = CT_TUNER_STEP_0;
2200 /* wait for the WBDMUX to switch and for the ADC to sample */
2201 break;
2202
2203 case CT_TUNER_STEP_0:
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002204 state->adc_diff = dib0090_get_slow_adc_val(state);
2205 dib0090_write_reg(state, 0x13, (state->bias & ~(0x3 << 8)) | (0x2 << 8));
Olivier Grenie28fafca2011-01-04 04:27:11 -03002206 *tune_state = CT_TUNER_STEP_1;
2207 break;
2208
2209 case CT_TUNER_STEP_1:
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002210 val = dib0090_get_slow_adc_val(state);
2211 state->temperature = ((s16) ((val - state->adc_diff) * 180) >> 8) + 55;
Olivier Grenie28fafca2011-01-04 04:27:11 -03002212
2213 dprintk("temperature: %d C", state->temperature - 30);
2214
2215 *tune_state = CT_TUNER_STEP_2;
2216 break;
2217
2218 case CT_TUNER_STEP_2:
Olivier Grenie28fafca2011-01-04 04:27:11 -03002219 dib0090_write_reg(state, 0x13, state->bias);
2220 dib0090_write_reg(state, 0x10, state->wbdmux); /* write back original WBDMUX */
2221
2222 *tune_state = CT_TUNER_START;
2223 state->calibrate &= ~TEMP_CAL;
2224 if (state->config->analog_output == 0)
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002225 dib0090_write_reg(state, 0x23, dib0090_read_reg(state, 0x23) | (1 << 14));
Olivier Grenie28fafca2011-01-04 04:27:11 -03002226
2227 break;
2228
2229 default:
2230 ret = 0;
2231 break;
2232 }
2233 return ret;
2234}
2235
Olivier Grenie03245a52009-12-04 13:27:57 -03002236#define WBD 0x781 /* 1 1 1 1 0000 0 0 1 */
2237static int dib0090_tune(struct dvb_frontend *fe)
2238{
2239 struct dib0090_state *state = fe->tuner_priv;
2240 const struct dib0090_tuning *tune = state->current_tune_table_index;
2241 const struct dib0090_pll *pll = state->current_pll_table_index;
2242 enum frontend_tune_state *tune_state = &state->tune_state;
2243
Olivier Grenie28fafca2011-01-04 04:27:11 -03002244 u16 lo5, lo6, Den, tmp;
Olivier Grenie03245a52009-12-04 13:27:57 -03002245 u32 FBDiv, Rest, FREF, VCOF_kHz = 0;
Olivier Grenie03245a52009-12-04 13:27:57 -03002246 int ret = 10; /* 1ms is the default delay most of the time */
2247 u8 c, i;
2248
Olivier Grenie28fafca2011-01-04 04:27:11 -03002249 /************************* VCO ***************************/
Olivier Grenie03245a52009-12-04 13:27:57 -03002250 /* Default values for FG */
2251 /* from these are needed : */
2252 /* Cp,HFdiv,VCOband,SD,Num,Den,FB and REFDiv */
2253
Olivier Grenie28fafca2011-01-04 04:27:11 -03002254 /* in any case we first need to do a calibration if needed */
2255 if (*tune_state == CT_TUNER_START) {
2256 /* deactivate DataTX before some calibrations */
2257 if (state->calibrate & (DC_CAL | TEMP_CAL | WBD_CAL))
2258 dib0090_write_reg(state, 0x23, dib0090_read_reg(state, 0x23) & ~(1 << 14));
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002259 else
2260 /* Activate DataTX in case a calibration has been done before */
2261 if (state->config->analog_output == 0)
2262 dib0090_write_reg(state, 0x23, dib0090_read_reg(state, 0x23) | (1 << 14));
Olivier Grenie03245a52009-12-04 13:27:57 -03002263 }
2264
Olivier Grenie28fafca2011-01-04 04:27:11 -03002265 if (state->calibrate & DC_CAL)
2266 return dib0090_dc_offset_calibration(state, tune_state);
2267 else if (state->calibrate & WBD_CAL) {
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002268 if (state->current_rf == 0)
Olivier Grenie28fafca2011-01-04 04:27:11 -03002269 state->current_rf = state->fe->dtv_property_cache.frequency / 1000;
Olivier Grenie28fafca2011-01-04 04:27:11 -03002270 return dib0090_wbd_calibration(state, tune_state);
2271 } else if (state->calibrate & TEMP_CAL)
2272 return dib0090_get_temperature(state, tune_state);
2273 else if (state->calibrate & CAPTRIM_CAL)
2274 return dib0090_captrim_search(state, tune_state);
2275
Olivier Grenie03245a52009-12-04 13:27:57 -03002276 if (*tune_state == CT_TUNER_START) {
Olivier Grenie28fafca2011-01-04 04:27:11 -03002277 /* 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 */
2278 if (state->config->use_pwm_agc && state->identity.in_soc) {
2279 tmp = dib0090_read_reg(state, 0x39);
2280 if ((tmp >> 10) & 0x1)
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002281 dib0090_write_reg(state, 0x39, tmp & ~(1 << 10));
Olivier Grenie28fafca2011-01-04 04:27:11 -03002282 }
Olivier Grenie03245a52009-12-04 13:27:57 -03002283
Olivier Grenie28fafca2011-01-04 04:27:11 -03002284 state->current_band = (u8) BAND_OF_FREQUENCY(state->fe->dtv_property_cache.frequency / 1000);
2285 state->rf_request =
2286 state->fe->dtv_property_cache.frequency / 1000 + (state->current_band ==
2287 BAND_UHF ? state->config->freq_offset_khz_uhf : state->config->
2288 freq_offset_khz_vhf);
2289
2290 /* in ISDB-T 1seg we shift tuning frequency */
2291 if ((state->fe->dtv_property_cache.delivery_system == SYS_ISDBT && state->fe->dtv_property_cache.isdbt_sb_mode == 1
2292 && state->fe->dtv_property_cache.isdbt_partial_reception == 0)) {
2293 const struct dib0090_low_if_offset_table *LUT_offset = state->config->low_if;
2294 u8 found_offset = 0;
2295 u32 margin_khz = 100;
2296
2297 if (LUT_offset != NULL) {
2298 while (LUT_offset->RF_freq != 0xffff) {
2299 if (((state->rf_request > (LUT_offset->RF_freq - margin_khz))
2300 && (state->rf_request < (LUT_offset->RF_freq + margin_khz)))
2301 && LUT_offset->std == state->fe->dtv_property_cache.delivery_system) {
2302 state->rf_request += LUT_offset->offset_khz;
2303 found_offset = 1;
2304 break;
2305 }
2306 LUT_offset++;
2307 }
2308 }
2309
2310 if (found_offset == 0)
2311 state->rf_request += 400;
2312 }
2313 if (state->current_rf != state->rf_request || (state->current_standard != state->fe->dtv_property_cache.delivery_system)) {
2314 state->tuner_is_tuned = 0;
Olivier Grenie03245a52009-12-04 13:27:57 -03002315 state->current_rf = 0;
Olivier Grenie28fafca2011-01-04 04:27:11 -03002316 state->current_standard = 0;
Olivier Grenie03245a52009-12-04 13:27:57 -03002317
Olivier Grenie28fafca2011-01-04 04:27:11 -03002318 tune = dib0090_tuning_table;
2319 if (state->identity.p1g)
2320 tune = dib0090_p1g_tuning_table;
Olivier Grenie03245a52009-12-04 13:27:57 -03002321
Olivier Grenie28fafca2011-01-04 04:27:11 -03002322 tmp = (state->identity.version >> 5) & 0x7;
2323
2324 if (state->identity.in_soc) {
2325 if (state->config->force_cband_input) { /* Use the CBAND input for all band */
2326 if (state->current_band & BAND_CBAND || state->current_band & BAND_FM || state->current_band & BAND_VHF
2327 || state->current_band & BAND_UHF) {
2328 state->current_band = BAND_CBAND;
Olivier Grenie6724a2f2011-08-05 13:49:33 -03002329 if (state->config->is_dib7090e)
2330 tune = dib0090_tuning_table_cband_7090e_sensitivity;
2331 else
2332 tune = dib0090_tuning_table_cband_7090;
Olivier Grenie28fafca2011-01-04 04:27:11 -03002333 }
2334 } else { /* Use the CBAND input for all band under UHF */
2335 if (state->current_band & BAND_CBAND || state->current_band & BAND_FM || state->current_band & BAND_VHF) {
2336 state->current_band = BAND_CBAND;
Olivier Grenie6724a2f2011-08-05 13:49:33 -03002337 if (state->config->is_dib7090e)
2338 tune = dib0090_tuning_table_cband_7090e_sensitivity;
2339 else
2340 tune = dib0090_tuning_table_cband_7090;
Olivier Grenie28fafca2011-01-04 04:27:11 -03002341 }
2342 }
2343 } else
2344 if (tmp == 0x4 || tmp == 0x7) {
2345 /* CBAND tuner version for VHF */
2346 if (state->current_band == BAND_FM || state->current_band == BAND_CBAND || state->current_band == BAND_VHF) {
2347 state->current_band = BAND_CBAND; /* Force CBAND */
2348
2349 tune = dib0090_tuning_table_fm_vhf_on_cband;
2350 if (state->identity.p1g)
2351 tune = dib0090_p1g_tuning_table_fm_vhf_on_cband;
2352 }
2353 }
2354
2355 pll = dib0090_pll_table;
2356 if (state->identity.p1g)
2357 pll = dib0090_p1g_pll_table;
2358
2359 /* Look for the interval */
2360 while (state->rf_request > tune->max_freq)
2361 tune++;
2362 while (state->rf_request > pll->max_freq)
2363 pll++;
2364
2365 state->current_tune_table_index = tune;
2366 state->current_pll_table_index = pll;
2367
Olivier Grenie03245a52009-12-04 13:27:57 -03002368 dib0090_write_reg(state, 0x0b, 0xb800 | (tune->switch_trim));
2369
Olivier Grenie28fafca2011-01-04 04:27:11 -03002370 VCOF_kHz = (pll->hfdiv * state->rf_request) * 2;
Olivier Grenie03245a52009-12-04 13:27:57 -03002371
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002372 FREF = state->config->io.clock_khz;
Olivier Grenie28fafca2011-01-04 04:27:11 -03002373 if (state->config->fref_clock_ratio != 0)
2374 FREF /= state->config->fref_clock_ratio;
Olivier Grenie03245a52009-12-04 13:27:57 -03002375
Olivier Grenie03245a52009-12-04 13:27:57 -03002376 FBDiv = (VCOF_kHz / pll->topresc / FREF);
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002377 Rest = (VCOF_kHz / pll->topresc) - FBDiv * FREF;
Olivier Grenie03245a52009-12-04 13:27:57 -03002378
2379 if (Rest < LPF)
2380 Rest = 0;
2381 else if (Rest < 2 * LPF)
2382 Rest = 2 * LPF;
2383 else if (Rest > (FREF - LPF)) {
2384 Rest = 0;
2385 FBDiv += 1;
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002386 } else if (Rest > (FREF - 2 * LPF))
Olivier Grenie03245a52009-12-04 13:27:57 -03002387 Rest = FREF - 2 * LPF;
2388 Rest = (Rest * 6528) / (FREF / 10);
Olivier Grenie28fafca2011-01-04 04:27:11 -03002389 state->rest = Rest;
2390
2391 /* external loop filter, otherwise:
2392 * lo5 = (0 << 15) | (0 << 12) | (0 << 11) | (3 << 9) | (4 << 6) | (3 << 4) | 4;
2393 * lo6 = 0x0e34 */
2394
2395 if (Rest == 0) {
2396 if (pll->vco_band)
2397 lo5 = 0x049f;
Olivier Grenie28fafca2011-01-04 04:27:11 -03002398 else
2399 lo5 = 0x041f;
2400 } else {
2401 if (pll->vco_band)
2402 lo5 = 0x049e;
2403 else if (state->config->analog_output)
2404 lo5 = 0x041d;
2405 else
2406 lo5 = 0x041c;
2407 }
2408
2409 if (state->identity.p1g) { /* Bias is done automatically in P1G */
2410 if (state->identity.in_soc) {
2411 if (state->identity.version == SOC_8090_P1G_11R1)
2412 lo5 = 0x46f;
2413 else
2414 lo5 = 0x42f;
2415 } else
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002416 lo5 = 0x42c;
Olivier Grenie28fafca2011-01-04 04:27:11 -03002417 }
2418
2419 lo5 |= (pll->hfdiv_code << 11) | (pll->vco_band << 7); /* bit 15 is the split to the slave, we do not do it here */
2420
Olivier Grenie28fafca2011-01-04 04:27:11 -03002421 if (!state->config->io.pll_int_loop_filt) {
2422 if (state->identity.in_soc)
2423 lo6 = 0xff98;
2424 else if (state->identity.p1g || (Rest == 0))
2425 lo6 = 0xfff8;
2426 else
2427 lo6 = 0xff28;
2428 } else
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002429 lo6 = (state->config->io.pll_int_loop_filt << 3);
Olivier Grenie03245a52009-12-04 13:27:57 -03002430
2431 Den = 1;
2432
Olivier Grenie03245a52009-12-04 13:27:57 -03002433 if (Rest > 0) {
2434 if (state->config->analog_output)
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002435 lo6 |= (1 << 2) | 2;
Olivier Grenie28fafca2011-01-04 04:27:11 -03002436 else {
2437 if (state->identity.in_soc)
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002438 lo6 |= (1 << 2) | 2;
Olivier Grenie28fafca2011-01-04 04:27:11 -03002439 else
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002440 lo6 |= (1 << 2) | 2;
Olivier Grenie28fafca2011-01-04 04:27:11 -03002441 }
Olivier Grenie03245a52009-12-04 13:27:57 -03002442 Den = 255;
2443 }
Olivier Grenie03245a52009-12-04 13:27:57 -03002444 dib0090_write_reg(state, 0x15, (u16) FBDiv);
Olivier Grenie28fafca2011-01-04 04:27:11 -03002445 if (state->config->fref_clock_ratio != 0)
2446 dib0090_write_reg(state, 0x16, (Den << 8) | state->config->fref_clock_ratio);
2447 else
2448 dib0090_write_reg(state, 0x16, (Den << 8) | 1);
Olivier Grenie03245a52009-12-04 13:27:57 -03002449 dib0090_write_reg(state, 0x17, (u16) Rest);
Olivier Grenie03245a52009-12-04 13:27:57 -03002450 dib0090_write_reg(state, 0x19, lo5);
Olivier Grenie03245a52009-12-04 13:27:57 -03002451 dib0090_write_reg(state, 0x1c, lo6);
2452
2453 lo6 = tune->tuner_enable;
2454 if (state->config->analog_output)
2455 lo6 = (lo6 & 0xff9f) | 0x2;
2456
Olivier Grenie28fafca2011-01-04 04:27:11 -03002457 dib0090_write_reg(state, 0x24, lo6 | EN_LO | state->config->use_pwm_agc * EN_CRYSTAL);
Olivier Grenie03245a52009-12-04 13:27:57 -03002458
Olivier Grenie03245a52009-12-04 13:27:57 -03002459 }
Olivier Grenie03245a52009-12-04 13:27:57 -03002460
Olivier Grenie28fafca2011-01-04 04:27:11 -03002461 state->current_rf = state->rf_request;
2462 state->current_standard = state->fe->dtv_property_cache.delivery_system;
Olivier Grenie03245a52009-12-04 13:27:57 -03002463
2464 ret = 20;
Olivier Grenie28fafca2011-01-04 04:27:11 -03002465 state->calibrate = CAPTRIM_CAL; /* captrim serach now */
2466 }
Olivier Grenie03245a52009-12-04 13:27:57 -03002467
Olivier Grenie28fafca2011-01-04 04:27:11 -03002468 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 */
2469 const struct dib0090_wbd_slope *wbd = state->current_wbd_table;
Olivier Grenie03245a52009-12-04 13:27:57 -03002470
Olivier Grenie28fafca2011-01-04 04:27:11 -03002471 while (state->current_rf / 1000 > wbd->max_freq)
2472 wbd++;
Olivier Grenie03245a52009-12-04 13:27:57 -03002473
Olivier Grenie03245a52009-12-04 13:27:57 -03002474 dib0090_write_reg(state, 0x1e, 0x07ff);
Olivier Grenie28fafca2011-01-04 04:27:11 -03002475 dprintk("Final Captrim: %d", (u32) state->fcaptrim);
2476 dprintk("HFDIV code: %d", (u32) pll->hfdiv_code);
2477 dprintk("VCO = %d", (u32) pll->vco_band);
2478 dprintk("VCOF in kHz: %d ((%d*%d) << 1))", (u32) ((pll->hfdiv * state->rf_request) * 2), (u32) pll->hfdiv, (u32) state->rf_request);
2479 dprintk("REFDIV: %d, FREF: %d", (u32) 1, (u32) state->config->io.clock_khz);
2480 dprintk("FBDIV: %d, Rest: %d", (u32) dib0090_read_reg(state, 0x15), (u32) dib0090_read_reg(state, 0x17));
2481 dprintk("Num: %d, Den: %d, SD: %d", (u32) dib0090_read_reg(state, 0x17), (u32) (dib0090_read_reg(state, 0x16) >> 8),
2482 (u32) dib0090_read_reg(state, 0x1c) & 0x3);
Olivier Grenie03245a52009-12-04 13:27:57 -03002483
Olivier Grenie28fafca2011-01-04 04:27:11 -03002484#define WBD 0x781 /* 1 1 1 1 0000 0 0 1 */
Olivier Grenie03245a52009-12-04 13:27:57 -03002485 c = 4;
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002486 i = 3;
Olivier Grenie28fafca2011-01-04 04:27:11 -03002487
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002488 if (wbd->wbd_gain != 0)
Olivier Grenie28fafca2011-01-04 04:27:11 -03002489 c = wbd->wbd_gain;
2490
Olivier Grenie28fafca2011-01-04 04:27:11 -03002491 state->wbdmux = (c << 13) | (i << 11) | (WBD | (state->config->use_pwm_agc << 1));
2492 dib0090_write_reg(state, 0x10, state->wbdmux);
2493
2494 if ((tune->tuner_enable == EN_CAB) && state->identity.p1g) {
2495 dprintk("P1G : The cable band is selected and lna_tune = %d", tune->lna_tune);
2496 dib0090_write_reg(state, 0x09, tune->lna_bias);
2497 dib0090_write_reg(state, 0x0b, 0xb800 | (tune->lna_tune << 6) | (tune->switch_trim));
2498 } else
2499 dib0090_write_reg(state, 0x09, (tune->lna_tune << 5) | tune->lna_bias);
2500
Olivier Grenie03245a52009-12-04 13:27:57 -03002501 dib0090_write_reg(state, 0x0c, tune->v2i);
2502 dib0090_write_reg(state, 0x0d, tune->mix);
2503 dib0090_write_reg(state, 0x0e, tune->load);
Olivier Grenie28fafca2011-01-04 04:27:11 -03002504 *tune_state = CT_TUNER_STEP_1;
Olivier Grenie03245a52009-12-04 13:27:57 -03002505
Olivier Grenie28fafca2011-01-04 04:27:11 -03002506 } else if (*tune_state == CT_TUNER_STEP_1) {
Olivier Grenie03245a52009-12-04 13:27:57 -03002507 /* initialize the lt gain register */
2508 state->rf_lt_def = 0x7c00;
Olivier Grenie03245a52009-12-04 13:27:57 -03002509
2510 dib0090_set_bandwidth(state);
2511 state->tuner_is_tuned = 1;
Olivier Grenie28fafca2011-01-04 04:27:11 -03002512
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002513 state->calibrate |= WBD_CAL;
2514 state->calibrate |= TEMP_CAL;
Olivier Grenie03245a52009-12-04 13:27:57 -03002515 *tune_state = CT_TUNER_STOP;
2516 } else
2517 ret = FE_CALLBACK_TIME_NEVER;
2518 return ret;
2519}
2520
2521static int dib0090_release(struct dvb_frontend *fe)
2522{
2523 kfree(fe->tuner_priv);
2524 fe->tuner_priv = NULL;
2525 return 0;
2526}
2527
2528enum frontend_tune_state dib0090_get_tune_state(struct dvb_frontend *fe)
2529{
2530 struct dib0090_state *state = fe->tuner_priv;
2531
2532 return state->tune_state;
2533}
Olivier Grenie28fafca2011-01-04 04:27:11 -03002534
Olivier Grenie03245a52009-12-04 13:27:57 -03002535EXPORT_SYMBOL(dib0090_get_tune_state);
2536
2537int dib0090_set_tune_state(struct dvb_frontend *fe, enum frontend_tune_state tune_state)
2538{
2539 struct dib0090_state *state = fe->tuner_priv;
2540
2541 state->tune_state = tune_state;
2542 return 0;
2543}
Olivier Grenie28fafca2011-01-04 04:27:11 -03002544
Olivier Grenie03245a52009-12-04 13:27:57 -03002545EXPORT_SYMBOL(dib0090_set_tune_state);
2546
2547static int dib0090_get_frequency(struct dvb_frontend *fe, u32 * frequency)
2548{
2549 struct dib0090_state *state = fe->tuner_priv;
2550
2551 *frequency = 1000 * state->current_rf;
2552 return 0;
2553}
2554
Mauro Carvalho Chehab14d24d12011-12-24 12:24:33 -03002555static int dib0090_set_params(struct dvb_frontend *fe)
Olivier Grenie03245a52009-12-04 13:27:57 -03002556{
2557 struct dib0090_state *state = fe->tuner_priv;
Olivier Grenie28fafca2011-01-04 04:27:11 -03002558 u32 ret;
Olivier Grenie03245a52009-12-04 13:27:57 -03002559
2560 state->tune_state = CT_TUNER_START;
2561
2562 do {
2563 ret = dib0090_tune(fe);
Mauro Carvalho Chehab0de04ca2014-07-04 14:15:36 -03002564 if (ret == FE_CALLBACK_TIME_NEVER)
Olivier Grenie03245a52009-12-04 13:27:57 -03002565 break;
Mauro Carvalho Chehab0de04ca2014-07-04 14:15:36 -03002566
2567 /*
2568 * Despite dib0090_tune returns time at a 0.1 ms range,
2569 * the actual sleep time depends on CONFIG_HZ. The worse case
2570 * is when CONFIG_HZ=100. In such case, the minimum granularity
2571 * is 10ms. On some real field tests, the tuner sometimes don't
2572 * lock when this timer is lower than 10ms. So, enforce a 10ms
2573 * granularity and use usleep_range() instead of msleep().
2574 */
2575 ret = 10 * (ret + 99)/100;
2576 usleep_range(ret * 1000, (ret + 1) * 1000);
Olivier Grenie03245a52009-12-04 13:27:57 -03002577 } while (state->tune_state != CT_TUNER_STOP);
2578
2579 return 0;
2580}
2581
2582static const struct dvb_tuner_ops dib0090_ops = {
2583 .info = {
2584 .name = "DiBcom DiB0090",
2585 .frequency_min = 45000000,
2586 .frequency_max = 860000000,
2587 .frequency_step = 1000,
2588 },
2589 .release = dib0090_release,
2590
2591 .init = dib0090_wakeup,
2592 .sleep = dib0090_sleep,
2593 .set_params = dib0090_set_params,
2594 .get_frequency = dib0090_get_frequency,
2595};
2596
Olivier Grenie28fafca2011-01-04 04:27:11 -03002597static const struct dvb_tuner_ops dib0090_fw_ops = {
2598 .info = {
2599 .name = "DiBcom DiB0090",
2600 .frequency_min = 45000000,
2601 .frequency_max = 860000000,
2602 .frequency_step = 1000,
2603 },
2604 .release = dib0090_release,
2605
2606 .init = NULL,
2607 .sleep = NULL,
2608 .set_params = NULL,
2609 .get_frequency = NULL,
2610};
2611
2612static const struct dib0090_wbd_slope dib0090_wbd_table_default[] = {
2613 {470, 0, 250, 0, 100, 4},
2614 {860, 51, 866, 21, 375, 4},
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002615 {1700, 0, 800, 0, 850, 4},
2616 {2900, 0, 250, 0, 100, 6},
Olivier Grenie28fafca2011-01-04 04:27:11 -03002617 {0xFFFF, 0, 0, 0, 0, 0},
2618};
2619
Olivier Grenie03245a52009-12-04 13:27:57 -03002620struct dvb_frontend *dib0090_register(struct dvb_frontend *fe, struct i2c_adapter *i2c, const struct dib0090_config *config)
2621{
2622 struct dib0090_state *st = kzalloc(sizeof(struct dib0090_state), GFP_KERNEL);
2623 if (st == NULL)
2624 return NULL;
2625
2626 st->config = config;
2627 st->i2c = i2c;
2628 st->fe = fe;
Patrick Boettcher79fcce32011-08-03 12:08:21 -03002629 mutex_init(&st->i2c_buffer_lock);
Olivier Grenie03245a52009-12-04 13:27:57 -03002630 fe->tuner_priv = st;
2631
Olivier Grenie28fafca2011-01-04 04:27:11 -03002632 if (config->wbd == NULL)
2633 st->current_wbd_table = dib0090_wbd_table_default;
2634 else
2635 st->current_wbd_table = config->wbd;
2636
Olivier Grenie03245a52009-12-04 13:27:57 -03002637 if (dib0090_reset(fe) != 0)
2638 goto free_mem;
2639
2640 printk(KERN_INFO "DiB0090: successfully identified\n");
2641 memcpy(&fe->ops.tuner_ops, &dib0090_ops, sizeof(struct dvb_tuner_ops));
2642
2643 return fe;
2644 free_mem:
2645 kfree(st);
2646 fe->tuner_priv = NULL;
2647 return NULL;
2648}
Olivier Grenie28fafca2011-01-04 04:27:11 -03002649
Olivier Grenie03245a52009-12-04 13:27:57 -03002650EXPORT_SYMBOL(dib0090_register);
2651
Olivier Grenie28fafca2011-01-04 04:27:11 -03002652struct dvb_frontend *dib0090_fw_register(struct dvb_frontend *fe, struct i2c_adapter *i2c, const struct dib0090_config *config)
2653{
2654 struct dib0090_fw_state *st = kzalloc(sizeof(struct dib0090_fw_state), GFP_KERNEL);
2655 if (st == NULL)
2656 return NULL;
2657
2658 st->config = config;
2659 st->i2c = i2c;
2660 st->fe = fe;
Patrick Boettcher79fcce32011-08-03 12:08:21 -03002661 mutex_init(&st->i2c_buffer_lock);
Olivier Grenie28fafca2011-01-04 04:27:11 -03002662 fe->tuner_priv = st;
2663
2664 if (dib0090_fw_reset_digital(fe, st->config) != 0)
2665 goto free_mem;
2666
2667 dprintk("DiB0090 FW: successfully identified");
2668 memcpy(&fe->ops.tuner_ops, &dib0090_fw_ops, sizeof(struct dvb_tuner_ops));
2669
2670 return fe;
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002671free_mem:
Olivier Grenie28fafca2011-01-04 04:27:11 -03002672 kfree(st);
2673 fe->tuner_priv = NULL;
2674 return NULL;
2675}
Olivier Grenie28fafca2011-01-04 04:27:11 -03002676EXPORT_SYMBOL(dib0090_fw_register);
2677
Patrick Boettcher99e44da2016-01-24 12:56:58 -02002678MODULE_AUTHOR("Patrick Boettcher <patrick.boettcher@posteo.de>");
2679MODULE_AUTHOR("Olivier Grenie <olivier.grenie@parrot.com>");
Olivier Grenie03245a52009-12-04 13:27:57 -03002680MODULE_DESCRIPTION("Driver for the DiBcom 0090 base-band RF Tuner");
2681MODULE_LICENSE("GPL");