blob: 14c403254fe06dbf0a7e0193d248ab1d7b9a158a [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
Mauro Carvalho Chehabcf47fac2016-06-24 11:12:17 -0300800#if 0
801/* Currently unused */
Olivier Grenieaedabf72012-12-31 10:38:44 -0300802static const u16 bb_ramp_pwm_boost[] = {
803 550, /* max BB gain in 10th of dB */
804 8, /* ramp_slope = 1dB of gain -> clock_ticks_per_db = clk_khz / ramp_slope -> BB_RAMP2 */
805 440,
806 (2 << 9) | 0, /* BB_RAMP3 = 26dB */
807 (0 << 9) | 208, /* BB_RAMP4 */
808 (2 << 9) | 208, /* BB_RAMP5 = 29dB */
809 (0 << 9) | 440, /* BB_RAMP6 */
Olivier Grenie28fafca2011-01-04 04:27:11 -0300810};
Mauro Carvalho Chehabcf47fac2016-06-24 11:12:17 -0300811#endif
Olivier Grenie28fafca2011-01-04 04:27:11 -0300812
Olivier Grenie03245a52009-12-04 13:27:57 -0300813static const u16 rf_ramp_pwm_cband[] = {
Olivier Grenieaedabf72012-12-31 10:38:44 -0300814 314, /* max RF gain in 10th of dB */
815 33, /* ramp_slope = 1dB of gain -> clock_ticks_per_db = clk_khz / ramp_slope -> RF_RAMP2 */
816 1023, /* ramp_max = maximum X used on the ramp */
817 (8 << 10) | 743, /* RF_RAMP3, LNA 1 = 0dB */
818 (0 << 10) | 1023, /* RF_RAMP4, LNA 1 */
819 (15 << 10) | 469, /* RF_RAMP5, LNA 2 = 0dB */
820 (0 << 10) | 742, /* RF_RAMP6, LNA 2 */
821 (9 << 10) | 234, /* RF_RAMP7, LNA 3 = 0dB */
822 (0 << 10) | 468, /* RF_RAMP8, LNA 3 */
823 (9 << 10) | 0, /* GAIN_4_1, LNA 4 = 0dB */
824 (0 << 10) | 233, /* GAIN_4_2, LNA 4 */
Olivier Grenie03245a52009-12-04 13:27:57 -0300825};
826
827static const u16 rf_ramp_pwm_vhf[] = {
Olivier Grenieaedabf72012-12-31 10:38:44 -0300828 398, /* max RF gain in 10th of dB */
829 24, /* ramp_slope = 1dB of gain -> clock_ticks_per_db = clk_khz / ramp_slope -> RF_RAMP2 */
830 954, /* ramp_max = maximum X used on the ramp */
831 (7 << 10) | 0, /* RF_RAMP3, LNA 1 = 13.2dB */
832 (0 << 10) | 290, /* RF_RAMP4, LNA 1 */
833 (16 << 10) | 699, /* RF_RAMP5, LNA 2 = 10.5dB */
834 (0 << 10) | 954, /* RF_RAMP6, LNA 2 */
835 (17 << 10) | 580, /* RF_RAMP7, LNA 3 = 5dB */
836 (0 << 10) | 699, /* RF_RAMP8, LNA 3 */
837 (7 << 10) | 290, /* GAIN_4_1, LNA 4 = 12.5dB */
838 (0 << 10) | 580, /* GAIN_4_2, LNA 4 */
Olivier Grenie03245a52009-12-04 13:27:57 -0300839};
840
841static const u16 rf_ramp_pwm_uhf[] = {
Olivier Grenieaedabf72012-12-31 10:38:44 -0300842 398, /* max RF gain in 10th of dB */
843 24, /* ramp_slope = 1dB of gain -> clock_ticks_per_db = clk_khz / ramp_slope -> RF_RAMP2 */
844 954, /* ramp_max = maximum X used on the ramp */
845 (7 << 10) | 0, /* RF_RAMP3, LNA 1 = 13.2dB */
846 (0 << 10) | 290, /* RF_RAMP4, LNA 1 */
847 (16 << 10) | 699, /* RF_RAMP5, LNA 2 = 10.5dB */
848 (0 << 10) | 954, /* RF_RAMP6, LNA 2 */
849 (17 << 10) | 580, /* RF_RAMP7, LNA 3 = 5dB */
850 (0 << 10) | 699, /* RF_RAMP8, LNA 3 */
851 (7 << 10) | 290, /* GAIN_4_1, LNA 4 = 12.5dB */
852 (0 << 10) | 580, /* GAIN_4_2, LNA 4 */
Olivier Grenie03245a52009-12-04 13:27:57 -0300853};
854
Mauro Carvalho Chehabcf47fac2016-06-24 11:12:17 -0300855#if 0
856/* Currently unused */
Olivier Grenieaedabf72012-12-31 10:38:44 -0300857static const u16 rf_ramp_pwm_sband[] = {
858 253, /* max RF gain in 10th of dB */
859 38, /* ramp_slope = 1dB of gain -> clock_ticks_per_db = clk_khz / ramp_slope -> RF_RAMP2 */
860 961,
861 (4 << 10) | 0, /* RF_RAMP3, LNA 1 = 14.1dB */
862 (0 << 10) | 508, /* RF_RAMP4, LNA 1 */
863 (9 << 10) | 508, /* RF_RAMP5, LNA 2 = 11.2dB */
864 (0 << 10) | 961, /* RF_RAMP6, LNA 2 */
865 (0 << 10) | 0, /* RF_RAMP7, LNA 3 = 0dB */
866 (0 << 10) | 0, /* RF_RAMP8, LNA 3 */
867 (0 << 10) | 0, /* GAIN_4_1, LNA 4 = 0dB */
868 (0 << 10) | 0, /* GAIN_4_2, LNA 4 */
Olivier Grenie03245a52009-12-04 13:27:57 -0300869};
Mauro Carvalho Chehabcf47fac2016-06-24 11:12:17 -0300870#endif
Olivier Grenie03245a52009-12-04 13:27:57 -0300871
872struct slope {
Olivier Grenie28fafca2011-01-04 04:27:11 -0300873 s16 range;
874 s16 slope;
Olivier Grenie03245a52009-12-04 13:27:57 -0300875};
876static u16 slopes_to_scale(const struct slope *slopes, u8 num, s16 val)
877{
878 u8 i;
879 u16 rest;
880 u16 ret = 0;
881 for (i = 0; i < num; i++) {
882 if (val > slopes[i].range)
883 rest = slopes[i].range;
884 else
885 rest = val;
886 ret += (rest * slopes[i].slope) / slopes[i].range;
887 val -= rest;
888 }
889 return ret;
890}
891
892static const struct slope dib0090_wbd_slopes[3] = {
893 {66, 120}, /* -64,-52: offset - 65 */
894 {600, 170}, /* -52,-35: 65 - 665 */
895 {170, 250}, /* -45,-10: 665 - 835 */
896};
897
898static s16 dib0090_wbd_to_db(struct dib0090_state *state, u16 wbd)
899{
900 wbd &= 0x3ff;
901 if (wbd < state->wbd_offset)
902 wbd = 0;
903 else
904 wbd -= state->wbd_offset;
905 /* -64dB is the floor */
906 return -640 + (s16) slopes_to_scale(dib0090_wbd_slopes, ARRAY_SIZE(dib0090_wbd_slopes), wbd);
907}
908
909static void dib0090_wbd_target(struct dib0090_state *state, u32 rf)
910{
911 u16 offset = 250;
912
913 /* TODO : DAB digital N+/-1 interferer perfs : offset = 10 */
914
915 if (state->current_band == BAND_VHF)
916 offset = 650;
917#ifndef FIRMWARE_FIREFLY
918 if (state->current_band == BAND_VHF)
919 offset = state->config->wbd_vhf_offset;
920 if (state->current_band == BAND_CBAND)
921 offset = state->config->wbd_cband_offset;
922#endif
923
924 state->wbd_target = dib0090_wbd_to_db(state, state->wbd_offset + offset);
925 dprintk("wbd-target: %d dB", (u32) state->wbd_target);
926}
927
928static const int gain_reg_addr[4] = {
929 0x08, 0x0a, 0x0f, 0x01
930};
931
932static void dib0090_gain_apply(struct dib0090_state *state, s16 gain_delta, s16 top_delta, u8 force)
933{
934 u16 rf, bb, ref;
935 u16 i, v, gain_reg[4] = { 0 }, gain;
936 const u16 *g;
937
938 if (top_delta < -511)
939 top_delta = -511;
940 if (top_delta > 511)
941 top_delta = 511;
942
943 if (force) {
944 top_delta *= (1 << WBD_ALPHA);
945 gain_delta *= (1 << GAIN_ALPHA);
946 }
947
948 if (top_delta >= ((s16) (state->rf_ramp[0] << WBD_ALPHA) - state->rf_gain_limit)) /* overflow */
949 state->rf_gain_limit = state->rf_ramp[0] << WBD_ALPHA;
950 else
951 state->rf_gain_limit += top_delta;
952
953 if (state->rf_gain_limit < 0) /*underflow */
954 state->rf_gain_limit = 0;
955
956 /* use gain as a temporary variable and correct current_gain */
957 gain = ((state->rf_gain_limit >> WBD_ALPHA) + state->bb_ramp[0]) << GAIN_ALPHA;
958 if (gain_delta >= ((s16) gain - state->current_gain)) /* overflow */
959 state->current_gain = gain;
960 else
961 state->current_gain += gain_delta;
962 /* cannot be less than 0 (only if gain_delta is less than 0 we can have current_gain < 0) */
963 if (state->current_gain < 0)
964 state->current_gain = 0;
965
966 /* now split total gain to rf and bb gain */
967 gain = state->current_gain >> GAIN_ALPHA;
968
969 /* requested gain is bigger than rf gain limit - ACI/WBD adjustment */
970 if (gain > (state->rf_gain_limit >> WBD_ALPHA)) {
971 rf = state->rf_gain_limit >> WBD_ALPHA;
972 bb = gain - rf;
973 if (bb > state->bb_ramp[0])
974 bb = state->bb_ramp[0];
975 } else { /* high signal level -> all gains put on RF */
976 rf = gain;
977 bb = 0;
978 }
979
980 state->gain[0] = rf;
981 state->gain[1] = bb;
982
983 /* software ramp */
984 /* Start with RF gains */
985 g = state->rf_ramp + 1; /* point on RF LNA1 max gain */
986 ref = rf;
987 for (i = 0; i < 7; i++) { /* Go over all amplifiers => 5RF amps + 2 BB amps = 7 amps */
988 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 */
989 v = 0; /* force the gain to write for the current amp to be null */
990 else if (ref >= g[1]) /* Gain to set is higher than the high working point of this amp */
991 v = g[2]; /* force this amp to be full gain */
992 else /* compute the value to set to this amp because we are somewhere in his range */
993 v = ((ref - (g[1] - g[0])) * g[2]) / g[0];
994
995 if (i == 0) /* LNA 1 reg mapping */
996 gain_reg[0] = v;
997 else if (i == 1) /* LNA 2 reg mapping */
998 gain_reg[0] |= v << 7;
999 else if (i == 2) /* LNA 3 reg mapping */
1000 gain_reg[1] = v;
1001 else if (i == 3) /* LNA 4 reg mapping */
1002 gain_reg[1] |= v << 7;
1003 else if (i == 4) /* CBAND LNA reg mapping */
1004 gain_reg[2] = v | state->rf_lt_def;
1005 else if (i == 5) /* BB gain 1 reg mapping */
1006 gain_reg[3] = v << 3;
1007 else if (i == 6) /* BB gain 2 reg mapping */
1008 gain_reg[3] |= v << 8;
1009
1010 g += 3; /* go to next gain bloc */
1011
1012 /* When RF is finished, start with BB */
1013 if (i == 4) {
1014 g = state->bb_ramp + 1; /* point on BB gain 1 max gain */
1015 ref = bb;
1016 }
1017 }
1018 gain_reg[3] |= state->bb_1_def;
1019 gain_reg[3] |= ((bb % 10) * 100) / 125;
1020
1021#ifdef DEBUG_AGC
1022 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,
1023 gain_reg[0], gain_reg[1], gain_reg[2], gain_reg[3]);
1024#endif
1025
1026 /* Write the amplifier regs */
1027 for (i = 0; i < 4; i++) {
1028 v = gain_reg[i];
1029 if (force || state->gain_reg[i] != v) {
1030 state->gain_reg[i] = v;
1031 dib0090_write_reg(state, gain_reg_addr[i], v);
1032 }
1033 }
1034}
1035
1036static void dib0090_set_boost(struct dib0090_state *state, int onoff)
1037{
1038 state->bb_1_def &= 0xdfff;
1039 state->bb_1_def |= onoff << 13;
1040}
1041
1042static void dib0090_set_rframp(struct dib0090_state *state, const u16 * cfg)
1043{
1044 state->rf_ramp = cfg;
1045}
1046
1047static void dib0090_set_rframp_pwm(struct dib0090_state *state, const u16 * cfg)
1048{
1049 state->rf_ramp = cfg;
1050
1051 dib0090_write_reg(state, 0x2a, 0xffff);
1052
1053 dprintk("total RF gain: %ddB, step: %d", (u32) cfg[0], dib0090_read_reg(state, 0x2a));
1054
1055 dib0090_write_regs(state, 0x2c, cfg + 3, 6);
1056 dib0090_write_regs(state, 0x3e, cfg + 9, 2);
1057}
1058
1059static void dib0090_set_bbramp(struct dib0090_state *state, const u16 * cfg)
1060{
1061 state->bb_ramp = cfg;
1062 dib0090_set_boost(state, cfg[0] > 500); /* we want the boost if the gain is higher that 50dB */
1063}
1064
1065static void dib0090_set_bbramp_pwm(struct dib0090_state *state, const u16 * cfg)
1066{
1067 state->bb_ramp = cfg;
1068
1069 dib0090_set_boost(state, cfg[0] > 500); /* we want the boost if the gain is higher that 50dB */
1070
1071 dib0090_write_reg(state, 0x33, 0xffff);
1072 dprintk("total BB gain: %ddB, step: %d", (u32) cfg[0], dib0090_read_reg(state, 0x33));
1073 dib0090_write_regs(state, 0x35, cfg + 3, 4);
1074}
1075
1076void dib0090_pwm_gain_reset(struct dvb_frontend *fe)
1077{
1078 struct dib0090_state *state = fe->tuner_priv;
Olivier Grenieaedabf72012-12-31 10:38:44 -03001079 u16 *bb_ramp = (u16 *)&bb_ramp_pwm_normal; /* default baseband config */
1080 u16 *rf_ramp = NULL;
1081 u8 en_pwm_rf_mux = 1;
Olivier Grenie03245a52009-12-04 13:27:57 -03001082
Olivier Grenieaedabf72012-12-31 10:38:44 -03001083 /* reset the AGC */
Olivier Grenie03245a52009-12-04 13:27:57 -03001084 if (state->config->use_pwm_agc) {
Olivier Grenie03245a52009-12-04 13:27:57 -03001085 if (state->current_band == BAND_CBAND) {
Olivier Grenie28fafca2011-01-04 04:27:11 -03001086 if (state->identity.in_soc) {
Olivier Grenieaedabf72012-12-31 10:38:44 -03001087 bb_ramp = (u16 *)&bb_ramp_pwm_normal_socs;
Olivier Grenie28fafca2011-01-04 04:27:11 -03001088 if (state->identity.version == SOC_8090_P1G_11R1 || state->identity.version == SOC_8090_P1G_21R1)
Olivier Grenieaedabf72012-12-31 10:38:44 -03001089 rf_ramp = (u16 *)&rf_ramp_pwm_cband_8090;
1090 else if (state->identity.version == SOC_7090_P1G_11R1 || state->identity.version == SOC_7090_P1G_21R1) {
Olivier Grenie6724a2f2011-08-05 13:49:33 -03001091 if (state->config->is_dib7090e) {
1092 if (state->rf_ramp == NULL)
Olivier Grenieaedabf72012-12-31 10:38:44 -03001093 rf_ramp = (u16 *)&rf_ramp_pwm_cband_7090e_sensitivity;
Olivier Grenie6724a2f2011-08-05 13:49:33 -03001094 else
Olivier Grenieaedabf72012-12-31 10:38:44 -03001095 rf_ramp = (u16 *)state->rf_ramp;
Olivier Grenie6724a2f2011-08-05 13:49:33 -03001096 } else
Olivier Grenieaedabf72012-12-31 10:38:44 -03001097 rf_ramp = (u16 *)&rf_ramp_pwm_cband_7090p;
Olivier Grenie6724a2f2011-08-05 13:49:33 -03001098 }
Olivier Grenieaedabf72012-12-31 10:38:44 -03001099 } else
1100 rf_ramp = (u16 *)&rf_ramp_pwm_cband;
Olivier Grenie03245a52009-12-04 13:27:57 -03001101 } else
Olivier Grenie03245a52009-12-04 13:27:57 -03001102
Olivier Grenieaedabf72012-12-31 10:38:44 -03001103 if (state->current_band == BAND_VHF) {
1104 if (state->identity.in_soc) {
1105 bb_ramp = (u16 *)&bb_ramp_pwm_normal_socs;
1106 /* rf_ramp = &rf_ramp_pwm_vhf_socs; */ /* TODO */
1107 } else
1108 rf_ramp = (u16 *)&rf_ramp_pwm_vhf;
1109 } else if (state->current_band == BAND_UHF) {
1110 if (state->identity.in_soc) {
1111 bb_ramp = (u16 *)&bb_ramp_pwm_normal_socs;
1112 if (state->identity.version == SOC_8090_P1G_11R1 || state->identity.version == SOC_8090_P1G_21R1)
1113 rf_ramp = (u16 *)&rf_ramp_pwm_uhf_8090;
1114 else if (state->identity.version == SOC_7090_P1G_11R1 || state->identity.version == SOC_7090_P1G_21R1)
1115 rf_ramp = (u16 *)&rf_ramp_pwm_uhf_7090;
1116 } else
1117 rf_ramp = (u16 *)&rf_ramp_pwm_uhf;
1118 }
1119 if (rf_ramp)
1120 dib0090_set_rframp_pwm(state, rf_ramp);
1121 dib0090_set_bbramp_pwm(state, bb_ramp);
1122
1123 /* activate the ramp generator using PWM control */
Mauro Carvalho Chehab57bcbde2016-02-27 07:51:09 -03001124 if (state->rf_ramp)
Mauro Carvalho Chehabe76bea92016-02-22 11:12:41 -03001125 dprintk("ramp RF gain = %d BAND = %s version = %d",
1126 state->rf_ramp[0],
1127 (state->current_band == BAND_CBAND) ? "CBAND" : "NOT CBAND",
1128 state->identity.version & 0x1f);
Olivier Grenieaedabf72012-12-31 10:38:44 -03001129
Hans Verkuil5848adb2016-04-15 12:35:33 -03001130 if (rf_ramp && ((state->rf_ramp && state->rf_ramp[0] == 0) ||
Mauro Carvalho Chehabe76bea92016-02-22 11:12:41 -03001131 (state->current_band == BAND_CBAND &&
1132 (state->identity.version & 0x1f) <= P1D_E_F))) {
Olivier Grenieaedabf72012-12-31 10:38:44 -03001133 dprintk("DE-Engage mux for direct gain reg control");
1134 en_pwm_rf_mux = 0;
1135 } else
1136 dprintk("Engage mux for PWM control");
1137
1138 dib0090_write_reg(state, 0x32, (en_pwm_rf_mux << 12) | (en_pwm_rf_mux << 11));
1139
1140 /* Set fast servo cutoff to start AGC; 0 = 1KHz ; 1 = 50Hz ; 2 = 150Hz ; 3 = 50KHz ; 4 = servo fast*/
1141 if (state->identity.version == SOC_7090_P1G_11R1 || state->identity.version == SOC_7090_P1G_21R1)
1142 dib0090_write_reg(state, 0x04, 3);
Olivier Grenie03245a52009-12-04 13:27:57 -03001143 else
Olivier Grenieaedabf72012-12-31 10:38:44 -03001144 dib0090_write_reg(state, 0x04, 1);
1145 dib0090_write_reg(state, 0x39, (1 << 10)); /* 0 gain by default */
Olivier Grenie03245a52009-12-04 13:27:57 -03001146 }
1147}
Olivier Grenie03245a52009-12-04 13:27:57 -03001148EXPORT_SYMBOL(dib0090_pwm_gain_reset);
Olivier Grenie9c783032009-12-07 07:49:40 -03001149
Olivier Grenie2e802862011-08-05 10:39:15 -03001150void dib0090_set_dc_servo(struct dvb_frontend *fe, u8 DC_servo_cutoff)
1151{
1152 struct dib0090_state *state = fe->tuner_priv;
1153 if (DC_servo_cutoff < 4)
1154 dib0090_write_reg(state, 0x04, DC_servo_cutoff);
1155}
1156EXPORT_SYMBOL(dib0090_set_dc_servo);
1157
Olivier Grenie28fafca2011-01-04 04:27:11 -03001158static u32 dib0090_get_slow_adc_val(struct dib0090_state *state)
1159{
1160 u16 adc_val = dib0090_read_reg(state, 0x1d);
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001161 if (state->identity.in_soc)
Olivier Grenie28fafca2011-01-04 04:27:11 -03001162 adc_val >>= 2;
Olivier Grenie28fafca2011-01-04 04:27:11 -03001163 return adc_val;
1164}
1165
Olivier Grenie03245a52009-12-04 13:27:57 -03001166int dib0090_gain_control(struct dvb_frontend *fe)
1167{
1168 struct dib0090_state *state = fe->tuner_priv;
1169 enum frontend_tune_state *tune_state = &state->tune_state;
1170 int ret = 10;
1171
1172 u16 wbd_val = 0;
1173 u8 apply_gain_immediatly = 1;
1174 s16 wbd_error = 0, adc_error = 0;
1175
1176 if (*tune_state == CT_AGC_START) {
1177 state->agc_freeze = 0;
1178 dib0090_write_reg(state, 0x04, 0x0);
1179
1180#ifdef CONFIG_BAND_SBAND
1181 if (state->current_band == BAND_SBAND) {
1182 dib0090_set_rframp(state, rf_ramp_sband);
1183 dib0090_set_bbramp(state, bb_ramp_boost);
1184 } else
1185#endif
1186#ifdef CONFIG_BAND_VHF
Olivier Grenie28fafca2011-01-04 04:27:11 -03001187 if (state->current_band == BAND_VHF && !state->identity.p1g) {
Olivier Grenieaedabf72012-12-31 10:38:44 -03001188 dib0090_set_rframp(state, rf_ramp_pwm_vhf);
1189 dib0090_set_bbramp(state, bb_ramp_pwm_normal);
Olivier Grenie03245a52009-12-04 13:27:57 -03001190 } else
1191#endif
1192#ifdef CONFIG_BAND_CBAND
Olivier Grenie28fafca2011-01-04 04:27:11 -03001193 if (state->current_band == BAND_CBAND && !state->identity.p1g) {
Olivier Grenieaedabf72012-12-31 10:38:44 -03001194 dib0090_set_rframp(state, rf_ramp_pwm_cband);
1195 dib0090_set_bbramp(state, bb_ramp_pwm_normal);
Olivier Grenie03245a52009-12-04 13:27:57 -03001196 } else
1197#endif
Olivier Grenie28fafca2011-01-04 04:27:11 -03001198 if ((state->current_band == BAND_CBAND || state->current_band == BAND_VHF) && state->identity.p1g) {
Olivier Grenieaedabf72012-12-31 10:38:44 -03001199 dib0090_set_rframp(state, rf_ramp_pwm_cband_7090p);
1200 dib0090_set_bbramp(state, bb_ramp_pwm_normal_socs);
Olivier Grenie28fafca2011-01-04 04:27:11 -03001201 } else {
Olivier Grenieaedabf72012-12-31 10:38:44 -03001202 dib0090_set_rframp(state, rf_ramp_pwm_uhf);
1203 dib0090_set_bbramp(state, bb_ramp_pwm_normal);
Olivier Grenie03245a52009-12-04 13:27:57 -03001204 }
1205
1206 dib0090_write_reg(state, 0x32, 0);
1207 dib0090_write_reg(state, 0x39, 0);
1208
1209 dib0090_wbd_target(state, state->current_rf);
1210
1211 state->rf_gain_limit = state->rf_ramp[0] << WBD_ALPHA;
1212 state->current_gain = ((state->rf_ramp[0] + state->bb_ramp[0]) / 2) << GAIN_ALPHA;
1213
1214 *tune_state = CT_AGC_STEP_0;
1215 } else if (!state->agc_freeze) {
Olivier Grenie28fafca2011-01-04 04:27:11 -03001216 s16 wbd = 0, i, cnt;
Olivier Grenie03245a52009-12-04 13:27:57 -03001217
1218 int adc;
Olivier Grenie28fafca2011-01-04 04:27:11 -03001219 wbd_val = dib0090_get_slow_adc_val(state);
Olivier Grenie03245a52009-12-04 13:27:57 -03001220
Olivier Grenie28fafca2011-01-04 04:27:11 -03001221 if (*tune_state == CT_AGC_STEP_0)
1222 cnt = 5;
1223 else
1224 cnt = 1;
1225
1226 for (i = 0; i < cnt; i++) {
1227 wbd_val = dib0090_get_slow_adc_val(state);
1228 wbd += dib0090_wbd_to_db(state, wbd_val);
1229 }
1230 wbd /= cnt;
Olivier Grenie03245a52009-12-04 13:27:57 -03001231 wbd_error = state->wbd_target - wbd;
1232
1233 if (*tune_state == CT_AGC_STEP_0) {
Olivier Grenie28fafca2011-01-04 04:27:11 -03001234 if (wbd_error < 0 && state->rf_gain_limit > 0 && !state->identity.p1g) {
Olivier Grenie03245a52009-12-04 13:27:57 -03001235#ifdef CONFIG_BAND_CBAND
1236 /* in case of CBAND tune reduce first the lt_gain2 before adjusting the RF gain */
1237 u8 ltg2 = (state->rf_lt_def >> 10) & 0x7;
1238 if (state->current_band == BAND_CBAND && ltg2) {
1239 ltg2 >>= 1;
1240 state->rf_lt_def &= ltg2 << 10; /* reduce in 3 steps from 7 to 0 */
1241 }
1242#endif
1243 } else {
1244 state->agc_step = 0;
1245 *tune_state = CT_AGC_STEP_1;
1246 }
1247 } else {
1248 /* calc the adc power */
1249 adc = state->config->get_adc_power(fe);
1250 adc = (adc * ((s32) 355774) + (((s32) 1) << 20)) >> 21; /* included in [0:-700] */
1251
1252 adc_error = (s16) (((s32) ADC_TARGET) - adc);
1253#ifdef CONFIG_STANDARD_DAB
1254 if (state->fe->dtv_property_cache.delivery_system == STANDARD_DAB)
Olivier Grenie28fafca2011-01-04 04:27:11 -03001255 adc_error -= 10;
Olivier Grenie03245a52009-12-04 13:27:57 -03001256#endif
1257#ifdef CONFIG_STANDARD_DVBT
1258 if (state->fe->dtv_property_cache.delivery_system == STANDARD_DVBT &&
Olivier Grenie28fafca2011-01-04 04:27:11 -03001259 (state->fe->dtv_property_cache.modulation == QAM_64 || state->fe->dtv_property_cache.modulation == QAM_16))
Olivier Grenie03245a52009-12-04 13:27:57 -03001260 adc_error += 60;
1261#endif
1262#ifdef CONFIG_SYS_ISDBT
1263 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 -03001264 0)
1265 &&
1266 ((state->fe->dtv_property_cache.layer[0].modulation ==
1267 QAM_64)
1268 || (state->fe->dtv_property_cache.
1269 layer[0].modulation == QAM_16)))
1270 ||
1271 ((state->fe->dtv_property_cache.layer[1].segment_count >
1272 0)
1273 &&
1274 ((state->fe->dtv_property_cache.layer[1].modulation ==
1275 QAM_64)
1276 || (state->fe->dtv_property_cache.
1277 layer[1].modulation == QAM_16)))
1278 ||
1279 ((state->fe->dtv_property_cache.layer[2].segment_count >
1280 0)
1281 &&
1282 ((state->fe->dtv_property_cache.layer[2].modulation ==
1283 QAM_64)
1284 || (state->fe->dtv_property_cache.
1285 layer[2].modulation == QAM_16)))
1286 )
1287 )
Olivier Grenie03245a52009-12-04 13:27:57 -03001288 adc_error += 60;
1289#endif
1290
1291 if (*tune_state == CT_AGC_STEP_1) { /* quickly go to the correct range of the ADC power */
1292 if (ABS(adc_error) < 50 || state->agc_step++ > 5) {
1293
1294#ifdef CONFIG_STANDARD_DAB
1295 if (state->fe->dtv_property_cache.delivery_system == STANDARD_DAB) {
1296 dib0090_write_reg(state, 0x02, (1 << 15) | (15 << 11) | (31 << 6) | (63)); /* cap value = 63 : narrow BB filter : Fc = 1.8MHz */
1297 dib0090_write_reg(state, 0x04, 0x0);
1298 } else
1299#endif
1300 {
1301 dib0090_write_reg(state, 0x02, (1 << 15) | (3 << 11) | (6 << 6) | (32));
1302 dib0090_write_reg(state, 0x04, 0x01); /*0 = 1KHz ; 1 = 150Hz ; 2 = 50Hz ; 3 = 50KHz ; 4 = servo fast */
1303 }
1304
1305 *tune_state = CT_AGC_STOP;
1306 }
1307 } else {
1308 /* everything higher than or equal to CT_AGC_STOP means tracking */
1309 ret = 100; /* 10ms interval */
1310 apply_gain_immediatly = 0;
1311 }
1312 }
1313#ifdef DEBUG_AGC
1314 dprintk
Olivier Grenie28fafca2011-01-04 04:27:11 -03001315 ("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 -03001316 (u32) *tune_state, (u32) adc, (u32) adc_error, (u32) wbd, (u32) wbd_error, (u32) wbd_val,
Olivier Grenie28fafca2011-01-04 04:27:11 -03001317 (u32) state->rf_gain_limit >> WBD_ALPHA, (s32) 200 + adc - (state->current_gain >> GAIN_ALPHA));
Olivier Grenie03245a52009-12-04 13:27:57 -03001318#endif
1319 }
1320
1321 /* apply gain */
1322 if (!state->agc_freeze)
1323 dib0090_gain_apply(state, adc_error, wbd_error, apply_gain_immediatly);
1324 return ret;
1325}
Olivier Grenie28fafca2011-01-04 04:27:11 -03001326
Olivier Grenie03245a52009-12-04 13:27:57 -03001327EXPORT_SYMBOL(dib0090_gain_control);
Olivier Grenie9c783032009-12-07 07:49:40 -03001328
Olivier Grenie03245a52009-12-04 13:27:57 -03001329void dib0090_get_current_gain(struct dvb_frontend *fe, u16 * rf, u16 * bb, u16 * rf_gain_limit, u16 * rflt)
1330{
1331 struct dib0090_state *state = fe->tuner_priv;
1332 if (rf)
1333 *rf = state->gain[0];
1334 if (bb)
1335 *bb = state->gain[1];
1336 if (rf_gain_limit)
1337 *rf_gain_limit = state->rf_gain_limit;
1338 if (rflt)
1339 *rflt = (state->rf_lt_def >> 10) & 0x7;
1340}
Olivier Grenie28fafca2011-01-04 04:27:11 -03001341
Olivier Grenie03245a52009-12-04 13:27:57 -03001342EXPORT_SYMBOL(dib0090_get_current_gain);
Olivier Grenie9c783032009-12-07 07:49:40 -03001343
Olivier Grenie6724a2f2011-08-05 13:49:33 -03001344u16 dib0090_get_wbd_target(struct dvb_frontend *fe)
Olivier Grenie03245a52009-12-04 13:27:57 -03001345{
Olivier Grenie28fafca2011-01-04 04:27:11 -03001346 struct dib0090_state *state = fe->tuner_priv;
1347 u32 f_MHz = state->fe->dtv_property_cache.frequency / 1000000;
1348 s32 current_temp = state->temperature;
1349 s32 wbd_thot, wbd_tcold;
1350 const struct dib0090_wbd_slope *wbd = state->current_wbd_table;
1351
1352 while (f_MHz > wbd->max_freq)
1353 wbd++;
1354
1355 dprintk("using wbd-table-entry with max freq %d", wbd->max_freq);
1356
1357 if (current_temp < 0)
1358 current_temp = 0;
1359 if (current_temp > 128)
1360 current_temp = 128;
1361
Olivier Grenie28fafca2011-01-04 04:27:11 -03001362 state->wbdmux &= ~(7 << 13);
1363 if (wbd->wbd_gain != 0)
1364 state->wbdmux |= (wbd->wbd_gain << 13);
1365 else
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001366 state->wbdmux |= (4 << 13);
Olivier Grenie28fafca2011-01-04 04:27:11 -03001367
1368 dib0090_write_reg(state, 0x10, state->wbdmux);
1369
Olivier Grenie28fafca2011-01-04 04:27:11 -03001370 wbd_thot = wbd->offset_hot - (((u32) wbd->slope_hot * f_MHz) >> 6);
1371 wbd_tcold = wbd->offset_cold - (((u32) wbd->slope_cold * f_MHz) >> 6);
1372
Olivier Grenie28fafca2011-01-04 04:27:11 -03001373 wbd_tcold += ((wbd_thot - wbd_tcold) * current_temp) >> 7;
1374
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001375 state->wbd_target = dib0090_wbd_to_db(state, state->wbd_offset + wbd_tcold);
Olivier Grenie28fafca2011-01-04 04:27:11 -03001376 dprintk("wbd-target: %d dB", (u32) state->wbd_target);
1377 dprintk("wbd offset applied is %d", wbd_tcold);
1378
1379 return state->wbd_offset + wbd_tcold;
Olivier Grenie03245a52009-12-04 13:27:57 -03001380}
Olivier Grenie6724a2f2011-08-05 13:49:33 -03001381EXPORT_SYMBOL(dib0090_get_wbd_target);
Olivier Grenie28fafca2011-01-04 04:27:11 -03001382
Olivier Grenie6724a2f2011-08-05 13:49:33 -03001383u16 dib0090_get_wbd_offset(struct dvb_frontend *fe)
1384{
1385 struct dib0090_state *state = fe->tuner_priv;
1386 return state->wbd_offset;
1387}
Olivier Grenie03245a52009-12-04 13:27:57 -03001388EXPORT_SYMBOL(dib0090_get_wbd_offset);
Olivier Grenie9c783032009-12-07 07:49:40 -03001389
Olivier Grenie6724a2f2011-08-05 13:49:33 -03001390int dib0090_set_switch(struct dvb_frontend *fe, u8 sw1, u8 sw2, u8 sw3)
1391{
1392 struct dib0090_state *state = fe->tuner_priv;
1393
1394 dib0090_write_reg(state, 0x0b, (dib0090_read_reg(state, 0x0b) & 0xfff8)
1395 | ((sw3 & 1) << 2) | ((sw2 & 1) << 1) | (sw1 & 1));
1396
1397 return 0;
1398}
1399EXPORT_SYMBOL(dib0090_set_switch);
1400
1401int dib0090_set_vga(struct dvb_frontend *fe, u8 onoff)
1402{
1403 struct dib0090_state *state = fe->tuner_priv;
1404
1405 dib0090_write_reg(state, 0x09, (dib0090_read_reg(state, 0x09) & 0x7fff)
1406 | ((onoff & 1) << 15));
1407 return 0;
1408}
1409EXPORT_SYMBOL(dib0090_set_vga);
1410
1411int dib0090_update_rframp_7090(struct dvb_frontend *fe, u8 cfg_sensitivity)
1412{
1413 struct dib0090_state *state = fe->tuner_priv;
1414
1415 if ((!state->identity.p1g) || (!state->identity.in_soc)
1416 || ((state->identity.version != SOC_7090_P1G_21R1)
1417 && (state->identity.version != SOC_7090_P1G_11R1))) {
1418 dprintk("%s() function can only be used for dib7090P", __func__);
1419 return -ENODEV;
1420 }
1421
1422 if (cfg_sensitivity)
1423 state->rf_ramp = (const u16 *)&rf_ramp_pwm_cband_7090e_sensitivity;
1424 else
1425 state->rf_ramp = (const u16 *)&rf_ramp_pwm_cband_7090e_aci;
1426 dib0090_pwm_gain_reset(fe);
1427
1428 return 0;
1429}
1430EXPORT_SYMBOL(dib0090_update_rframp_7090);
1431
Olivier Grenie03245a52009-12-04 13:27:57 -03001432static const u16 dib0090_defaults[] = {
1433
1434 25, 0x01,
1435 0x0000,
1436 0x99a0,
1437 0x6008,
1438 0x0000,
Olivier Grenie28fafca2011-01-04 04:27:11 -03001439 0x8bcb,
Olivier Grenie03245a52009-12-04 13:27:57 -03001440 0x0000,
1441 0x0405,
1442 0x0000,
1443 0x0000,
1444 0x0000,
1445 0xb802,
1446 0x0300,
1447 0x2d12,
1448 0xbac0,
1449 0x7c00,
1450 0xdbb9,
1451 0x0954,
1452 0x0743,
1453 0x8000,
1454 0x0001,
1455 0x0040,
1456 0x0100,
1457 0x0000,
1458 0xe910,
1459 0x149e,
1460
1461 1, 0x1c,
1462 0xff2d,
1463
1464 1, 0x39,
1465 0x0000,
1466
Olivier Grenie03245a52009-12-04 13:27:57 -03001467 2, 0x1e,
1468 0x07FF,
1469 0x0007,
1470
1471 1, 0x24,
1472 EN_UHF | EN_CRYSTAL,
1473
1474 2, 0x3c,
1475 0x3ff,
1476 0x111,
1477 0
1478};
1479
Olivier Grenie28fafca2011-01-04 04:27:11 -03001480static const u16 dib0090_p1g_additionnal_defaults[] = {
Olivier Grenie28fafca2011-01-04 04:27:11 -03001481 1, 0x05,
1482 0xabcd,
1483
1484 1, 0x11,
1485 0x00b4,
1486
1487 1, 0x1c,
1488 0xfffd,
1489
1490 1, 0x40,
1491 0x108,
1492 0
1493};
1494
1495static void dib0090_set_default_config(struct dib0090_state *state, const u16 * n)
Olivier Grenie03245a52009-12-04 13:27:57 -03001496{
Olivier Grenie28fafca2011-01-04 04:27:11 -03001497 u16 l, r;
Olivier Grenie03245a52009-12-04 13:27:57 -03001498
Olivier Grenie03245a52009-12-04 13:27:57 -03001499 l = pgm_read_word(n++);
1500 while (l) {
1501 r = pgm_read_word(n++);
1502 do {
Olivier Grenie03245a52009-12-04 13:27:57 -03001503 dib0090_write_reg(state, r, pgm_read_word(n++));
1504 r++;
1505 } while (--l);
1506 l = pgm_read_word(n++);
1507 }
Olivier Grenie28fafca2011-01-04 04:27:11 -03001508}
1509
1510#define CAP_VALUE_MIN (u8) 9
1511#define CAP_VALUE_MAX (u8) 40
1512#define HR_MIN (u8) 25
1513#define HR_MAX (u8) 40
1514#define POLY_MIN (u8) 0
1515#define POLY_MAX (u8) 8
1516
Olivier Greniea685dbb2011-08-05 14:10:40 -03001517static void dib0090_set_EFUSE(struct dib0090_state *state)
Olivier Grenie28fafca2011-01-04 04:27:11 -03001518{
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001519 u8 c, h, n;
1520 u16 e2, e4;
1521 u16 cal;
Olivier Grenie28fafca2011-01-04 04:27:11 -03001522
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001523 e2 = dib0090_read_reg(state, 0x26);
1524 e4 = dib0090_read_reg(state, 0x28);
Olivier Grenie28fafca2011-01-04 04:27:11 -03001525
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001526 if ((state->identity.version == P1D_E_F) ||
1527 (state->identity.version == P1G) || (e2 == 0xffff)) {
Olivier Grenie28fafca2011-01-04 04:27:11 -03001528
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001529 dib0090_write_reg(state, 0x22, 0x10);
1530 cal = (dib0090_read_reg(state, 0x22) >> 6) & 0x3ff;
Olivier Grenie28fafca2011-01-04 04:27:11 -03001531
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001532 if ((cal < 670) || (cal == 1023))
1533 cal = 850;
1534 n = 165 - ((cal * 10)>>6) ;
1535 e2 = e4 = (3<<12) | (34<<6) | (n);
1536 }
Olivier Grenie28fafca2011-01-04 04:27:11 -03001537
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001538 if (e2 != e4)
1539 e2 &= e4; /* Remove the redundancy */
Olivier Grenie28fafca2011-01-04 04:27:11 -03001540
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001541 if (e2 != 0xffff) {
1542 c = e2 & 0x3f;
1543 n = (e2 >> 12) & 0xf;
1544 h = (e2 >> 6) & 0x3f;
Olivier Grenie28fafca2011-01-04 04:27:11 -03001545
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001546 if ((c >= CAP_VALUE_MAX) || (c <= CAP_VALUE_MIN))
1547 c = 32;
Olivier Grenieaedabf72012-12-31 10:38:44 -03001548 else
1549 c += 14;
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001550 if ((h >= HR_MAX) || (h <= HR_MIN))
1551 h = 34;
1552 if ((n >= POLY_MAX) || (n <= POLY_MIN))
1553 n = 3;
Olivier Grenie28fafca2011-01-04 04:27:11 -03001554
Mauro Carvalho Chehab751dc8c2013-04-25 15:30:40 -03001555 dib0090_write_reg(state, 0x13, (h << 10));
1556 e2 = (n << 11) | ((h >> 2)<<6) | c;
1557 dib0090_write_reg(state, 0x2, e2); /* Load the BB_2 */
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001558 }
Olivier Grenie28fafca2011-01-04 04:27:11 -03001559}
1560
1561static int dib0090_reset(struct dvb_frontend *fe)
1562{
1563 struct dib0090_state *state = fe->tuner_priv;
1564
1565 dib0090_reset_digital(fe, state->config);
1566 if (dib0090_identify(fe) < 0)
1567 return -EIO;
1568
1569#ifdef CONFIG_TUNER_DIB0090_P1B_SUPPORT
1570 if (!(state->identity.version & 0x1)) /* it is P1B - reset is already done */
1571 return 0;
1572#endif
1573
1574 if (!state->identity.in_soc) {
1575 if ((dib0090_read_reg(state, 0x1a) >> 5) & 0x2)
1576 dib0090_write_reg(state, 0x1b, (EN_IQADC | EN_BB | EN_BIAS | EN_DIGCLK | EN_PLL | EN_CRYSTAL));
1577 else
1578 dib0090_write_reg(state, 0x1b, (EN_DIGCLK | EN_PLL | EN_CRYSTAL));
1579 }
1580
1581 dib0090_set_default_config(state, dib0090_defaults);
1582
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001583 if (state->identity.in_soc)
1584 dib0090_write_reg(state, 0x18, 0x2910); /* charge pump current = 0 */
Olivier Grenie28fafca2011-01-04 04:27:11 -03001585
1586 if (state->identity.p1g)
1587 dib0090_set_default_config(state, dib0090_p1g_additionnal_defaults);
1588
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001589 /* Update the efuse : Only available for KROSUS > P1C and SOC as well*/
1590 if (((state->identity.version & 0x1f) >= P1D_E_F) || (state->identity.in_soc))
1591 dib0090_set_EFUSE(state);
Olivier Grenie03245a52009-12-04 13:27:57 -03001592
1593 /* Congigure in function of the crystal */
Olivier Grenie2e802862011-08-05 10:39:15 -03001594 if (state->config->force_crystal_mode != 0)
1595 dib0090_write_reg(state, 0x14,
1596 state->config->force_crystal_mode & 3);
1597 else if (state->config->io.clock_khz >= 24000)
Olivier Grenie28fafca2011-01-04 04:27:11 -03001598 dib0090_write_reg(state, 0x14, 1);
Olivier Grenie03245a52009-12-04 13:27:57 -03001599 else
Olivier Grenie28fafca2011-01-04 04:27:11 -03001600 dib0090_write_reg(state, 0x14, 2);
Olivier Grenie03245a52009-12-04 13:27:57 -03001601 dprintk("Pll lock : %d", (dib0090_read_reg(state, 0x1a) >> 11) & 0x1);
1602
Olivier Grenie28fafca2011-01-04 04:27:11 -03001603 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 -03001604
1605 return 0;
1606}
1607
Olivier Grenie9c783032009-12-07 07:49:40 -03001608#define steps(u) (((u) > 15) ? ((u)-16) : (u))
Olivier Grenie03245a52009-12-04 13:27:57 -03001609#define INTERN_WAIT 10
1610static int dib0090_get_offset(struct dib0090_state *state, enum frontend_tune_state *tune_state)
1611{
1612 int ret = INTERN_WAIT * 10;
1613
1614 switch (*tune_state) {
1615 case CT_TUNER_STEP_2:
1616 /* Turns to positive */
1617 dib0090_write_reg(state, 0x1f, 0x7);
1618 *tune_state = CT_TUNER_STEP_3;
1619 break;
1620
1621 case CT_TUNER_STEP_3:
1622 state->adc_diff = dib0090_read_reg(state, 0x1d);
1623
1624 /* Turns to negative */
1625 dib0090_write_reg(state, 0x1f, 0x4);
1626 *tune_state = CT_TUNER_STEP_4;
1627 break;
1628
1629 case CT_TUNER_STEP_4:
1630 state->adc_diff -= dib0090_read_reg(state, 0x1d);
1631 *tune_state = CT_TUNER_STEP_5;
1632 ret = 0;
1633 break;
1634
1635 default:
1636 break;
1637 }
1638
1639 return ret;
1640}
1641
1642struct dc_calibration {
Olivier Grenie28fafca2011-01-04 04:27:11 -03001643 u8 addr;
1644 u8 offset;
1645 u8 pga:1;
1646 u16 bb1;
1647 u8 i:1;
Olivier Grenie03245a52009-12-04 13:27:57 -03001648};
1649
1650static const struct dc_calibration dc_table[] = {
1651 /* Step1 BB gain1= 26 with boost 1, gain 2 = 0 */
1652 {0x06, 5, 1, (1 << 13) | (0 << 8) | (26 << 3), 1},
1653 {0x07, 11, 1, (1 << 13) | (0 << 8) | (26 << 3), 0},
1654 /* Step 2 BB gain 1 = 26 with boost = 1 & gain 2 = 29 */
1655 {0x06, 0, 0, (1 << 13) | (29 << 8) | (26 << 3), 1},
1656 {0x06, 10, 0, (1 << 13) | (29 << 8) | (26 << 3), 0},
1657 {0},
1658};
1659
Olivier Grenie28fafca2011-01-04 04:27:11 -03001660static const struct dc_calibration dc_p1g_table[] = {
1661 /* Step1 BB gain1= 26 with boost 1, gain 2 = 0 */
1662 /* addr ; trim reg offset ; pga ; CTRL_BB1 value ; i or q */
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001663 {0x06, 5, 1, (1 << 13) | (0 << 8) | (15 << 3), 1},
1664 {0x07, 11, 1, (1 << 13) | (0 << 8) | (15 << 3), 0},
Olivier Grenie28fafca2011-01-04 04:27:11 -03001665 /* Step 2 BB gain 1 = 26 with boost = 1 & gain 2 = 29 */
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001666 {0x06, 0, 0, (1 << 13) | (29 << 8) | (15 << 3), 1},
1667 {0x06, 10, 0, (1 << 13) | (29 << 8) | (15 << 3), 0},
Olivier Grenie28fafca2011-01-04 04:27:11 -03001668 {0},
1669};
1670
Olivier Grenie03245a52009-12-04 13:27:57 -03001671static void dib0090_set_trim(struct dib0090_state *state)
1672{
1673 u16 *val;
1674
1675 if (state->dc->addr == 0x07)
1676 val = &state->bb7;
1677 else
1678 val = &state->bb6;
1679
1680 *val &= ~(0x1f << state->dc->offset);
1681 *val |= state->step << state->dc->offset;
1682
1683 dib0090_write_reg(state, state->dc->addr, *val);
1684}
1685
1686static int dib0090_dc_offset_calibration(struct dib0090_state *state, enum frontend_tune_state *tune_state)
1687{
1688 int ret = 0;
Olivier Grenie28fafca2011-01-04 04:27:11 -03001689 u16 reg;
Olivier Grenie03245a52009-12-04 13:27:57 -03001690
1691 switch (*tune_state) {
Olivier Grenie03245a52009-12-04 13:27:57 -03001692 case CT_TUNER_START:
Olivier Grenie28fafca2011-01-04 04:27:11 -03001693 dprintk("Start DC offset calibration");
Olivier Grenie03245a52009-12-04 13:27:57 -03001694
1695 /* force vcm2 = 0.8V */
1696 state->bb6 = 0;
1697 state->bb7 = 0x040d;
1698
Olivier Grenie28fafca2011-01-04 04:27:11 -03001699 /* the LNA AND LO are off */
1700 reg = dib0090_read_reg(state, 0x24) & 0x0ffb; /* shutdown lna and lo */
1701 dib0090_write_reg(state, 0x24, reg);
1702
1703 state->wbdmux = dib0090_read_reg(state, 0x10);
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001704 dib0090_write_reg(state, 0x10, (state->wbdmux & ~(0xff << 3)) | (0x7 << 3) | 0x3);
1705 dib0090_write_reg(state, 0x23, dib0090_read_reg(state, 0x23) & ~(1 << 14));
Olivier Grenie28fafca2011-01-04 04:27:11 -03001706
Olivier Grenie03245a52009-12-04 13:27:57 -03001707 state->dc = dc_table;
1708
Olivier Grenie28fafca2011-01-04 04:27:11 -03001709 if (state->identity.p1g)
1710 state->dc = dc_p1g_table;
Olivier Grenie03245a52009-12-04 13:27:57 -03001711
1712 /* fall through */
Olivier Grenie03245a52009-12-04 13:27:57 -03001713 case CT_TUNER_STEP_0:
Mauro Carvalho Chehab91aff0c2015-06-05 08:27:18 -03001714 dprintk("Start/continue DC calibration for %s path", (state->dc->i == 1) ? "I" : "Q");
Olivier Grenie03245a52009-12-04 13:27:57 -03001715 dib0090_write_reg(state, 0x01, state->dc->bb1);
1716 dib0090_write_reg(state, 0x07, state->bb7 | (state->dc->i << 7));
1717
1718 state->step = 0;
Olivier Grenie03245a52009-12-04 13:27:57 -03001719 state->min_adc_diff = 1023;
Olivier Grenie03245a52009-12-04 13:27:57 -03001720 *tune_state = CT_TUNER_STEP_1;
1721 ret = 50;
1722 break;
1723
1724 case CT_TUNER_STEP_1:
1725 dib0090_set_trim(state);
Olivier Grenie03245a52009-12-04 13:27:57 -03001726 *tune_state = CT_TUNER_STEP_2;
1727 break;
1728
1729 case CT_TUNER_STEP_2:
1730 case CT_TUNER_STEP_3:
1731 case CT_TUNER_STEP_4:
1732 ret = dib0090_get_offset(state, tune_state);
1733 break;
1734
1735 case CT_TUNER_STEP_5: /* found an offset */
Olivier Grenie28fafca2011-01-04 04:27:11 -03001736 dprintk("adc_diff = %d, current step= %d", (u32) state->adc_diff, state->step);
1737 if (state->step == 0 && state->adc_diff < 0) {
1738 state->min_adc_diff = -1023;
1739 dprintk("Change of sign of the minimum adc diff");
1740 }
1741
1742 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 -03001743
1744 /* first turn for this frequency */
1745 if (state->step == 0) {
1746 if (state->dc->pga && state->adc_diff < 0)
1747 state->step = 0x10;
1748 if (state->dc->pga == 0 && state->adc_diff > 0)
1749 state->step = 0x10;
1750 }
1751
Olivier Grenie28fafca2011-01-04 04:27:11 -03001752 /* Look for a change of Sign in the Adc_diff.min_adc_diff is used to STORE the setp N-1 */
1753 if ((state->adc_diff & 0x8000) == (state->min_adc_diff & 0x8000) && steps(state->step) < 15) {
1754 /* 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 -03001755 state->step++;
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001756 state->min_adc_diff = state->adc_diff;
Olivier Grenie03245a52009-12-04 13:27:57 -03001757 *tune_state = CT_TUNER_STEP_1;
1758 } else {
Olivier Grenie03245a52009-12-04 13:27:57 -03001759 /* the minimum was what we have seen in the step before */
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001760 if (ABS(state->adc_diff) > ABS(state->min_adc_diff)) {
Olivier Grenie28fafca2011-01-04 04:27:11 -03001761 dprintk("Since adc_diff N = %d > adc_diff step N-1 = %d, Come back one step", state->adc_diff, state->min_adc_diff);
1762 state->step--;
1763 }
Olivier Grenie03245a52009-12-04 13:27:57 -03001764
Olivier Grenie28fafca2011-01-04 04:27:11 -03001765 dib0090_set_trim(state);
1766 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 -03001767
1768 state->dc++;
1769 if (state->dc->addr == 0) /* done */
1770 *tune_state = CT_TUNER_STEP_6;
1771 else
1772 *tune_state = CT_TUNER_STEP_0;
1773
1774 }
1775 break;
1776
1777 case CT_TUNER_STEP_6:
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001778 dib0090_write_reg(state, 0x07, state->bb7 & ~0x0008);
Olivier Grenie03245a52009-12-04 13:27:57 -03001779 dib0090_write_reg(state, 0x1f, 0x7);
1780 *tune_state = CT_TUNER_START; /* reset done -> real tuning can now begin */
Olivier Grenie28fafca2011-01-04 04:27:11 -03001781 state->calibrate &= ~DC_CAL;
Olivier Grenie03245a52009-12-04 13:27:57 -03001782 default:
1783 break;
1784 }
1785 return ret;
1786}
1787
1788static int dib0090_wbd_calibration(struct dib0090_state *state, enum frontend_tune_state *tune_state)
1789{
Olivier Grenie28fafca2011-01-04 04:27:11 -03001790 u8 wbd_gain;
1791 const struct dib0090_wbd_slope *wbd = state->current_wbd_table;
1792
Olivier Grenie03245a52009-12-04 13:27:57 -03001793 switch (*tune_state) {
1794 case CT_TUNER_START:
Olivier Grenie28fafca2011-01-04 04:27:11 -03001795 while (state->current_rf / 1000 > wbd->max_freq)
1796 wbd++;
1797 if (wbd->wbd_gain != 0)
1798 wbd_gain = wbd->wbd_gain;
1799 else {
1800 wbd_gain = 4;
1801#if defined(CONFIG_BAND_LBAND) || defined(CONFIG_BAND_SBAND)
1802 if ((state->current_band == BAND_LBAND) || (state->current_band == BAND_SBAND))
1803 wbd_gain = 2;
1804#endif
1805 }
Olivier Grenie03245a52009-12-04 13:27:57 -03001806
Olivier Grenie28fafca2011-01-04 04:27:11 -03001807 if (wbd_gain == state->wbd_calibration_gain) { /* the WBD calibration has already been done */
1808 *tune_state = CT_TUNER_START;
1809 state->calibrate &= ~WBD_CAL;
1810 return 0;
1811 }
1812
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001813 dib0090_write_reg(state, 0x10, 0x1b81 | (1 << 10) | (wbd_gain << 13) | (1 << 3));
Olivier Grenie28fafca2011-01-04 04:27:11 -03001814
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001815 dib0090_write_reg(state, 0x24, ((EN_UHF & 0x0fff) | (1 << 1)));
Olivier Grenie03245a52009-12-04 13:27:57 -03001816 *tune_state = CT_TUNER_STEP_0;
Olivier Grenie28fafca2011-01-04 04:27:11 -03001817 state->wbd_calibration_gain = wbd_gain;
Olivier Grenie03245a52009-12-04 13:27:57 -03001818 return 90; /* wait for the WBDMUX to switch and for the ADC to sample */
Olivier Grenie03245a52009-12-04 13:27:57 -03001819
Olivier Grenie28fafca2011-01-04 04:27:11 -03001820 case CT_TUNER_STEP_0:
1821 state->wbd_offset = dib0090_get_slow_adc_val(state);
1822 dprintk("WBD calibration offset = %d", state->wbd_offset);
Olivier Grenie03245a52009-12-04 13:27:57 -03001823 *tune_state = CT_TUNER_START; /* reset done -> real tuning can now begin */
Olivier Grenie28fafca2011-01-04 04:27:11 -03001824 state->calibrate &= ~WBD_CAL;
Olivier Grenie03245a52009-12-04 13:27:57 -03001825 break;
Olivier Grenie28fafca2011-01-04 04:27:11 -03001826
Olivier Grenie03245a52009-12-04 13:27:57 -03001827 default:
1828 break;
1829 }
1830 return 0;
1831}
1832
1833static void dib0090_set_bandwidth(struct dib0090_state *state)
1834{
1835 u16 tmp;
1836
1837 if (state->fe->dtv_property_cache.bandwidth_hz / 1000 <= 5000)
1838 tmp = (3 << 14);
1839 else if (state->fe->dtv_property_cache.bandwidth_hz / 1000 <= 6000)
1840 tmp = (2 << 14);
1841 else if (state->fe->dtv_property_cache.bandwidth_hz / 1000 <= 7000)
1842 tmp = (1 << 14);
1843 else
1844 tmp = (0 << 14);
1845
1846 state->bb_1_def &= 0x3fff;
1847 state->bb_1_def |= tmp;
1848
1849 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 -03001850
1851 dib0090_write_reg(state, 0x03, 0x6008); /* = 0x6008 : vcm3_trim = 1 ; filter2_gm1_trim = 8 ; filter2_cutoff_freq = 0 */
1852 dib0090_write_reg(state, 0x04, 0x1); /* 0 = 1KHz ; 1 = 50Hz ; 2 = 150Hz ; 3 = 50KHz ; 4 = servo fast */
1853 if (state->identity.in_soc) {
1854 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 */
1855 } else {
1856 dib0090_write_reg(state, 0x02, (5 << 11) | (8 << 6) | (22 & 0x3f)); /* 22 = cap_value */
1857 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 */
1858 }
Olivier Grenie03245a52009-12-04 13:27:57 -03001859}
1860
1861static const struct dib0090_pll dib0090_pll_table[] = {
1862#ifdef CONFIG_BAND_CBAND
1863 {56000, 0, 9, 48, 6},
1864 {70000, 1, 9, 48, 6},
1865 {87000, 0, 8, 32, 4},
1866 {105000, 1, 8, 32, 4},
1867 {115000, 0, 7, 24, 6},
1868 {140000, 1, 7, 24, 6},
1869 {170000, 0, 6, 16, 4},
1870#endif
1871#ifdef CONFIG_BAND_VHF
1872 {200000, 1, 6, 16, 4},
1873 {230000, 0, 5, 12, 6},
1874 {280000, 1, 5, 12, 6},
1875 {340000, 0, 4, 8, 4},
1876 {380000, 1, 4, 8, 4},
1877 {450000, 0, 3, 6, 6},
1878#endif
1879#ifdef CONFIG_BAND_UHF
1880 {580000, 1, 3, 6, 6},
1881 {700000, 0, 2, 4, 4},
1882 {860000, 1, 2, 4, 4},
1883#endif
1884#ifdef CONFIG_BAND_LBAND
1885 {1800000, 1, 0, 2, 4},
1886#endif
1887#ifdef CONFIG_BAND_SBAND
1888 {2900000, 0, 14, 1, 4},
1889#endif
1890};
1891
1892static const struct dib0090_tuning dib0090_tuning_table_fm_vhf_on_cband[] = {
1893
1894#ifdef CONFIG_BAND_CBAND
1895 {184000, 4, 1, 15, 0x280, 0x2912, 0xb94e, EN_CAB},
1896 {227000, 4, 3, 15, 0x280, 0x2912, 0xb94e, EN_CAB},
1897 {380000, 4, 7, 15, 0x280, 0x2912, 0xb94e, EN_CAB},
1898#endif
1899#ifdef CONFIG_BAND_UHF
1900 {520000, 2, 0, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},
1901 {550000, 2, 2, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},
1902 {650000, 2, 3, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},
1903 {750000, 2, 5, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},
1904 {850000, 2, 6, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},
1905 {900000, 2, 7, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},
1906#endif
1907#ifdef CONFIG_BAND_LBAND
1908 {1500000, 4, 0, 20, 0x300, 0x1912, 0x82c9, EN_LBD},
1909 {1600000, 4, 1, 20, 0x300, 0x1912, 0x82c9, EN_LBD},
1910 {1800000, 4, 3, 20, 0x300, 0x1912, 0x82c9, EN_LBD},
1911#endif
1912#ifdef CONFIG_BAND_SBAND
1913 {2300000, 1, 4, 20, 0x300, 0x2d2A, 0x82c7, EN_SBD},
1914 {2900000, 1, 7, 20, 0x280, 0x2deb, 0x8347, EN_SBD},
1915#endif
1916};
1917
1918static const struct dib0090_tuning dib0090_tuning_table[] = {
1919
1920#ifdef CONFIG_BAND_CBAND
1921 {170000, 4, 1, 15, 0x280, 0x2912, 0xb94e, EN_CAB},
1922#endif
1923#ifdef CONFIG_BAND_VHF
1924 {184000, 1, 1, 15, 0x300, 0x4d12, 0xb94e, EN_VHF},
1925 {227000, 1, 3, 15, 0x300, 0x4d12, 0xb94e, EN_VHF},
1926 {380000, 1, 7, 15, 0x300, 0x4d12, 0xb94e, EN_VHF},
1927#endif
1928#ifdef CONFIG_BAND_UHF
1929 {520000, 2, 0, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},
1930 {550000, 2, 2, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},
1931 {650000, 2, 3, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},
1932 {750000, 2, 5, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},
1933 {850000, 2, 6, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},
1934 {900000, 2, 7, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},
1935#endif
1936#ifdef CONFIG_BAND_LBAND
1937 {1500000, 4, 0, 20, 0x300, 0x1912, 0x82c9, EN_LBD},
1938 {1600000, 4, 1, 20, 0x300, 0x1912, 0x82c9, EN_LBD},
1939 {1800000, 4, 3, 20, 0x300, 0x1912, 0x82c9, EN_LBD},
1940#endif
1941#ifdef CONFIG_BAND_SBAND
1942 {2300000, 1, 4, 20, 0x300, 0x2d2A, 0x82c7, EN_SBD},
1943 {2900000, 1, 7, 20, 0x280, 0x2deb, 0x8347, EN_SBD},
1944#endif
1945};
1946
Olivier Grenie28fafca2011-01-04 04:27:11 -03001947static const struct dib0090_tuning dib0090_p1g_tuning_table[] = {
Olivier Grenie28fafca2011-01-04 04:27:11 -03001948#ifdef CONFIG_BAND_CBAND
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001949 {170000, 4, 1, 0x820f, 0x300, 0x2d22, 0x82cb, EN_CAB},
Olivier Grenie28fafca2011-01-04 04:27:11 -03001950#endif
1951#ifdef CONFIG_BAND_VHF
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001952 {184000, 1, 1, 15, 0x300, 0x4d12, 0xb94e, EN_VHF},
1953 {227000, 1, 3, 15, 0x300, 0x4d12, 0xb94e, EN_VHF},
1954 {380000, 1, 7, 15, 0x300, 0x4d12, 0xb94e, EN_VHF},
Olivier Grenie28fafca2011-01-04 04:27:11 -03001955#endif
1956#ifdef CONFIG_BAND_UHF
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001957 {510000, 2, 0, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},
1958 {540000, 2, 1, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},
1959 {600000, 2, 3, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},
1960 {630000, 2, 4, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},
1961 {680000, 2, 5, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},
1962 {720000, 2, 6, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},
1963 {900000, 2, 7, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},
Olivier Grenie28fafca2011-01-04 04:27:11 -03001964#endif
1965#ifdef CONFIG_BAND_LBAND
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001966 {1500000, 4, 0, 20, 0x300, 0x1912, 0x82c9, EN_LBD},
1967 {1600000, 4, 1, 20, 0x300, 0x1912, 0x82c9, EN_LBD},
1968 {1800000, 4, 3, 20, 0x300, 0x1912, 0x82c9, EN_LBD},
Olivier Grenie28fafca2011-01-04 04:27:11 -03001969#endif
1970#ifdef CONFIG_BAND_SBAND
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001971 {2300000, 1, 4, 20, 0x300, 0x2d2A, 0x82c7, EN_SBD},
1972 {2900000, 1, 7, 20, 0x280, 0x2deb, 0x8347, EN_SBD},
Olivier Grenie28fafca2011-01-04 04:27:11 -03001973#endif
1974};
1975
1976static const struct dib0090_pll dib0090_p1g_pll_table[] = {
1977#ifdef CONFIG_BAND_CBAND
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001978 {57000, 0, 11, 48, 6},
1979 {70000, 1, 11, 48, 6},
1980 {86000, 0, 10, 32, 4},
1981 {105000, 1, 10, 32, 4},
1982 {115000, 0, 9, 24, 6},
1983 {140000, 1, 9, 24, 6},
1984 {170000, 0, 8, 16, 4},
Olivier Grenie28fafca2011-01-04 04:27:11 -03001985#endif
1986#ifdef CONFIG_BAND_VHF
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001987 {200000, 1, 8, 16, 4},
1988 {230000, 0, 7, 12, 6},
1989 {280000, 1, 7, 12, 6},
1990 {340000, 0, 6, 8, 4},
1991 {380000, 1, 6, 8, 4},
1992 {455000, 0, 5, 6, 6},
Olivier Grenie28fafca2011-01-04 04:27:11 -03001993#endif
1994#ifdef CONFIG_BAND_UHF
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001995 {580000, 1, 5, 6, 6},
1996 {680000, 0, 4, 4, 4},
1997 {860000, 1, 4, 4, 4},
Olivier Grenie28fafca2011-01-04 04:27:11 -03001998#endif
1999#ifdef CONFIG_BAND_LBAND
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002000 {1800000, 1, 2, 2, 4},
Olivier Grenie28fafca2011-01-04 04:27:11 -03002001#endif
2002#ifdef CONFIG_BAND_SBAND
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002003 {2900000, 0, 1, 1, 6},
Olivier Grenie28fafca2011-01-04 04:27:11 -03002004#endif
2005};
2006
2007static const struct dib0090_tuning dib0090_p1g_tuning_table_fm_vhf_on_cband[] = {
Olivier Grenie28fafca2011-01-04 04:27:11 -03002008#ifdef CONFIG_BAND_CBAND
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002009 {184000, 4, 3, 0x4187, 0x2c0, 0x2d22, 0x81cb, EN_CAB},
2010 {227000, 4, 3, 0x4187, 0x2c0, 0x2d22, 0x81cb, EN_CAB},
2011 {380000, 4, 3, 0x4187, 0x2c0, 0x2d22, 0x81cb, EN_CAB},
Olivier Grenie28fafca2011-01-04 04:27:11 -03002012#endif
2013#ifdef CONFIG_BAND_UHF
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002014 {520000, 2, 0, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},
2015 {550000, 2, 2, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},
2016 {650000, 2, 3, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},
2017 {750000, 2, 5, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},
2018 {850000, 2, 6, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},
2019 {900000, 2, 7, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},
Olivier Grenie28fafca2011-01-04 04:27:11 -03002020#endif
2021#ifdef CONFIG_BAND_LBAND
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002022 {1500000, 4, 0, 20, 0x300, 0x1912, 0x82c9, EN_LBD},
2023 {1600000, 4, 1, 20, 0x300, 0x1912, 0x82c9, EN_LBD},
2024 {1800000, 4, 3, 20, 0x300, 0x1912, 0x82c9, EN_LBD},
Olivier Grenie28fafca2011-01-04 04:27:11 -03002025#endif
2026#ifdef CONFIG_BAND_SBAND
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002027 {2300000, 1, 4, 20, 0x300, 0x2d2A, 0x82c7, EN_SBD},
2028 {2900000, 1, 7, 20, 0x280, 0x2deb, 0x8347, EN_SBD},
Olivier Grenie28fafca2011-01-04 04:27:11 -03002029#endif
2030};
2031
2032static const struct dib0090_tuning dib0090_tuning_table_cband_7090[] = {
Olivier Grenie28fafca2011-01-04 04:27:11 -03002033#ifdef CONFIG_BAND_CBAND
Olivier Grenie28fafca2011-01-04 04:27:11 -03002034 {300000, 4, 3, 0x018F, 0x2c0, 0x2d22, 0xb9ce, EN_CAB},
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002035 {380000, 4, 10, 0x018F, 0x2c0, 0x2d22, 0xb9ce, EN_CAB},
Olivier Grenie28fafca2011-01-04 04:27:11 -03002036 {570000, 4, 10, 0x8190, 0x2c0, 0x2d22, 0xb9ce, EN_CAB},
2037 {858000, 4, 5, 0x8190, 0x2c0, 0x2d22, 0xb9ce, EN_CAB},
2038#endif
2039};
2040
Olivier Grenie6724a2f2011-08-05 13:49:33 -03002041static const struct dib0090_tuning dib0090_tuning_table_cband_7090e_sensitivity[] = {
2042#ifdef CONFIG_BAND_CBAND
2043 { 300000, 0 , 3, 0x8105, 0x2c0, 0x2d12, 0xb84e, EN_CAB },
2044 { 380000, 0 , 10, 0x810F, 0x2c0, 0x2d12, 0xb84e, EN_CAB },
2045 { 600000, 0 , 10, 0x815E, 0x280, 0x2d12, 0xb84e, EN_CAB },
2046 { 660000, 0 , 5, 0x85E3, 0x280, 0x2d12, 0xb84e, EN_CAB },
2047 { 720000, 0 , 5, 0x852E, 0x280, 0x2d12, 0xb84e, EN_CAB },
2048 { 860000, 0 , 4, 0x85E5, 0x280, 0x2d12, 0xb84e, EN_CAB },
2049#endif
2050};
2051
2052int dib0090_update_tuning_table_7090(struct dvb_frontend *fe,
2053 u8 cfg_sensitivity)
2054{
2055 struct dib0090_state *state = fe->tuner_priv;
2056 const struct dib0090_tuning *tune =
2057 dib0090_tuning_table_cband_7090e_sensitivity;
2058 const struct dib0090_tuning dib0090_tuning_table_cband_7090e_aci[] = {
2059 { 300000, 0 , 3, 0x8165, 0x2c0, 0x2d12, 0xb84e, EN_CAB },
2060 { 650000, 0 , 4, 0x815B, 0x280, 0x2d12, 0xb84e, EN_CAB },
2061 { 860000, 0 , 5, 0x84EF, 0x280, 0x2d12, 0xb84e, EN_CAB },
2062 };
2063
2064 if ((!state->identity.p1g) || (!state->identity.in_soc)
2065 || ((state->identity.version != SOC_7090_P1G_21R1)
2066 && (state->identity.version != SOC_7090_P1G_11R1))) {
2067 dprintk("%s() function can only be used for dib7090", __func__);
2068 return -ENODEV;
2069 }
2070
2071 if (cfg_sensitivity)
2072 tune = dib0090_tuning_table_cband_7090e_sensitivity;
2073 else
2074 tune = dib0090_tuning_table_cband_7090e_aci;
2075
2076 while (state->rf_request > tune->max_freq)
2077 tune++;
2078
2079 dib0090_write_reg(state, 0x09, (dib0090_read_reg(state, 0x09) & 0x8000)
2080 | (tune->lna_bias & 0x7fff));
2081 dib0090_write_reg(state, 0x0b, (dib0090_read_reg(state, 0x0b) & 0xf83f)
2082 | ((tune->lna_tune << 6) & 0x07c0));
2083 return 0;
2084}
2085EXPORT_SYMBOL(dib0090_update_tuning_table_7090);
2086
Olivier Grenie28fafca2011-01-04 04:27:11 -03002087static int dib0090_captrim_search(struct dib0090_state *state, enum frontend_tune_state *tune_state)
2088{
2089 int ret = 0;
2090 u16 lo4 = 0xe900;
2091
2092 s16 adc_target;
2093 u16 adc;
2094 s8 step_sign;
2095 u8 force_soft_search = 0;
2096
2097 if (state->identity.version == SOC_8090_P1G_11R1 || state->identity.version == SOC_8090_P1G_21R1)
2098 force_soft_search = 1;
2099
2100 if (*tune_state == CT_TUNER_START) {
2101 dprintk("Start Captrim search : %s", (force_soft_search == 1) ? "FORCE SOFT SEARCH" : "AUTO");
2102 dib0090_write_reg(state, 0x10, 0x2B1);
2103 dib0090_write_reg(state, 0x1e, 0x0032);
2104
2105 if (!state->tuner_is_tuned) {
2106 /* prepare a complete captrim */
2107 if (!state->identity.p1g || force_soft_search)
2108 state->step = state->captrim = state->fcaptrim = 64;
2109
2110 state->current_rf = state->rf_request;
2111 } else { /* we are already tuned to this frequency - the configuration is correct */
2112 if (!state->identity.p1g || force_soft_search) {
2113 /* do a minimal captrim even if the frequency has not changed */
2114 state->step = 4;
2115 state->captrim = state->fcaptrim = dib0090_read_reg(state, 0x18) & 0x7f;
2116 }
2117 }
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002118 state->adc_diff = 3000;
Olivier Grenie28fafca2011-01-04 04:27:11 -03002119 *tune_state = CT_TUNER_STEP_0;
2120
2121 } else if (*tune_state == CT_TUNER_STEP_0) {
2122 if (state->identity.p1g && !force_soft_search) {
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002123 u8 ratio = 31;
Olivier Grenie28fafca2011-01-04 04:27:11 -03002124
2125 dib0090_write_reg(state, 0x40, (3 << 7) | (ratio << 2) | (1 << 1) | 1);
2126 dib0090_read_reg(state, 0x40);
Olivier Grenie28fafca2011-01-04 04:27:11 -03002127 ret = 50;
2128 } else {
2129 state->step /= 2;
2130 dib0090_write_reg(state, 0x18, lo4 | state->captrim);
2131
2132 if (state->identity.in_soc)
2133 ret = 25;
2134 }
2135 *tune_state = CT_TUNER_STEP_1;
2136
2137 } else if (*tune_state == CT_TUNER_STEP_1) {
2138 if (state->identity.p1g && !force_soft_search) {
2139 dib0090_write_reg(state, 0x40, 0x18c | (0 << 1) | 0);
2140 dib0090_read_reg(state, 0x40);
2141
2142 state->fcaptrim = dib0090_read_reg(state, 0x18) & 0x7F;
2143 dprintk("***Final Captrim= 0x%x", state->fcaptrim);
2144 *tune_state = CT_TUNER_STEP_3;
2145
2146 } else {
2147 /* MERGE for all krosus before P1G */
2148 adc = dib0090_get_slow_adc_val(state);
2149 dprintk("CAPTRIM=%d; ADC = %d (ADC) & %dmV", (u32) state->captrim, (u32) adc, (u32) (adc) * (u32) 1800 / (u32) 1024);
2150
2151 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 !!! */
2152 adc_target = 200;
2153 } else
2154 adc_target = 400;
2155
2156 if (adc >= adc_target) {
2157 adc -= adc_target;
2158 step_sign = -1;
2159 } else {
2160 adc = adc_target - adc;
2161 step_sign = 1;
2162 }
2163
2164 if (adc < state->adc_diff) {
2165 dprintk("CAPTRIM=%d is closer to target (%d/%d)", (u32) state->captrim, (u32) adc, (u32) state->adc_diff);
2166 state->adc_diff = adc;
2167 state->fcaptrim = state->captrim;
Olivier Grenie28fafca2011-01-04 04:27:11 -03002168 }
2169
2170 state->captrim += step_sign * state->step;
2171 if (state->step >= 1)
2172 *tune_state = CT_TUNER_STEP_0;
2173 else
2174 *tune_state = CT_TUNER_STEP_2;
2175
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002176 ret = 25;
Olivier Grenie28fafca2011-01-04 04:27:11 -03002177 }
2178 } else if (*tune_state == CT_TUNER_STEP_2) { /* this step is only used by krosus < P1G */
2179 /*write the final cptrim config */
2180 dib0090_write_reg(state, 0x18, lo4 | state->fcaptrim);
2181
2182 *tune_state = CT_TUNER_STEP_3;
2183
2184 } else if (*tune_state == CT_TUNER_STEP_3) {
2185 state->calibrate &= ~CAPTRIM_CAL;
2186 *tune_state = CT_TUNER_STEP_0;
2187 }
2188
2189 return ret;
2190}
2191
2192static int dib0090_get_temperature(struct dib0090_state *state, enum frontend_tune_state *tune_state)
2193{
2194 int ret = 15;
2195 s16 val;
2196
Olivier Grenie28fafca2011-01-04 04:27:11 -03002197 switch (*tune_state) {
2198 case CT_TUNER_START:
2199 state->wbdmux = dib0090_read_reg(state, 0x10);
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002200 dib0090_write_reg(state, 0x10, (state->wbdmux & ~(0xff << 3)) | (0x8 << 3));
Olivier Grenie28fafca2011-01-04 04:27:11 -03002201
2202 state->bias = dib0090_read_reg(state, 0x13);
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002203 dib0090_write_reg(state, 0x13, state->bias | (0x3 << 8));
Olivier Grenie28fafca2011-01-04 04:27:11 -03002204
2205 *tune_state = CT_TUNER_STEP_0;
2206 /* wait for the WBDMUX to switch and for the ADC to sample */
2207 break;
2208
2209 case CT_TUNER_STEP_0:
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002210 state->adc_diff = dib0090_get_slow_adc_val(state);
2211 dib0090_write_reg(state, 0x13, (state->bias & ~(0x3 << 8)) | (0x2 << 8));
Olivier Grenie28fafca2011-01-04 04:27:11 -03002212 *tune_state = CT_TUNER_STEP_1;
2213 break;
2214
2215 case CT_TUNER_STEP_1:
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002216 val = dib0090_get_slow_adc_val(state);
2217 state->temperature = ((s16) ((val - state->adc_diff) * 180) >> 8) + 55;
Olivier Grenie28fafca2011-01-04 04:27:11 -03002218
2219 dprintk("temperature: %d C", state->temperature - 30);
2220
2221 *tune_state = CT_TUNER_STEP_2;
2222 break;
2223
2224 case CT_TUNER_STEP_2:
Olivier Grenie28fafca2011-01-04 04:27:11 -03002225 dib0090_write_reg(state, 0x13, state->bias);
2226 dib0090_write_reg(state, 0x10, state->wbdmux); /* write back original WBDMUX */
2227
2228 *tune_state = CT_TUNER_START;
2229 state->calibrate &= ~TEMP_CAL;
2230 if (state->config->analog_output == 0)
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002231 dib0090_write_reg(state, 0x23, dib0090_read_reg(state, 0x23) | (1 << 14));
Olivier Grenie28fafca2011-01-04 04:27:11 -03002232
2233 break;
2234
2235 default:
2236 ret = 0;
2237 break;
2238 }
2239 return ret;
2240}
2241
Olivier Grenie03245a52009-12-04 13:27:57 -03002242#define WBD 0x781 /* 1 1 1 1 0000 0 0 1 */
2243static int dib0090_tune(struct dvb_frontend *fe)
2244{
2245 struct dib0090_state *state = fe->tuner_priv;
2246 const struct dib0090_tuning *tune = state->current_tune_table_index;
2247 const struct dib0090_pll *pll = state->current_pll_table_index;
2248 enum frontend_tune_state *tune_state = &state->tune_state;
2249
Olivier Grenie28fafca2011-01-04 04:27:11 -03002250 u16 lo5, lo6, Den, tmp;
Olivier Grenie03245a52009-12-04 13:27:57 -03002251 u32 FBDiv, Rest, FREF, VCOF_kHz = 0;
Olivier Grenie03245a52009-12-04 13:27:57 -03002252 int ret = 10; /* 1ms is the default delay most of the time */
2253 u8 c, i;
2254
Olivier Grenie28fafca2011-01-04 04:27:11 -03002255 /************************* VCO ***************************/
Olivier Grenie03245a52009-12-04 13:27:57 -03002256 /* Default values for FG */
2257 /* from these are needed : */
2258 /* Cp,HFdiv,VCOband,SD,Num,Den,FB and REFDiv */
2259
Olivier Grenie28fafca2011-01-04 04:27:11 -03002260 /* in any case we first need to do a calibration if needed */
2261 if (*tune_state == CT_TUNER_START) {
2262 /* deactivate DataTX before some calibrations */
2263 if (state->calibrate & (DC_CAL | TEMP_CAL | WBD_CAL))
2264 dib0090_write_reg(state, 0x23, dib0090_read_reg(state, 0x23) & ~(1 << 14));
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002265 else
2266 /* Activate DataTX in case a calibration has been done before */
2267 if (state->config->analog_output == 0)
2268 dib0090_write_reg(state, 0x23, dib0090_read_reg(state, 0x23) | (1 << 14));
Olivier Grenie03245a52009-12-04 13:27:57 -03002269 }
2270
Olivier Grenie28fafca2011-01-04 04:27:11 -03002271 if (state->calibrate & DC_CAL)
2272 return dib0090_dc_offset_calibration(state, tune_state);
2273 else if (state->calibrate & WBD_CAL) {
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002274 if (state->current_rf == 0)
Olivier Grenie28fafca2011-01-04 04:27:11 -03002275 state->current_rf = state->fe->dtv_property_cache.frequency / 1000;
Olivier Grenie28fafca2011-01-04 04:27:11 -03002276 return dib0090_wbd_calibration(state, tune_state);
2277 } else if (state->calibrate & TEMP_CAL)
2278 return dib0090_get_temperature(state, tune_state);
2279 else if (state->calibrate & CAPTRIM_CAL)
2280 return dib0090_captrim_search(state, tune_state);
2281
Olivier Grenie03245a52009-12-04 13:27:57 -03002282 if (*tune_state == CT_TUNER_START) {
Olivier Grenie28fafca2011-01-04 04:27:11 -03002283 /* 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 */
2284 if (state->config->use_pwm_agc && state->identity.in_soc) {
2285 tmp = dib0090_read_reg(state, 0x39);
2286 if ((tmp >> 10) & 0x1)
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002287 dib0090_write_reg(state, 0x39, tmp & ~(1 << 10));
Olivier Grenie28fafca2011-01-04 04:27:11 -03002288 }
Olivier Grenie03245a52009-12-04 13:27:57 -03002289
Olivier Grenie28fafca2011-01-04 04:27:11 -03002290 state->current_band = (u8) BAND_OF_FREQUENCY(state->fe->dtv_property_cache.frequency / 1000);
2291 state->rf_request =
2292 state->fe->dtv_property_cache.frequency / 1000 + (state->current_band ==
2293 BAND_UHF ? state->config->freq_offset_khz_uhf : state->config->
2294 freq_offset_khz_vhf);
2295
2296 /* in ISDB-T 1seg we shift tuning frequency */
2297 if ((state->fe->dtv_property_cache.delivery_system == SYS_ISDBT && state->fe->dtv_property_cache.isdbt_sb_mode == 1
2298 && state->fe->dtv_property_cache.isdbt_partial_reception == 0)) {
2299 const struct dib0090_low_if_offset_table *LUT_offset = state->config->low_if;
2300 u8 found_offset = 0;
2301 u32 margin_khz = 100;
2302
2303 if (LUT_offset != NULL) {
2304 while (LUT_offset->RF_freq != 0xffff) {
2305 if (((state->rf_request > (LUT_offset->RF_freq - margin_khz))
2306 && (state->rf_request < (LUT_offset->RF_freq + margin_khz)))
2307 && LUT_offset->std == state->fe->dtv_property_cache.delivery_system) {
2308 state->rf_request += LUT_offset->offset_khz;
2309 found_offset = 1;
2310 break;
2311 }
2312 LUT_offset++;
2313 }
2314 }
2315
2316 if (found_offset == 0)
2317 state->rf_request += 400;
2318 }
2319 if (state->current_rf != state->rf_request || (state->current_standard != state->fe->dtv_property_cache.delivery_system)) {
2320 state->tuner_is_tuned = 0;
Olivier Grenie03245a52009-12-04 13:27:57 -03002321 state->current_rf = 0;
Olivier Grenie28fafca2011-01-04 04:27:11 -03002322 state->current_standard = 0;
Olivier Grenie03245a52009-12-04 13:27:57 -03002323
Olivier Grenie28fafca2011-01-04 04:27:11 -03002324 tune = dib0090_tuning_table;
2325 if (state->identity.p1g)
2326 tune = dib0090_p1g_tuning_table;
Olivier Grenie03245a52009-12-04 13:27:57 -03002327
Olivier Grenie28fafca2011-01-04 04:27:11 -03002328 tmp = (state->identity.version >> 5) & 0x7;
2329
2330 if (state->identity.in_soc) {
2331 if (state->config->force_cband_input) { /* Use the CBAND input for all band */
2332 if (state->current_band & BAND_CBAND || state->current_band & BAND_FM || state->current_band & BAND_VHF
2333 || state->current_band & BAND_UHF) {
2334 state->current_band = BAND_CBAND;
Olivier Grenie6724a2f2011-08-05 13:49:33 -03002335 if (state->config->is_dib7090e)
2336 tune = dib0090_tuning_table_cband_7090e_sensitivity;
2337 else
2338 tune = dib0090_tuning_table_cband_7090;
Olivier Grenie28fafca2011-01-04 04:27:11 -03002339 }
2340 } else { /* Use the CBAND input for all band under UHF */
2341 if (state->current_band & BAND_CBAND || state->current_band & BAND_FM || state->current_band & BAND_VHF) {
2342 state->current_band = BAND_CBAND;
Olivier Grenie6724a2f2011-08-05 13:49:33 -03002343 if (state->config->is_dib7090e)
2344 tune = dib0090_tuning_table_cband_7090e_sensitivity;
2345 else
2346 tune = dib0090_tuning_table_cband_7090;
Olivier Grenie28fafca2011-01-04 04:27:11 -03002347 }
2348 }
2349 } else
2350 if (tmp == 0x4 || tmp == 0x7) {
2351 /* CBAND tuner version for VHF */
2352 if (state->current_band == BAND_FM || state->current_band == BAND_CBAND || state->current_band == BAND_VHF) {
2353 state->current_band = BAND_CBAND; /* Force CBAND */
2354
2355 tune = dib0090_tuning_table_fm_vhf_on_cband;
2356 if (state->identity.p1g)
2357 tune = dib0090_p1g_tuning_table_fm_vhf_on_cband;
2358 }
2359 }
2360
2361 pll = dib0090_pll_table;
2362 if (state->identity.p1g)
2363 pll = dib0090_p1g_pll_table;
2364
2365 /* Look for the interval */
2366 while (state->rf_request > tune->max_freq)
2367 tune++;
2368 while (state->rf_request > pll->max_freq)
2369 pll++;
2370
2371 state->current_tune_table_index = tune;
2372 state->current_pll_table_index = pll;
2373
Olivier Grenie03245a52009-12-04 13:27:57 -03002374 dib0090_write_reg(state, 0x0b, 0xb800 | (tune->switch_trim));
2375
Olivier Grenie28fafca2011-01-04 04:27:11 -03002376 VCOF_kHz = (pll->hfdiv * state->rf_request) * 2;
Olivier Grenie03245a52009-12-04 13:27:57 -03002377
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002378 FREF = state->config->io.clock_khz;
Olivier Grenie28fafca2011-01-04 04:27:11 -03002379 if (state->config->fref_clock_ratio != 0)
2380 FREF /= state->config->fref_clock_ratio;
Olivier Grenie03245a52009-12-04 13:27:57 -03002381
Olivier Grenie03245a52009-12-04 13:27:57 -03002382 FBDiv = (VCOF_kHz / pll->topresc / FREF);
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002383 Rest = (VCOF_kHz / pll->topresc) - FBDiv * FREF;
Olivier Grenie03245a52009-12-04 13:27:57 -03002384
2385 if (Rest < LPF)
2386 Rest = 0;
2387 else if (Rest < 2 * LPF)
2388 Rest = 2 * LPF;
2389 else if (Rest > (FREF - LPF)) {
2390 Rest = 0;
2391 FBDiv += 1;
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002392 } else if (Rest > (FREF - 2 * LPF))
Olivier Grenie03245a52009-12-04 13:27:57 -03002393 Rest = FREF - 2 * LPF;
2394 Rest = (Rest * 6528) / (FREF / 10);
Olivier Grenie28fafca2011-01-04 04:27:11 -03002395 state->rest = Rest;
2396
2397 /* external loop filter, otherwise:
2398 * lo5 = (0 << 15) | (0 << 12) | (0 << 11) | (3 << 9) | (4 << 6) | (3 << 4) | 4;
2399 * lo6 = 0x0e34 */
2400
2401 if (Rest == 0) {
2402 if (pll->vco_band)
2403 lo5 = 0x049f;
Olivier Grenie28fafca2011-01-04 04:27:11 -03002404 else
2405 lo5 = 0x041f;
2406 } else {
2407 if (pll->vco_band)
2408 lo5 = 0x049e;
2409 else if (state->config->analog_output)
2410 lo5 = 0x041d;
2411 else
2412 lo5 = 0x041c;
2413 }
2414
2415 if (state->identity.p1g) { /* Bias is done automatically in P1G */
2416 if (state->identity.in_soc) {
2417 if (state->identity.version == SOC_8090_P1G_11R1)
2418 lo5 = 0x46f;
2419 else
2420 lo5 = 0x42f;
2421 } else
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002422 lo5 = 0x42c;
Olivier Grenie28fafca2011-01-04 04:27:11 -03002423 }
2424
2425 lo5 |= (pll->hfdiv_code << 11) | (pll->vco_band << 7); /* bit 15 is the split to the slave, we do not do it here */
2426
Olivier Grenie28fafca2011-01-04 04:27:11 -03002427 if (!state->config->io.pll_int_loop_filt) {
2428 if (state->identity.in_soc)
2429 lo6 = 0xff98;
2430 else if (state->identity.p1g || (Rest == 0))
2431 lo6 = 0xfff8;
2432 else
2433 lo6 = 0xff28;
2434 } else
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002435 lo6 = (state->config->io.pll_int_loop_filt << 3);
Olivier Grenie03245a52009-12-04 13:27:57 -03002436
2437 Den = 1;
2438
Olivier Grenie03245a52009-12-04 13:27:57 -03002439 if (Rest > 0) {
2440 if (state->config->analog_output)
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002441 lo6 |= (1 << 2) | 2;
Olivier Grenie28fafca2011-01-04 04:27:11 -03002442 else {
2443 if (state->identity.in_soc)
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002444 lo6 |= (1 << 2) | 2;
Olivier Grenie28fafca2011-01-04 04:27:11 -03002445 else
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002446 lo6 |= (1 << 2) | 2;
Olivier Grenie28fafca2011-01-04 04:27:11 -03002447 }
Olivier Grenie03245a52009-12-04 13:27:57 -03002448 Den = 255;
2449 }
Olivier Grenie03245a52009-12-04 13:27:57 -03002450 dib0090_write_reg(state, 0x15, (u16) FBDiv);
Olivier Grenie28fafca2011-01-04 04:27:11 -03002451 if (state->config->fref_clock_ratio != 0)
2452 dib0090_write_reg(state, 0x16, (Den << 8) | state->config->fref_clock_ratio);
2453 else
2454 dib0090_write_reg(state, 0x16, (Den << 8) | 1);
Olivier Grenie03245a52009-12-04 13:27:57 -03002455 dib0090_write_reg(state, 0x17, (u16) Rest);
Olivier Grenie03245a52009-12-04 13:27:57 -03002456 dib0090_write_reg(state, 0x19, lo5);
Olivier Grenie03245a52009-12-04 13:27:57 -03002457 dib0090_write_reg(state, 0x1c, lo6);
2458
2459 lo6 = tune->tuner_enable;
2460 if (state->config->analog_output)
2461 lo6 = (lo6 & 0xff9f) | 0x2;
2462
Olivier Grenie28fafca2011-01-04 04:27:11 -03002463 dib0090_write_reg(state, 0x24, lo6 | EN_LO | state->config->use_pwm_agc * EN_CRYSTAL);
Olivier Grenie03245a52009-12-04 13:27:57 -03002464
Olivier Grenie03245a52009-12-04 13:27:57 -03002465 }
Olivier Grenie03245a52009-12-04 13:27:57 -03002466
Olivier Grenie28fafca2011-01-04 04:27:11 -03002467 state->current_rf = state->rf_request;
2468 state->current_standard = state->fe->dtv_property_cache.delivery_system;
Olivier Grenie03245a52009-12-04 13:27:57 -03002469
2470 ret = 20;
Olivier Grenie28fafca2011-01-04 04:27:11 -03002471 state->calibrate = CAPTRIM_CAL; /* captrim serach now */
2472 }
Olivier Grenie03245a52009-12-04 13:27:57 -03002473
Olivier Grenie28fafca2011-01-04 04:27:11 -03002474 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 */
2475 const struct dib0090_wbd_slope *wbd = state->current_wbd_table;
Olivier Grenie03245a52009-12-04 13:27:57 -03002476
Olivier Grenie28fafca2011-01-04 04:27:11 -03002477 while (state->current_rf / 1000 > wbd->max_freq)
2478 wbd++;
Olivier Grenie03245a52009-12-04 13:27:57 -03002479
Olivier Grenie03245a52009-12-04 13:27:57 -03002480 dib0090_write_reg(state, 0x1e, 0x07ff);
Olivier Grenie28fafca2011-01-04 04:27:11 -03002481 dprintk("Final Captrim: %d", (u32) state->fcaptrim);
2482 dprintk("HFDIV code: %d", (u32) pll->hfdiv_code);
2483 dprintk("VCO = %d", (u32) pll->vco_band);
2484 dprintk("VCOF in kHz: %d ((%d*%d) << 1))", (u32) ((pll->hfdiv * state->rf_request) * 2), (u32) pll->hfdiv, (u32) state->rf_request);
2485 dprintk("REFDIV: %d, FREF: %d", (u32) 1, (u32) state->config->io.clock_khz);
2486 dprintk("FBDIV: %d, Rest: %d", (u32) dib0090_read_reg(state, 0x15), (u32) dib0090_read_reg(state, 0x17));
2487 dprintk("Num: %d, Den: %d, SD: %d", (u32) dib0090_read_reg(state, 0x17), (u32) (dib0090_read_reg(state, 0x16) >> 8),
2488 (u32) dib0090_read_reg(state, 0x1c) & 0x3);
Olivier Grenie03245a52009-12-04 13:27:57 -03002489
Olivier Grenie28fafca2011-01-04 04:27:11 -03002490#define WBD 0x781 /* 1 1 1 1 0000 0 0 1 */
Olivier Grenie03245a52009-12-04 13:27:57 -03002491 c = 4;
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002492 i = 3;
Olivier Grenie28fafca2011-01-04 04:27:11 -03002493
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002494 if (wbd->wbd_gain != 0)
Olivier Grenie28fafca2011-01-04 04:27:11 -03002495 c = wbd->wbd_gain;
2496
Olivier Grenie28fafca2011-01-04 04:27:11 -03002497 state->wbdmux = (c << 13) | (i << 11) | (WBD | (state->config->use_pwm_agc << 1));
2498 dib0090_write_reg(state, 0x10, state->wbdmux);
2499
2500 if ((tune->tuner_enable == EN_CAB) && state->identity.p1g) {
2501 dprintk("P1G : The cable band is selected and lna_tune = %d", tune->lna_tune);
2502 dib0090_write_reg(state, 0x09, tune->lna_bias);
2503 dib0090_write_reg(state, 0x0b, 0xb800 | (tune->lna_tune << 6) | (tune->switch_trim));
2504 } else
2505 dib0090_write_reg(state, 0x09, (tune->lna_tune << 5) | tune->lna_bias);
2506
Olivier Grenie03245a52009-12-04 13:27:57 -03002507 dib0090_write_reg(state, 0x0c, tune->v2i);
2508 dib0090_write_reg(state, 0x0d, tune->mix);
2509 dib0090_write_reg(state, 0x0e, tune->load);
Olivier Grenie28fafca2011-01-04 04:27:11 -03002510 *tune_state = CT_TUNER_STEP_1;
Olivier Grenie03245a52009-12-04 13:27:57 -03002511
Olivier Grenie28fafca2011-01-04 04:27:11 -03002512 } else if (*tune_state == CT_TUNER_STEP_1) {
Olivier Grenie03245a52009-12-04 13:27:57 -03002513 /* initialize the lt gain register */
2514 state->rf_lt_def = 0x7c00;
Olivier Grenie03245a52009-12-04 13:27:57 -03002515
2516 dib0090_set_bandwidth(state);
2517 state->tuner_is_tuned = 1;
Olivier Grenie28fafca2011-01-04 04:27:11 -03002518
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002519 state->calibrate |= WBD_CAL;
2520 state->calibrate |= TEMP_CAL;
Olivier Grenie03245a52009-12-04 13:27:57 -03002521 *tune_state = CT_TUNER_STOP;
2522 } else
2523 ret = FE_CALLBACK_TIME_NEVER;
2524 return ret;
2525}
2526
2527static int dib0090_release(struct dvb_frontend *fe)
2528{
2529 kfree(fe->tuner_priv);
2530 fe->tuner_priv = NULL;
2531 return 0;
2532}
2533
2534enum frontend_tune_state dib0090_get_tune_state(struct dvb_frontend *fe)
2535{
2536 struct dib0090_state *state = fe->tuner_priv;
2537
2538 return state->tune_state;
2539}
Olivier Grenie28fafca2011-01-04 04:27:11 -03002540
Olivier Grenie03245a52009-12-04 13:27:57 -03002541EXPORT_SYMBOL(dib0090_get_tune_state);
2542
2543int dib0090_set_tune_state(struct dvb_frontend *fe, enum frontend_tune_state tune_state)
2544{
2545 struct dib0090_state *state = fe->tuner_priv;
2546
2547 state->tune_state = tune_state;
2548 return 0;
2549}
Olivier Grenie28fafca2011-01-04 04:27:11 -03002550
Olivier Grenie03245a52009-12-04 13:27:57 -03002551EXPORT_SYMBOL(dib0090_set_tune_state);
2552
2553static int dib0090_get_frequency(struct dvb_frontend *fe, u32 * frequency)
2554{
2555 struct dib0090_state *state = fe->tuner_priv;
2556
2557 *frequency = 1000 * state->current_rf;
2558 return 0;
2559}
2560
Mauro Carvalho Chehab14d24d12011-12-24 12:24:33 -03002561static int dib0090_set_params(struct dvb_frontend *fe)
Olivier Grenie03245a52009-12-04 13:27:57 -03002562{
2563 struct dib0090_state *state = fe->tuner_priv;
Olivier Grenie28fafca2011-01-04 04:27:11 -03002564 u32 ret;
Olivier Grenie03245a52009-12-04 13:27:57 -03002565
2566 state->tune_state = CT_TUNER_START;
2567
2568 do {
2569 ret = dib0090_tune(fe);
Mauro Carvalho Chehab0de04ca2014-07-04 14:15:36 -03002570 if (ret == FE_CALLBACK_TIME_NEVER)
Olivier Grenie03245a52009-12-04 13:27:57 -03002571 break;
Mauro Carvalho Chehab0de04ca2014-07-04 14:15:36 -03002572
2573 /*
2574 * Despite dib0090_tune returns time at a 0.1 ms range,
2575 * the actual sleep time depends on CONFIG_HZ. The worse case
2576 * is when CONFIG_HZ=100. In such case, the minimum granularity
2577 * is 10ms. On some real field tests, the tuner sometimes don't
2578 * lock when this timer is lower than 10ms. So, enforce a 10ms
2579 * granularity and use usleep_range() instead of msleep().
2580 */
2581 ret = 10 * (ret + 99)/100;
2582 usleep_range(ret * 1000, (ret + 1) * 1000);
Olivier Grenie03245a52009-12-04 13:27:57 -03002583 } while (state->tune_state != CT_TUNER_STOP);
2584
2585 return 0;
2586}
2587
2588static const struct dvb_tuner_ops dib0090_ops = {
2589 .info = {
2590 .name = "DiBcom DiB0090",
2591 .frequency_min = 45000000,
2592 .frequency_max = 860000000,
2593 .frequency_step = 1000,
2594 },
2595 .release = dib0090_release,
2596
2597 .init = dib0090_wakeup,
2598 .sleep = dib0090_sleep,
2599 .set_params = dib0090_set_params,
2600 .get_frequency = dib0090_get_frequency,
2601};
2602
Olivier Grenie28fafca2011-01-04 04:27:11 -03002603static const struct dvb_tuner_ops dib0090_fw_ops = {
2604 .info = {
2605 .name = "DiBcom DiB0090",
2606 .frequency_min = 45000000,
2607 .frequency_max = 860000000,
2608 .frequency_step = 1000,
2609 },
2610 .release = dib0090_release,
2611
2612 .init = NULL,
2613 .sleep = NULL,
2614 .set_params = NULL,
2615 .get_frequency = NULL,
2616};
2617
2618static const struct dib0090_wbd_slope dib0090_wbd_table_default[] = {
2619 {470, 0, 250, 0, 100, 4},
2620 {860, 51, 866, 21, 375, 4},
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002621 {1700, 0, 800, 0, 850, 4},
2622 {2900, 0, 250, 0, 100, 6},
Olivier Grenie28fafca2011-01-04 04:27:11 -03002623 {0xFFFF, 0, 0, 0, 0, 0},
2624};
2625
Olivier Grenie03245a52009-12-04 13:27:57 -03002626struct dvb_frontend *dib0090_register(struct dvb_frontend *fe, struct i2c_adapter *i2c, const struct dib0090_config *config)
2627{
2628 struct dib0090_state *st = kzalloc(sizeof(struct dib0090_state), GFP_KERNEL);
2629 if (st == NULL)
2630 return NULL;
2631
2632 st->config = config;
2633 st->i2c = i2c;
2634 st->fe = fe;
Patrick Boettcher79fcce32011-08-03 12:08:21 -03002635 mutex_init(&st->i2c_buffer_lock);
Olivier Grenie03245a52009-12-04 13:27:57 -03002636 fe->tuner_priv = st;
2637
Olivier Grenie28fafca2011-01-04 04:27:11 -03002638 if (config->wbd == NULL)
2639 st->current_wbd_table = dib0090_wbd_table_default;
2640 else
2641 st->current_wbd_table = config->wbd;
2642
Olivier Grenie03245a52009-12-04 13:27:57 -03002643 if (dib0090_reset(fe) != 0)
2644 goto free_mem;
2645
2646 printk(KERN_INFO "DiB0090: successfully identified\n");
2647 memcpy(&fe->ops.tuner_ops, &dib0090_ops, sizeof(struct dvb_tuner_ops));
2648
2649 return fe;
2650 free_mem:
2651 kfree(st);
2652 fe->tuner_priv = NULL;
2653 return NULL;
2654}
Olivier Grenie28fafca2011-01-04 04:27:11 -03002655
Olivier Grenie03245a52009-12-04 13:27:57 -03002656EXPORT_SYMBOL(dib0090_register);
2657
Olivier Grenie28fafca2011-01-04 04:27:11 -03002658struct dvb_frontend *dib0090_fw_register(struct dvb_frontend *fe, struct i2c_adapter *i2c, const struct dib0090_config *config)
2659{
2660 struct dib0090_fw_state *st = kzalloc(sizeof(struct dib0090_fw_state), GFP_KERNEL);
2661 if (st == NULL)
2662 return NULL;
2663
2664 st->config = config;
2665 st->i2c = i2c;
2666 st->fe = fe;
Patrick Boettcher79fcce32011-08-03 12:08:21 -03002667 mutex_init(&st->i2c_buffer_lock);
Olivier Grenie28fafca2011-01-04 04:27:11 -03002668 fe->tuner_priv = st;
2669
2670 if (dib0090_fw_reset_digital(fe, st->config) != 0)
2671 goto free_mem;
2672
2673 dprintk("DiB0090 FW: successfully identified");
2674 memcpy(&fe->ops.tuner_ops, &dib0090_fw_ops, sizeof(struct dvb_tuner_ops));
2675
2676 return fe;
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002677free_mem:
Olivier Grenie28fafca2011-01-04 04:27:11 -03002678 kfree(st);
2679 fe->tuner_priv = NULL;
2680 return NULL;
2681}
Olivier Grenie28fafca2011-01-04 04:27:11 -03002682EXPORT_SYMBOL(dib0090_fw_register);
2683
Patrick Boettcher99e44da2016-01-24 12:56:58 -02002684MODULE_AUTHOR("Patrick Boettcher <patrick.boettcher@posteo.de>");
2685MODULE_AUTHOR("Olivier Grenie <olivier.grenie@parrot.com>");
Olivier Grenie03245a52009-12-04 13:27:57 -03002686MODULE_DESCRIPTION("Driver for the DiBcom 0090 base-band RF Tuner");
2687MODULE_LICENSE("GPL");