blob: d13d2e81f8c9ec0047335bde0403fe2d53f5e53f [file] [log] [blame]
Thomas Gleixnerc942fdd2019-05-27 08:55:06 +02001// SPDX-License-Identifier: GPL-2.0-or-later
Olivier Grenie03245a52009-12-04 13:27:57 -03002/*
3 * Linux-DVB Driver for DiBcom's DiB0090 base-band RF Tuner.
4 *
5 * Copyright (C) 2005-9 DiBcom (http://www.dibcom.fr/)
6 *
Olivier Grenie03245a52009-12-04 13:27:57 -03007 * This code is more or less generated from another driver, please
8 * excuse some codingstyle oddities.
Olivier Grenie03245a52009-12-04 13:27:57 -03009 */
10
Mauro Carvalho Chehab4bd1a8d2016-10-14 08:16:43 -030011#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
12
Olivier Grenie03245a52009-12-04 13:27:57 -030013#include <linux/kernel.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090014#include <linux/slab.h>
Olivier Grenie03245a52009-12-04 13:27:57 -030015#include <linux/i2c.h>
Patrick Boettcher79fcce32011-08-03 12:08:21 -030016#include <linux/mutex.h>
Olivier Grenie03245a52009-12-04 13:27:57 -030017
Mauro Carvalho Chehabfada1932017-12-28 13:03:51 -050018#include <media/dvb_frontend.h>
Olivier Grenie03245a52009-12-04 13:27:57 -030019
20#include "dib0090.h"
21#include "dibx000_common.h"
22
23static int debug;
24module_param(debug, int, 0644);
25MODULE_PARM_DESC(debug, "turn on debugging (default: 0)");
26
Mauro Carvalho Chehab4bd1a8d2016-10-14 08:16:43 -030027#define dprintk(fmt, arg...) do { \
28 if (debug) \
29 printk(KERN_DEBUG pr_fmt("%s: " fmt), \
30 __func__, ##arg); \
Olivier Grenie03245a52009-12-04 13:27:57 -030031} while (0)
32
Olivier Grenie28fafca2011-01-04 04:27:11 -030033#define CONFIG_SYS_DVBT
Olivier Grenie03245a52009-12-04 13:27:57 -030034#define CONFIG_SYS_ISDBT
35#define CONFIG_BAND_CBAND
36#define CONFIG_BAND_VHF
37#define CONFIG_BAND_UHF
38#define CONFIG_DIB0090_USE_PWM_AGC
39
40#define EN_LNA0 0x8000
41#define EN_LNA1 0x4000
42#define EN_LNA2 0x2000
43#define EN_LNA3 0x1000
44#define EN_MIX0 0x0800
45#define EN_MIX1 0x0400
46#define EN_MIX2 0x0200
47#define EN_MIX3 0x0100
48#define EN_IQADC 0x0040
49#define EN_PLL 0x0020
50#define EN_TX 0x0010
51#define EN_BB 0x0008
52#define EN_LO 0x0004
53#define EN_BIAS 0x0001
54
55#define EN_IQANA 0x0002
56#define EN_DIGCLK 0x0080 /* not in the 0x24 reg, only in 0x1b */
57#define EN_CRYSTAL 0x0002
58
59#define EN_UHF 0x22E9
60#define EN_VHF 0x44E9
61#define EN_LBD 0x11E9
62#define EN_SBD 0x44E9
63#define EN_CAB 0x88E9
64
Olivier Grenie28fafca2011-01-04 04:27:11 -030065/* Calibration defines */
66#define DC_CAL 0x1
67#define WBD_CAL 0x2
68#define TEMP_CAL 0x4
69#define CAPTRIM_CAL 0x8
70
71#define KROSUS_PLL_LOCKED 0x800
72#define KROSUS 0x2
73
74/* Use those defines to identify SOC version */
75#define SOC 0x02
76#define SOC_7090_P1G_11R1 0x82
77#define SOC_7090_P1G_21R1 0x8a
78#define SOC_8090_P1G_11R1 0x86
79#define SOC_8090_P1G_21R1 0x8e
80
81/* else use thos ones to check */
82#define P1A_B 0x0
83#define P1C 0x1
84#define P1D_E_F 0x3
85#define P1G 0x7
86#define P1G_21R2 0xf
87
88#define MP001 0x1 /* Single 9090/8096 */
89#define MP005 0x4 /* Single Sband */
90#define MP008 0x6 /* Dual diversity VHF-UHF-LBAND */
91#define MP009 0x7 /* Dual diversity 29098 CBAND-UHF-LBAND-SBAND */
92
Olivier Grenie03245a52009-12-04 13:27:57 -030093#define pgm_read_word(w) (*w)
94
95struct dc_calibration;
96
97struct dib0090_tuning {
98 u32 max_freq; /* for every frequency less than or equal to that field: this information is correct */
99 u8 switch_trim;
100 u8 lna_tune;
Olivier Grenie28fafca2011-01-04 04:27:11 -0300101 u16 lna_bias;
Olivier Grenie03245a52009-12-04 13:27:57 -0300102 u16 v2i;
103 u16 mix;
104 u16 load;
105 u16 tuner_enable;
106};
107
108struct dib0090_pll {
109 u32 max_freq; /* for every frequency less than or equal to that field: this information is correct */
110 u8 vco_band;
111 u8 hfdiv_code;
112 u8 hfdiv;
113 u8 topresc;
114};
115
Olivier Grenie28fafca2011-01-04 04:27:11 -0300116struct dib0090_identity {
117 u8 version;
118 u8 product;
119 u8 p1g;
120 u8 in_soc;
121};
122
Olivier Grenie03245a52009-12-04 13:27:57 -0300123struct dib0090_state {
124 struct i2c_adapter *i2c;
125 struct dvb_frontend *fe;
126 const struct dib0090_config *config;
127
128 u8 current_band;
Olivier Grenie03245a52009-12-04 13:27:57 -0300129 enum frontend_tune_state tune_state;
130 u32 current_rf;
131
132 u16 wbd_offset;
133 s16 wbd_target; /* in dB */
134
135 s16 rf_gain_limit; /* take-over-point: where to split between bb and rf gain */
136 s16 current_gain; /* keeps the currently programmed gain */
137 u8 agc_step; /* new binary search */
138
139 u16 gain[2]; /* for channel monitoring */
140
141 const u16 *rf_ramp;
142 const u16 *bb_ramp;
143
144 /* for the software AGC ramps */
145 u16 bb_1_def;
146 u16 rf_lt_def;
147 u16 gain_reg[4];
148
149 /* for the captrim/dc-offset search */
150 s8 step;
151 s16 adc_diff;
152 s16 min_adc_diff;
153
154 s8 captrim;
155 s8 fcaptrim;
156
157 const struct dc_calibration *dc;
158 u16 bb6, bb7;
159
160 const struct dib0090_tuning *current_tune_table_index;
161 const struct dib0090_pll *current_pll_table_index;
162
163 u8 tuner_is_tuned;
164 u8 agc_freeze;
165
Olivier Grenie28fafca2011-01-04 04:27:11 -0300166 struct dib0090_identity identity;
167
168 u32 rf_request;
169 u8 current_standard;
170
171 u8 calibrate;
172 u32 rest;
173 u16 bias;
174 s16 temperature;
175
176 u8 wbd_calibration_gain;
177 const struct dib0090_wbd_slope *current_wbd_table;
178 u16 wbdmux;
Olivier Grenie5a0deee2011-05-03 12:27:33 -0300179
180 /* for the I2C transfer */
181 struct i2c_msg msg[2];
182 u8 i2c_write_buffer[3];
183 u8 i2c_read_buffer[2];
Patrick Boettcher79fcce32011-08-03 12:08:21 -0300184 struct mutex i2c_buffer_lock;
Olivier Grenie28fafca2011-01-04 04:27:11 -0300185};
186
187struct dib0090_fw_state {
188 struct i2c_adapter *i2c;
189 struct dvb_frontend *fe;
190 struct dib0090_identity identity;
191 const struct dib0090_config *config;
Olivier Grenie5a0deee2011-05-03 12:27:33 -0300192
193 /* for the I2C transfer */
194 struct i2c_msg msg;
195 u8 i2c_write_buffer[2];
196 u8 i2c_read_buffer[2];
Patrick Boettcher79fcce32011-08-03 12:08:21 -0300197 struct mutex i2c_buffer_lock;
Olivier Grenie03245a52009-12-04 13:27:57 -0300198};
199
200static u16 dib0090_read_reg(struct dib0090_state *state, u8 reg)
201{
Patrick Boettcher79fcce32011-08-03 12:08:21 -0300202 u16 ret;
203
204 if (mutex_lock_interruptible(&state->i2c_buffer_lock) < 0) {
Mauro Carvalho Chehab4bd1a8d2016-10-14 08:16:43 -0300205 dprintk("could not acquire lock\n");
Patrick Boettcher79fcce32011-08-03 12:08:21 -0300206 return 0;
207 }
208
Olivier Grenie5a0deee2011-05-03 12:27:33 -0300209 state->i2c_write_buffer[0] = reg;
210
211 memset(state->msg, 0, 2 * sizeof(struct i2c_msg));
212 state->msg[0].addr = state->config->i2c_address;
213 state->msg[0].flags = 0;
214 state->msg[0].buf = state->i2c_write_buffer;
215 state->msg[0].len = 1;
216 state->msg[1].addr = state->config->i2c_address;
217 state->msg[1].flags = I2C_M_RD;
218 state->msg[1].buf = state->i2c_read_buffer;
219 state->msg[1].len = 2;
220
221 if (i2c_transfer(state->i2c, state->msg, 2) != 2) {
Mauro Carvalho Chehab4bd1a8d2016-10-14 08:16:43 -0300222 pr_warn("DiB0090 I2C read failed\n");
Patrick Boettcher79fcce32011-08-03 12:08:21 -0300223 ret = 0;
224 } else
225 ret = (state->i2c_read_buffer[0] << 8)
226 | state->i2c_read_buffer[1];
Olivier Grenie5a0deee2011-05-03 12:27:33 -0300227
Patrick Boettcher79fcce32011-08-03 12:08:21 -0300228 mutex_unlock(&state->i2c_buffer_lock);
229 return ret;
Olivier Grenie03245a52009-12-04 13:27:57 -0300230}
231
232static int dib0090_write_reg(struct dib0090_state *state, u32 reg, u16 val)
233{
Patrick Boettcher79fcce32011-08-03 12:08:21 -0300234 int ret;
235
236 if (mutex_lock_interruptible(&state->i2c_buffer_lock) < 0) {
Mauro Carvalho Chehab4bd1a8d2016-10-14 08:16:43 -0300237 dprintk("could not acquire lock\n");
Patrick Boettcher79fcce32011-08-03 12:08:21 -0300238 return -EINVAL;
239 }
240
Olivier Grenie5a0deee2011-05-03 12:27:33 -0300241 state->i2c_write_buffer[0] = reg & 0xff;
242 state->i2c_write_buffer[1] = val >> 8;
243 state->i2c_write_buffer[2] = val & 0xff;
244
245 memset(state->msg, 0, sizeof(struct i2c_msg));
246 state->msg[0].addr = state->config->i2c_address;
247 state->msg[0].flags = 0;
248 state->msg[0].buf = state->i2c_write_buffer;
249 state->msg[0].len = 3;
250
251 if (i2c_transfer(state->i2c, state->msg, 1) != 1) {
Mauro Carvalho Chehab4bd1a8d2016-10-14 08:16:43 -0300252 pr_warn("DiB0090 I2C write failed\n");
Patrick Boettcher79fcce32011-08-03 12:08:21 -0300253 ret = -EREMOTEIO;
254 } else
255 ret = 0;
256
257 mutex_unlock(&state->i2c_buffer_lock);
258 return ret;
Olivier Grenie28fafca2011-01-04 04:27:11 -0300259}
260
261static u16 dib0090_fw_read_reg(struct dib0090_fw_state *state, u8 reg)
262{
Patrick Boettcher79fcce32011-08-03 12:08:21 -0300263 u16 ret;
264
265 if (mutex_lock_interruptible(&state->i2c_buffer_lock) < 0) {
Mauro Carvalho Chehab4bd1a8d2016-10-14 08:16:43 -0300266 dprintk("could not acquire lock\n");
Patrick Boettcher79fcce32011-08-03 12:08:21 -0300267 return 0;
268 }
269
Olivier Grenie5a0deee2011-05-03 12:27:33 -0300270 state->i2c_write_buffer[0] = reg;
271
272 memset(&state->msg, 0, sizeof(struct i2c_msg));
273 state->msg.addr = reg;
274 state->msg.flags = I2C_M_RD;
275 state->msg.buf = state->i2c_read_buffer;
276 state->msg.len = 2;
277 if (i2c_transfer(state->i2c, &state->msg, 1) != 1) {
Mauro Carvalho Chehab4bd1a8d2016-10-14 08:16:43 -0300278 pr_warn("DiB0090 I2C read failed\n");
Patrick Boettcher79fcce32011-08-03 12:08:21 -0300279 ret = 0;
280 } else
281 ret = (state->i2c_read_buffer[0] << 8)
282 | state->i2c_read_buffer[1];
283
284 mutex_unlock(&state->i2c_buffer_lock);
285 return ret;
Olivier Grenie28fafca2011-01-04 04:27:11 -0300286}
287
288static int dib0090_fw_write_reg(struct dib0090_fw_state *state, u8 reg, u16 val)
289{
Patrick Boettcher79fcce32011-08-03 12:08:21 -0300290 int ret;
291
292 if (mutex_lock_interruptible(&state->i2c_buffer_lock) < 0) {
Mauro Carvalho Chehab4bd1a8d2016-10-14 08:16:43 -0300293 dprintk("could not acquire lock\n");
Patrick Boettcher79fcce32011-08-03 12:08:21 -0300294 return -EINVAL;
295 }
296
Olivier Grenie5a0deee2011-05-03 12:27:33 -0300297 state->i2c_write_buffer[0] = val >> 8;
298 state->i2c_write_buffer[1] = val & 0xff;
299
300 memset(&state->msg, 0, sizeof(struct i2c_msg));
301 state->msg.addr = reg;
302 state->msg.flags = 0;
303 state->msg.buf = state->i2c_write_buffer;
304 state->msg.len = 2;
305 if (i2c_transfer(state->i2c, &state->msg, 1) != 1) {
Mauro Carvalho Chehab4bd1a8d2016-10-14 08:16:43 -0300306 pr_warn("DiB0090 I2C write failed\n");
Patrick Boettcher79fcce32011-08-03 12:08:21 -0300307 ret = -EREMOTEIO;
308 } else
309 ret = 0;
310
311 mutex_unlock(&state->i2c_buffer_lock);
312 return ret;
Olivier Grenie03245a52009-12-04 13:27:57 -0300313}
314
315#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)
316#define ADC_TARGET -220
317#define GAIN_ALPHA 5
318#define WBD_ALPHA 6
319#define LPF 100
320static void dib0090_write_regs(struct dib0090_state *state, u8 r, const u16 * b, u8 c)
321{
322 do {
323 dib0090_write_reg(state, r++, *b++);
324 } while (--c);
325}
326
Olivier Grenie28fafca2011-01-04 04:27:11 -0300327static int dib0090_identify(struct dvb_frontend *fe)
Olivier Grenie03245a52009-12-04 13:27:57 -0300328{
329 struct dib0090_state *state = fe->tuner_priv;
330 u16 v;
Olivier Grenie28fafca2011-01-04 04:27:11 -0300331 struct dib0090_identity *identity = &state->identity;
Olivier Grenie03245a52009-12-04 13:27:57 -0300332
333 v = dib0090_read_reg(state, 0x1a);
334
Olivier Grenie28fafca2011-01-04 04:27:11 -0300335 identity->p1g = 0;
336 identity->in_soc = 0;
337
Mauro Carvalho Chehab4bd1a8d2016-10-14 08:16:43 -0300338 dprintk("Tuner identification (Version = 0x%04x)\n", v);
Olivier Grenie03245a52009-12-04 13:27:57 -0300339
340 /* without PLL lock info */
Olivier Grenie28fafca2011-01-04 04:27:11 -0300341 v &= ~KROSUS_PLL_LOCKED;
Olivier Grenie03245a52009-12-04 13:27:57 -0300342
Olivier Grenie28fafca2011-01-04 04:27:11 -0300343 identity->version = v & 0xff;
344 identity->product = (v >> 8) & 0xf;
Olivier Grenie03245a52009-12-04 13:27:57 -0300345
Olivier Grenie28fafca2011-01-04 04:27:11 -0300346 if (identity->product != KROSUS)
347 goto identification_error;
Olivier Grenie03245a52009-12-04 13:27:57 -0300348
Olivier Grenie28fafca2011-01-04 04:27:11 -0300349 if ((identity->version & 0x3) == SOC) {
350 identity->in_soc = 1;
351 switch (identity->version) {
352 case SOC_8090_P1G_11R1:
Mauro Carvalho Chehab4bd1a8d2016-10-14 08:16:43 -0300353 dprintk("SOC 8090 P1-G11R1 Has been detected\n");
Olivier Grenie28fafca2011-01-04 04:27:11 -0300354 identity->p1g = 1;
355 break;
356 case SOC_8090_P1G_21R1:
Mauro Carvalho Chehab4bd1a8d2016-10-14 08:16:43 -0300357 dprintk("SOC 8090 P1-G21R1 Has been detected\n");
Olivier Grenie28fafca2011-01-04 04:27:11 -0300358 identity->p1g = 1;
359 break;
360 case SOC_7090_P1G_11R1:
Mauro Carvalho Chehab4bd1a8d2016-10-14 08:16:43 -0300361 dprintk("SOC 7090 P1-G11R1 Has been detected\n");
Olivier Grenie28fafca2011-01-04 04:27:11 -0300362 identity->p1g = 1;
363 break;
364 case SOC_7090_P1G_21R1:
Mauro Carvalho Chehab4bd1a8d2016-10-14 08:16:43 -0300365 dprintk("SOC 7090 P1-G21R1 Has been detected\n");
Olivier Grenie28fafca2011-01-04 04:27:11 -0300366 identity->p1g = 1;
367 break;
368 default:
369 goto identification_error;
370 }
371 } else {
372 switch ((identity->version >> 5) & 0x7) {
373 case MP001:
Mauro Carvalho Chehab4bd1a8d2016-10-14 08:16:43 -0300374 dprintk("MP001 : 9090/8096\n");
Olivier Grenie28fafca2011-01-04 04:27:11 -0300375 break;
376 case MP005:
Mauro Carvalho Chehab4bd1a8d2016-10-14 08:16:43 -0300377 dprintk("MP005 : Single Sband\n");
Olivier Grenie28fafca2011-01-04 04:27:11 -0300378 break;
379 case MP008:
Mauro Carvalho Chehab4bd1a8d2016-10-14 08:16:43 -0300380 dprintk("MP008 : diversity VHF-UHF-LBAND\n");
Olivier Grenie28fafca2011-01-04 04:27:11 -0300381 break;
382 case MP009:
Mauro Carvalho Chehab4bd1a8d2016-10-14 08:16:43 -0300383 dprintk("MP009 : diversity 29098 CBAND-UHF-LBAND-SBAND\n");
Olivier Grenie28fafca2011-01-04 04:27:11 -0300384 break;
385 default:
386 goto identification_error;
387 }
388
389 switch (identity->version & 0x1f) {
390 case P1G_21R2:
Mauro Carvalho Chehab4bd1a8d2016-10-14 08:16:43 -0300391 dprintk("P1G_21R2 detected\n");
Olivier Grenie28fafca2011-01-04 04:27:11 -0300392 identity->p1g = 1;
393 break;
394 case P1G:
Mauro Carvalho Chehab4bd1a8d2016-10-14 08:16:43 -0300395 dprintk("P1G detected\n");
Olivier Grenie28fafca2011-01-04 04:27:11 -0300396 identity->p1g = 1;
397 break;
398 case P1D_E_F:
Mauro Carvalho Chehab4bd1a8d2016-10-14 08:16:43 -0300399 dprintk("P1D/E/F detected\n");
Olivier Grenie28fafca2011-01-04 04:27:11 -0300400 break;
401 case P1C:
Mauro Carvalho Chehab4bd1a8d2016-10-14 08:16:43 -0300402 dprintk("P1C detected\n");
Olivier Grenie28fafca2011-01-04 04:27:11 -0300403 break;
404 case P1A_B:
Mauro Carvalho Chehab4bd1a8d2016-10-14 08:16:43 -0300405 dprintk("P1-A/B detected: driver is deactivated - not available\n");
Olivier Grenie28fafca2011-01-04 04:27:11 -0300406 goto identification_error;
407 break;
408 default:
409 goto identification_error;
410 }
Olivier Grenie03245a52009-12-04 13:27:57 -0300411 }
412
Olivier Grenie28fafca2011-01-04 04:27:11 -0300413 return 0;
414
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300415identification_error:
Olivier Grenie28fafca2011-01-04 04:27:11 -0300416 return -EIO;
417}
418
419static int dib0090_fw_identify(struct dvb_frontend *fe)
420{
421 struct dib0090_fw_state *state = fe->tuner_priv;
422 struct dib0090_identity *identity = &state->identity;
423
424 u16 v = dib0090_fw_read_reg(state, 0x1a);
425 identity->p1g = 0;
426 identity->in_soc = 0;
427
Mauro Carvalho Chehab4bd1a8d2016-10-14 08:16:43 -0300428 dprintk("FE: Tuner identification (Version = 0x%04x)\n", v);
Olivier Grenie28fafca2011-01-04 04:27:11 -0300429
430 /* without PLL lock info */
431 v &= ~KROSUS_PLL_LOCKED;
432
433 identity->version = v & 0xff;
434 identity->product = (v >> 8) & 0xf;
435
436 if (identity->product != KROSUS)
437 goto identification_error;
438
Olivier Grenie28fafca2011-01-04 04:27:11 -0300439 if ((identity->version & 0x3) == SOC) {
440 identity->in_soc = 1;
441 switch (identity->version) {
442 case SOC_8090_P1G_11R1:
Mauro Carvalho Chehab4bd1a8d2016-10-14 08:16:43 -0300443 dprintk("SOC 8090 P1-G11R1 Has been detected\n");
Olivier Grenie28fafca2011-01-04 04:27:11 -0300444 identity->p1g = 1;
445 break;
446 case SOC_8090_P1G_21R1:
Mauro Carvalho Chehab4bd1a8d2016-10-14 08:16:43 -0300447 dprintk("SOC 8090 P1-G21R1 Has been detected\n");
Olivier Grenie28fafca2011-01-04 04:27:11 -0300448 identity->p1g = 1;
449 break;
450 case SOC_7090_P1G_11R1:
Mauro Carvalho Chehab4bd1a8d2016-10-14 08:16:43 -0300451 dprintk("SOC 7090 P1-G11R1 Has been detected\n");
Olivier Grenie28fafca2011-01-04 04:27:11 -0300452 identity->p1g = 1;
453 break;
454 case SOC_7090_P1G_21R1:
Mauro Carvalho Chehab4bd1a8d2016-10-14 08:16:43 -0300455 dprintk("SOC 7090 P1-G21R1 Has been detected\n");
Olivier Grenie28fafca2011-01-04 04:27:11 -0300456 identity->p1g = 1;
457 break;
458 default:
459 goto identification_error;
460 }
461 } else {
462 switch ((identity->version >> 5) & 0x7) {
463 case MP001:
Mauro Carvalho Chehab4bd1a8d2016-10-14 08:16:43 -0300464 dprintk("MP001 : 9090/8096\n");
Olivier Grenie28fafca2011-01-04 04:27:11 -0300465 break;
466 case MP005:
Mauro Carvalho Chehab4bd1a8d2016-10-14 08:16:43 -0300467 dprintk("MP005 : Single Sband\n");
Olivier Grenie28fafca2011-01-04 04:27:11 -0300468 break;
469 case MP008:
Mauro Carvalho Chehab4bd1a8d2016-10-14 08:16:43 -0300470 dprintk("MP008 : diversity VHF-UHF-LBAND\n");
Olivier Grenie28fafca2011-01-04 04:27:11 -0300471 break;
472 case MP009:
Mauro Carvalho Chehab4bd1a8d2016-10-14 08:16:43 -0300473 dprintk("MP009 : diversity 29098 CBAND-UHF-LBAND-SBAND\n");
Olivier Grenie28fafca2011-01-04 04:27:11 -0300474 break;
475 default:
476 goto identification_error;
477 }
478
479 switch (identity->version & 0x1f) {
480 case P1G_21R2:
Mauro Carvalho Chehab4bd1a8d2016-10-14 08:16:43 -0300481 dprintk("P1G_21R2 detected\n");
Olivier Grenie28fafca2011-01-04 04:27:11 -0300482 identity->p1g = 1;
483 break;
484 case P1G:
Mauro Carvalho Chehab4bd1a8d2016-10-14 08:16:43 -0300485 dprintk("P1G detected\n");
Olivier Grenie28fafca2011-01-04 04:27:11 -0300486 identity->p1g = 1;
487 break;
488 case P1D_E_F:
Mauro Carvalho Chehab4bd1a8d2016-10-14 08:16:43 -0300489 dprintk("P1D/E/F detected\n");
Olivier Grenie28fafca2011-01-04 04:27:11 -0300490 break;
491 case P1C:
Mauro Carvalho Chehab4bd1a8d2016-10-14 08:16:43 -0300492 dprintk("P1C detected\n");
Olivier Grenie28fafca2011-01-04 04:27:11 -0300493 break;
494 case P1A_B:
Mauro Carvalho Chehab4bd1a8d2016-10-14 08:16:43 -0300495 dprintk("P1-A/B detected: driver is deactivated - not available\n");
Olivier Grenie28fafca2011-01-04 04:27:11 -0300496 goto identification_error;
497 break;
498 default:
499 goto identification_error;
500 }
501 }
502
503 return 0;
504
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300505identification_error:
Jesper Juhlf1ed3212012-02-26 18:57:13 -0300506 return -EIO;
Olivier Grenie03245a52009-12-04 13:27:57 -0300507}
508
509static void dib0090_reset_digital(struct dvb_frontend *fe, const struct dib0090_config *cfg)
510{
511 struct dib0090_state *state = fe->tuner_priv;
Olivier Grenie28fafca2011-01-04 04:27:11 -0300512 u16 PllCfg, i, v;
Olivier Grenie03245a52009-12-04 13:27:57 -0300513
514 HARD_RESET(state);
Olivier Grenie28fafca2011-01-04 04:27:11 -0300515 dib0090_write_reg(state, 0x24, EN_PLL | EN_CRYSTAL);
Olivier Grenieaedabf72012-12-31 10:38:44 -0300516 if (cfg->in_soc)
517 return;
Olivier Grenie03245a52009-12-04 13:27:57 -0300518
Olivier Grenieaedabf72012-12-31 10:38:44 -0300519 dib0090_write_reg(state, 0x1b, EN_DIGCLK | EN_PLL | EN_CRYSTAL); /* PLL, DIG_CLK and CRYSTAL remain */
520 /* adcClkOutRatio=8->7, release reset */
521 dib0090_write_reg(state, 0x20, ((cfg->io.adc_clock_ratio - 1) << 11) | (0 << 10) | (1 << 9) | (1 << 8) | (0 << 4) | 0);
522 if (cfg->clkoutdrive != 0)
523 dib0090_write_reg(state, 0x23, (0 << 15) | ((!cfg->analog_output) << 14) | (2 << 10) | (1 << 9) | (0 << 8)
524 | (cfg->clkoutdrive << 5) | (cfg->clkouttobamse << 4) | (0 << 2) | (0));
525 else
526 dib0090_write_reg(state, 0x23, (0 << 15) | ((!cfg->analog_output) << 14) | (2 << 10) | (1 << 9) | (0 << 8)
527 | (7 << 5) | (cfg->clkouttobamse << 4) | (0 << 2) | (0));
Olivier Grenie28fafca2011-01-04 04:27:11 -0300528
529 /* Read Pll current config * */
530 PllCfg = dib0090_read_reg(state, 0x21);
531
532 /** Reconfigure PLL if current setting is different from default setting **/
533 if ((PllCfg & 0x1FFF) != ((cfg->io.pll_range << 12) | (cfg->io.pll_loopdiv << 6) | (cfg->io.pll_prediv)) && (!cfg->in_soc)
534 && !cfg->io.pll_bypass) {
535
536 /* Set Bypass mode */
537 PllCfg |= (1 << 15);
538 dib0090_write_reg(state, 0x21, PllCfg);
539
540 /* Set Reset Pll */
541 PllCfg &= ~(1 << 13);
542 dib0090_write_reg(state, 0x21, PllCfg);
543
544 /*** Set new Pll configuration in bypass and reset state ***/
545 PllCfg = (1 << 15) | (0 << 13) | (cfg->io.pll_range << 12) | (cfg->io.pll_loopdiv << 6) | (cfg->io.pll_prediv);
546 dib0090_write_reg(state, 0x21, PllCfg);
547
548 /* Remove Reset Pll */
549 PllCfg |= (1 << 13);
550 dib0090_write_reg(state, 0x21, PllCfg);
551
552 /*** Wait for PLL lock ***/
553 i = 100;
554 do {
555 v = !!(dib0090_read_reg(state, 0x1a) & 0x800);
556 if (v)
557 break;
558 } while (--i);
559
560 if (i == 0) {
Mauro Carvalho Chehab4bd1a8d2016-10-14 08:16:43 -0300561 dprintk("Pll: Unable to lock Pll\n");
Olivier Grenie28fafca2011-01-04 04:27:11 -0300562 return;
563 }
564
565 /* Finally Remove Bypass mode */
566 PllCfg &= ~(1 << 15);
567 dib0090_write_reg(state, 0x21, PllCfg);
568 }
569
570 if (cfg->io.pll_bypass) {
571 PllCfg |= (cfg->io.pll_bypass << 15);
572 dib0090_write_reg(state, 0x21, PllCfg);
573 }
574}
575
576static int dib0090_fw_reset_digital(struct dvb_frontend *fe, const struct dib0090_config *cfg)
577{
578 struct dib0090_fw_state *state = fe->tuner_priv;
579 u16 PllCfg;
580 u16 v;
581 int i;
582
Mauro Carvalho Chehab4bd1a8d2016-10-14 08:16:43 -0300583 dprintk("fw reset digital\n");
Olivier Grenie28fafca2011-01-04 04:27:11 -0300584 HARD_RESET(state);
585
586 dib0090_fw_write_reg(state, 0x24, EN_PLL | EN_CRYSTAL);
587 dib0090_fw_write_reg(state, 0x1b, EN_DIGCLK | EN_PLL | EN_CRYSTAL); /* PLL, DIG_CLK and CRYSTAL remain */
588
589 dib0090_fw_write_reg(state, 0x20,
590 ((cfg->io.adc_clock_ratio - 1) << 11) | (0 << 10) | (1 << 9) | (1 << 8) | (cfg->data_tx_drv << 4) | cfg->ls_cfg_pad_drv);
591
592 v = (0 << 15) | ((!cfg->analog_output) << 14) | (1 << 9) | (0 << 8) | (cfg->clkouttobamse << 4) | (0 << 2) | (0);
Olivier Grenie03245a52009-12-04 13:27:57 -0300593 if (cfg->clkoutdrive != 0)
Olivier Grenie28fafca2011-01-04 04:27:11 -0300594 v |= cfg->clkoutdrive << 5;
Olivier Grenie03245a52009-12-04 13:27:57 -0300595 else
Olivier Grenie28fafca2011-01-04 04:27:11 -0300596 v |= 7 << 5;
Olivier Grenie03245a52009-12-04 13:27:57 -0300597
Olivier Grenie28fafca2011-01-04 04:27:11 -0300598 v |= 2 << 10;
599 dib0090_fw_write_reg(state, 0x23, v);
Olivier Grenie03245a52009-12-04 13:27:57 -0300600
Olivier Grenie28fafca2011-01-04 04:27:11 -0300601 /* Read Pll current config * */
602 PllCfg = dib0090_fw_read_reg(state, 0x21);
603
604 /** Reconfigure PLL if current setting is different from default setting **/
605 if ((PllCfg & 0x1FFF) != ((cfg->io.pll_range << 12) | (cfg->io.pll_loopdiv << 6) | (cfg->io.pll_prediv)) && !cfg->io.pll_bypass) {
606
607 /* Set Bypass mode */
608 PllCfg |= (1 << 15);
609 dib0090_fw_write_reg(state, 0x21, PllCfg);
610
611 /* Set Reset Pll */
612 PllCfg &= ~(1 << 13);
613 dib0090_fw_write_reg(state, 0x21, PllCfg);
614
615 /*** Set new Pll configuration in bypass and reset state ***/
616 PllCfg = (1 << 15) | (0 << 13) | (cfg->io.pll_range << 12) | (cfg->io.pll_loopdiv << 6) | (cfg->io.pll_prediv);
617 dib0090_fw_write_reg(state, 0x21, PllCfg);
618
619 /* Remove Reset Pll */
620 PllCfg |= (1 << 13);
621 dib0090_fw_write_reg(state, 0x21, PllCfg);
622
623 /*** Wait for PLL lock ***/
624 i = 100;
625 do {
626 v = !!(dib0090_fw_read_reg(state, 0x1a) & 0x800);
627 if (v)
628 break;
629 } while (--i);
630
631 if (i == 0) {
Mauro Carvalho Chehab4bd1a8d2016-10-14 08:16:43 -0300632 dprintk("Pll: Unable to lock Pll\n");
Olivier Grenie28fafca2011-01-04 04:27:11 -0300633 return -EIO;
634 }
635
636 /* Finally Remove Bypass mode */
637 PllCfg &= ~(1 << 15);
638 dib0090_fw_write_reg(state, 0x21, PllCfg);
639 }
640
641 if (cfg->io.pll_bypass) {
642 PllCfg |= (cfg->io.pll_bypass << 15);
643 dib0090_fw_write_reg(state, 0x21, PllCfg);
644 }
645
646 return dib0090_fw_identify(fe);
Olivier Grenie03245a52009-12-04 13:27:57 -0300647}
648
649static int dib0090_wakeup(struct dvb_frontend *fe)
650{
651 struct dib0090_state *state = fe->tuner_priv;
652 if (state->config->sleep)
653 state->config->sleep(fe, 0);
Olivier Grenie28fafca2011-01-04 04:27:11 -0300654
655 /* enable dataTX in case we have been restarted in the wrong moment */
656 dib0090_write_reg(state, 0x23, dib0090_read_reg(state, 0x23) | (1 << 14));
Olivier Grenie03245a52009-12-04 13:27:57 -0300657 return 0;
658}
659
660static int dib0090_sleep(struct dvb_frontend *fe)
661{
662 struct dib0090_state *state = fe->tuner_priv;
663 if (state->config->sleep)
664 state->config->sleep(fe, 1);
665 return 0;
666}
667
Márton Németh43e3e6d2010-01-16 14:35:03 -0300668void dib0090_dcc_freq(struct dvb_frontend *fe, u8 fast)
Olivier Grenie03245a52009-12-04 13:27:57 -0300669{
670 struct dib0090_state *state = fe->tuner_priv;
671 if (fast)
Olivier Grenie9c783032009-12-07 07:49:40 -0300672 dib0090_write_reg(state, 0x04, 0);
Olivier Grenie03245a52009-12-04 13:27:57 -0300673 else
Olivier Grenie9c783032009-12-07 07:49:40 -0300674 dib0090_write_reg(state, 0x04, 1);
Olivier Grenie03245a52009-12-04 13:27:57 -0300675}
Olivier Grenie28fafca2011-01-04 04:27:11 -0300676
Olivier Grenie03245a52009-12-04 13:27:57 -0300677EXPORT_SYMBOL(dib0090_dcc_freq);
Olivier Grenie9c783032009-12-07 07:49:40 -0300678
Olivier Grenie28fafca2011-01-04 04:27:11 -0300679static const u16 bb_ramp_pwm_normal_socs[] = {
Olivier Grenieaedabf72012-12-31 10:38:44 -0300680 550, /* max BB gain in 10th of dB */
681 (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 -0300682 440,
Olivier Grenieaedabf72012-12-31 10:38:44 -0300683 (4 << 9) | 0, /* BB_RAMP3 = 26dB */
684 (0 << 9) | 208, /* BB_RAMP4 */
685 (4 << 9) | 208, /* BB_RAMP5 = 29dB */
686 (0 << 9) | 440, /* BB_RAMP6 */
Olivier Grenie28fafca2011-01-04 04:27:11 -0300687};
688
Olivier Grenieaedabf72012-12-31 10:38:44 -0300689static const u16 rf_ramp_pwm_cband_7090p[] = {
690 280, /* max RF gain in 10th of dB */
691 18, /* ramp_slope = 1dB of gain -> clock_ticks_per_db = clk_khz / ramp_slope -> RF_RAMP2 */
692 504, /* ramp_max = maximum X used on the ramp */
693 (29 << 10) | 364, /* RF_RAMP5, LNA 1 = 8dB */
694 (0 << 10) | 504, /* RF_RAMP6, LNA 1 */
695 (60 << 10) | 228, /* RF_RAMP7, LNA 2 = 7.7dB */
696 (0 << 10) | 364, /* RF_RAMP8, LNA 2 */
697 (34 << 10) | 109, /* GAIN_4_1, LNA 3 = 6.8dB */
698 (0 << 10) | 228, /* GAIN_4_2, LNA 3 */
699 (37 << 10) | 0, /* RF_RAMP3, LNA 4 = 6.2dB */
700 (0 << 10) | 109, /* RF_RAMP4, LNA 4 */
Olivier Grenie28fafca2011-01-04 04:27:11 -0300701};
702
Olivier Grenieaedabf72012-12-31 10:38:44 -0300703static const u16 rf_ramp_pwm_cband_7090e_sensitivity[] = {
704 186, /* max RF gain in 10th of dB */
705 40, /* ramp_slope = 1dB of gain -> clock_ticks_per_db = clk_khz / ramp_slope -> RF_RAMP2 */
706 746, /* ramp_max = maximum X used on the ramp */
707 (10 << 10) | 345, /* RF_RAMP5, LNA 1 = 10dB */
708 (0 << 10) | 746, /* RF_RAMP6, LNA 1 */
709 (0 << 10) | 0, /* RF_RAMP7, LNA 2 = 0 dB */
710 (0 << 10) | 0, /* RF_RAMP8, LNA 2 */
711 (28 << 10) | 200, /* GAIN_4_1, LNA 3 = 6.8dB */ /* 3.61 dB */
712 (0 << 10) | 345, /* GAIN_4_2, LNA 3 */
713 (20 << 10) | 0, /* RF_RAMP3, LNA 4 = 6.2dB */ /* 4.96 dB */
714 (0 << 10) | 200, /* RF_RAMP4, LNA 4 */
Olivier Grenie6724a2f2011-08-05 13:49:33 -0300715};
716
Olivier Grenieaedabf72012-12-31 10:38:44 -0300717static const u16 rf_ramp_pwm_cband_7090e_aci[] = {
718 86, /* max RF gain in 10th of dB */
719 40, /* ramp_slope = 1dB of gain -> clock_ticks_per_db = clk_khz / ramp_slope -> RF_RAMP2 */
720 345, /* ramp_max = maximum X used on the ramp */
721 (0 << 10) | 0, /* RF_RAMP5, LNA 1 = 8dB */ /* 7.47 dB */
722 (0 << 10) | 0, /* RF_RAMP6, LNA 1 */
723 (0 << 10) | 0, /* RF_RAMP7, LNA 2 = 0 dB */
724 (0 << 10) | 0, /* RF_RAMP8, LNA 2 */
725 (28 << 10) | 200, /* GAIN_4_1, LNA 3 = 6.8dB */ /* 3.61 dB */
726 (0 << 10) | 345, /* GAIN_4_2, LNA 3 */
727 (20 << 10) | 0, /* RF_RAMP3, LNA 4 = 6.2dB */ /* 4.96 dB */
728 (0 << 10) | 200, /* RF_RAMP4, LNA 4 */
Olivier Grenie6724a2f2011-08-05 13:49:33 -0300729};
730
Olivier Grenie28fafca2011-01-04 04:27:11 -0300731static const u16 rf_ramp_pwm_cband_8090[] = {
Olivier Grenieaedabf72012-12-31 10:38:44 -0300732 345, /* max RF gain in 10th of dB */
733 29, /* ramp_slope = 1dB of gain -> clock_ticks_per_db = clk_khz / ramp_slope -> RF_RAMP2 */
734 1000, /* ramp_max = maximum X used on the ramp */
735 (35 << 10) | 772, /* RF_RAMP3, LNA 1 = 8dB */
736 (0 << 10) | 1000, /* RF_RAMP4, LNA 1 */
737 (58 << 10) | 496, /* RF_RAMP5, LNA 2 = 9.5dB */
738 (0 << 10) | 772, /* RF_RAMP6, LNA 2 */
739 (27 << 10) | 200, /* RF_RAMP7, LNA 3 = 10.5dB */
740 (0 << 10) | 496, /* RF_RAMP8, LNA 3 */
741 (40 << 10) | 0, /* GAIN_4_1, LNA 4 = 7dB */
742 (0 << 10) | 200, /* GAIN_4_2, LNA 4 */
Olivier Grenie28fafca2011-01-04 04:27:11 -0300743};
744
745static const u16 rf_ramp_pwm_uhf_7090[] = {
Olivier Grenieaedabf72012-12-31 10:38:44 -0300746 407, /* max RF gain in 10th of dB */
747 13, /* ramp_slope = 1dB of gain -> clock_ticks_per_db = clk_khz / ramp_slope -> RF_RAMP2 */
748 529, /* ramp_max = maximum X used on the ramp */
749 (23 << 10) | 0, /* RF_RAMP3, LNA 1 = 14.7dB */
750 (0 << 10) | 176, /* RF_RAMP4, LNA 1 */
751 (63 << 10) | 400, /* RF_RAMP5, LNA 2 = 8dB */
752 (0 << 10) | 529, /* RF_RAMP6, LNA 2 */
753 (48 << 10) | 316, /* RF_RAMP7, LNA 3 = 6.8dB */
754 (0 << 10) | 400, /* RF_RAMP8, LNA 3 */
755 (29 << 10) | 176, /* GAIN_4_1, LNA 4 = 11.5dB */
756 (0 << 10) | 316, /* GAIN_4_2, LNA 4 */
Olivier Grenie28fafca2011-01-04 04:27:11 -0300757};
758
759static const u16 rf_ramp_pwm_uhf_8090[] = {
Olivier Grenieaedabf72012-12-31 10:38:44 -0300760 388, /* max RF gain in 10th of dB */
761 26, /* ramp_slope = 1dB of gain -> clock_ticks_per_db = clk_khz / ramp_slope -> RF_RAMP2 */
762 1008, /* ramp_max = maximum X used on the ramp */
763 (11 << 10) | 0, /* RF_RAMP3, LNA 1 = 14.7dB */
764 (0 << 10) | 369, /* RF_RAMP4, LNA 1 */
765 (41 << 10) | 809, /* RF_RAMP5, LNA 2 = 8dB */
766 (0 << 10) | 1008, /* RF_RAMP6, LNA 2 */
767 (27 << 10) | 659, /* RF_RAMP7, LNA 3 = 6dB */
768 (0 << 10) | 809, /* RF_RAMP8, LNA 3 */
769 (14 << 10) | 369, /* GAIN_4_1, LNA 4 = 11.5dB */
770 (0 << 10) | 659, /* GAIN_4_2, LNA 4 */
771};
772
773/* GENERAL PWM ramp definition for all other Krosus */
774static const u16 bb_ramp_pwm_normal[] = {
775 500, /* max BB gain in 10th of dB */
776 8, /* ramp_slope = 1dB of gain -> clock_ticks_per_db = clk_khz / ramp_slope -> BB_RAMP2 */
777 400,
778 (2 << 9) | 0, /* BB_RAMP3 = 21dB */
779 (0 << 9) | 168, /* BB_RAMP4 */
780 (2 << 9) | 168, /* BB_RAMP5 = 29dB */
781 (0 << 9) | 400, /* BB_RAMP6 */
782};
783
Mauro Carvalho Chehabcf47fac2016-06-24 11:12:17 -0300784#if 0
785/* Currently unused */
Olivier Grenieaedabf72012-12-31 10:38:44 -0300786static const u16 bb_ramp_pwm_boost[] = {
787 550, /* max BB gain in 10th of dB */
788 8, /* ramp_slope = 1dB of gain -> clock_ticks_per_db = clk_khz / ramp_slope -> BB_RAMP2 */
789 440,
790 (2 << 9) | 0, /* BB_RAMP3 = 26dB */
791 (0 << 9) | 208, /* BB_RAMP4 */
792 (2 << 9) | 208, /* BB_RAMP5 = 29dB */
793 (0 << 9) | 440, /* BB_RAMP6 */
Olivier Grenie28fafca2011-01-04 04:27:11 -0300794};
Mauro Carvalho Chehabcf47fac2016-06-24 11:12:17 -0300795#endif
Olivier Grenie28fafca2011-01-04 04:27:11 -0300796
Olivier Grenie03245a52009-12-04 13:27:57 -0300797static const u16 rf_ramp_pwm_cband[] = {
Olivier Grenieaedabf72012-12-31 10:38:44 -0300798 314, /* max RF gain in 10th of dB */
799 33, /* ramp_slope = 1dB of gain -> clock_ticks_per_db = clk_khz / ramp_slope -> RF_RAMP2 */
800 1023, /* ramp_max = maximum X used on the ramp */
801 (8 << 10) | 743, /* RF_RAMP3, LNA 1 = 0dB */
802 (0 << 10) | 1023, /* RF_RAMP4, LNA 1 */
803 (15 << 10) | 469, /* RF_RAMP5, LNA 2 = 0dB */
804 (0 << 10) | 742, /* RF_RAMP6, LNA 2 */
805 (9 << 10) | 234, /* RF_RAMP7, LNA 3 = 0dB */
806 (0 << 10) | 468, /* RF_RAMP8, LNA 3 */
807 (9 << 10) | 0, /* GAIN_4_1, LNA 4 = 0dB */
808 (0 << 10) | 233, /* GAIN_4_2, LNA 4 */
Olivier Grenie03245a52009-12-04 13:27:57 -0300809};
810
811static const u16 rf_ramp_pwm_vhf[] = {
Olivier Grenieaedabf72012-12-31 10:38:44 -0300812 398, /* max RF gain in 10th of dB */
813 24, /* ramp_slope = 1dB of gain -> clock_ticks_per_db = clk_khz / ramp_slope -> RF_RAMP2 */
814 954, /* ramp_max = maximum X used on the ramp */
815 (7 << 10) | 0, /* RF_RAMP3, LNA 1 = 13.2dB */
816 (0 << 10) | 290, /* RF_RAMP4, LNA 1 */
817 (16 << 10) | 699, /* RF_RAMP5, LNA 2 = 10.5dB */
818 (0 << 10) | 954, /* RF_RAMP6, LNA 2 */
819 (17 << 10) | 580, /* RF_RAMP7, LNA 3 = 5dB */
820 (0 << 10) | 699, /* RF_RAMP8, LNA 3 */
821 (7 << 10) | 290, /* GAIN_4_1, LNA 4 = 12.5dB */
822 (0 << 10) | 580, /* GAIN_4_2, LNA 4 */
Olivier Grenie03245a52009-12-04 13:27:57 -0300823};
824
825static const u16 rf_ramp_pwm_uhf[] = {
Olivier Grenieaedabf72012-12-31 10:38:44 -0300826 398, /* max RF gain in 10th of dB */
827 24, /* ramp_slope = 1dB of gain -> clock_ticks_per_db = clk_khz / ramp_slope -> RF_RAMP2 */
828 954, /* ramp_max = maximum X used on the ramp */
829 (7 << 10) | 0, /* RF_RAMP3, LNA 1 = 13.2dB */
830 (0 << 10) | 290, /* RF_RAMP4, LNA 1 */
831 (16 << 10) | 699, /* RF_RAMP5, LNA 2 = 10.5dB */
832 (0 << 10) | 954, /* RF_RAMP6, LNA 2 */
833 (17 << 10) | 580, /* RF_RAMP7, LNA 3 = 5dB */
834 (0 << 10) | 699, /* RF_RAMP8, LNA 3 */
835 (7 << 10) | 290, /* GAIN_4_1, LNA 4 = 12.5dB */
836 (0 << 10) | 580, /* GAIN_4_2, LNA 4 */
Olivier Grenie03245a52009-12-04 13:27:57 -0300837};
838
Mauro Carvalho Chehabcf47fac2016-06-24 11:12:17 -0300839#if 0
840/* Currently unused */
Olivier Grenieaedabf72012-12-31 10:38:44 -0300841static const u16 rf_ramp_pwm_sband[] = {
842 253, /* max RF gain in 10th of dB */
843 38, /* ramp_slope = 1dB of gain -> clock_ticks_per_db = clk_khz / ramp_slope -> RF_RAMP2 */
844 961,
845 (4 << 10) | 0, /* RF_RAMP3, LNA 1 = 14.1dB */
846 (0 << 10) | 508, /* RF_RAMP4, LNA 1 */
847 (9 << 10) | 508, /* RF_RAMP5, LNA 2 = 11.2dB */
848 (0 << 10) | 961, /* RF_RAMP6, LNA 2 */
849 (0 << 10) | 0, /* RF_RAMP7, LNA 3 = 0dB */
850 (0 << 10) | 0, /* RF_RAMP8, LNA 3 */
851 (0 << 10) | 0, /* GAIN_4_1, LNA 4 = 0dB */
852 (0 << 10) | 0, /* GAIN_4_2, LNA 4 */
Olivier Grenie03245a52009-12-04 13:27:57 -0300853};
Mauro Carvalho Chehabcf47fac2016-06-24 11:12:17 -0300854#endif
Olivier Grenie03245a52009-12-04 13:27:57 -0300855
856struct slope {
Olivier Grenie28fafca2011-01-04 04:27:11 -0300857 s16 range;
858 s16 slope;
Olivier Grenie03245a52009-12-04 13:27:57 -0300859};
860static u16 slopes_to_scale(const struct slope *slopes, u8 num, s16 val)
861{
862 u8 i;
863 u16 rest;
864 u16 ret = 0;
865 for (i = 0; i < num; i++) {
866 if (val > slopes[i].range)
867 rest = slopes[i].range;
868 else
869 rest = val;
870 ret += (rest * slopes[i].slope) / slopes[i].range;
871 val -= rest;
872 }
873 return ret;
874}
875
876static const struct slope dib0090_wbd_slopes[3] = {
877 {66, 120}, /* -64,-52: offset - 65 */
878 {600, 170}, /* -52,-35: 65 - 665 */
879 {170, 250}, /* -45,-10: 665 - 835 */
880};
881
882static s16 dib0090_wbd_to_db(struct dib0090_state *state, u16 wbd)
883{
884 wbd &= 0x3ff;
885 if (wbd < state->wbd_offset)
886 wbd = 0;
887 else
888 wbd -= state->wbd_offset;
889 /* -64dB is the floor */
890 return -640 + (s16) slopes_to_scale(dib0090_wbd_slopes, ARRAY_SIZE(dib0090_wbd_slopes), wbd);
891}
892
893static void dib0090_wbd_target(struct dib0090_state *state, u32 rf)
894{
895 u16 offset = 250;
896
897 /* TODO : DAB digital N+/-1 interferer perfs : offset = 10 */
898
899 if (state->current_band == BAND_VHF)
900 offset = 650;
901#ifndef FIRMWARE_FIREFLY
902 if (state->current_band == BAND_VHF)
903 offset = state->config->wbd_vhf_offset;
904 if (state->current_band == BAND_CBAND)
905 offset = state->config->wbd_cband_offset;
906#endif
907
908 state->wbd_target = dib0090_wbd_to_db(state, state->wbd_offset + offset);
Mauro Carvalho Chehab4bd1a8d2016-10-14 08:16:43 -0300909 dprintk("wbd-target: %d dB\n", (u32) state->wbd_target);
Olivier Grenie03245a52009-12-04 13:27:57 -0300910}
911
912static const int gain_reg_addr[4] = {
913 0x08, 0x0a, 0x0f, 0x01
914};
915
916static void dib0090_gain_apply(struct dib0090_state *state, s16 gain_delta, s16 top_delta, u8 force)
917{
918 u16 rf, bb, ref;
919 u16 i, v, gain_reg[4] = { 0 }, gain;
920 const u16 *g;
921
922 if (top_delta < -511)
923 top_delta = -511;
924 if (top_delta > 511)
925 top_delta = 511;
926
927 if (force) {
928 top_delta *= (1 << WBD_ALPHA);
929 gain_delta *= (1 << GAIN_ALPHA);
930 }
931
932 if (top_delta >= ((s16) (state->rf_ramp[0] << WBD_ALPHA) - state->rf_gain_limit)) /* overflow */
933 state->rf_gain_limit = state->rf_ramp[0] << WBD_ALPHA;
934 else
935 state->rf_gain_limit += top_delta;
936
937 if (state->rf_gain_limit < 0) /*underflow */
938 state->rf_gain_limit = 0;
939
940 /* use gain as a temporary variable and correct current_gain */
941 gain = ((state->rf_gain_limit >> WBD_ALPHA) + state->bb_ramp[0]) << GAIN_ALPHA;
942 if (gain_delta >= ((s16) gain - state->current_gain)) /* overflow */
943 state->current_gain = gain;
944 else
945 state->current_gain += gain_delta;
946 /* cannot be less than 0 (only if gain_delta is less than 0 we can have current_gain < 0) */
947 if (state->current_gain < 0)
948 state->current_gain = 0;
949
950 /* now split total gain to rf and bb gain */
951 gain = state->current_gain >> GAIN_ALPHA;
952
953 /* requested gain is bigger than rf gain limit - ACI/WBD adjustment */
954 if (gain > (state->rf_gain_limit >> WBD_ALPHA)) {
955 rf = state->rf_gain_limit >> WBD_ALPHA;
956 bb = gain - rf;
957 if (bb > state->bb_ramp[0])
958 bb = state->bb_ramp[0];
959 } else { /* high signal level -> all gains put on RF */
960 rf = gain;
961 bb = 0;
962 }
963
964 state->gain[0] = rf;
965 state->gain[1] = bb;
966
967 /* software ramp */
968 /* Start with RF gains */
969 g = state->rf_ramp + 1; /* point on RF LNA1 max gain */
970 ref = rf;
971 for (i = 0; i < 7; i++) { /* Go over all amplifiers => 5RF amps + 2 BB amps = 7 amps */
972 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 */
973 v = 0; /* force the gain to write for the current amp to be null */
974 else if (ref >= g[1]) /* Gain to set is higher than the high working point of this amp */
975 v = g[2]; /* force this amp to be full gain */
976 else /* compute the value to set to this amp because we are somewhere in his range */
977 v = ((ref - (g[1] - g[0])) * g[2]) / g[0];
978
979 if (i == 0) /* LNA 1 reg mapping */
980 gain_reg[0] = v;
981 else if (i == 1) /* LNA 2 reg mapping */
982 gain_reg[0] |= v << 7;
983 else if (i == 2) /* LNA 3 reg mapping */
984 gain_reg[1] = v;
985 else if (i == 3) /* LNA 4 reg mapping */
986 gain_reg[1] |= v << 7;
987 else if (i == 4) /* CBAND LNA reg mapping */
988 gain_reg[2] = v | state->rf_lt_def;
989 else if (i == 5) /* BB gain 1 reg mapping */
990 gain_reg[3] = v << 3;
991 else if (i == 6) /* BB gain 2 reg mapping */
992 gain_reg[3] |= v << 8;
993
994 g += 3; /* go to next gain bloc */
995
996 /* When RF is finished, start with BB */
997 if (i == 4) {
998 g = state->bb_ramp + 1; /* point on BB gain 1 max gain */
999 ref = bb;
1000 }
1001 }
1002 gain_reg[3] |= state->bb_1_def;
1003 gain_reg[3] |= ((bb % 10) * 100) / 125;
1004
1005#ifdef DEBUG_AGC
Mauro Carvalho Chehab4bd1a8d2016-10-14 08:16:43 -03001006 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\n", rf, bb, rf + bb,
Olivier Grenie03245a52009-12-04 13:27:57 -03001007 gain_reg[0], gain_reg[1], gain_reg[2], gain_reg[3]);
1008#endif
1009
1010 /* Write the amplifier regs */
1011 for (i = 0; i < 4; i++) {
1012 v = gain_reg[i];
1013 if (force || state->gain_reg[i] != v) {
1014 state->gain_reg[i] = v;
1015 dib0090_write_reg(state, gain_reg_addr[i], v);
1016 }
1017 }
1018}
1019
1020static void dib0090_set_boost(struct dib0090_state *state, int onoff)
1021{
1022 state->bb_1_def &= 0xdfff;
1023 state->bb_1_def |= onoff << 13;
1024}
1025
1026static void dib0090_set_rframp(struct dib0090_state *state, const u16 * cfg)
1027{
1028 state->rf_ramp = cfg;
1029}
1030
1031static void dib0090_set_rframp_pwm(struct dib0090_state *state, const u16 * cfg)
1032{
1033 state->rf_ramp = cfg;
1034
1035 dib0090_write_reg(state, 0x2a, 0xffff);
1036
Mauro Carvalho Chehab4bd1a8d2016-10-14 08:16:43 -03001037 dprintk("total RF gain: %ddB, step: %d\n", (u32) cfg[0], dib0090_read_reg(state, 0x2a));
Olivier Grenie03245a52009-12-04 13:27:57 -03001038
1039 dib0090_write_regs(state, 0x2c, cfg + 3, 6);
1040 dib0090_write_regs(state, 0x3e, cfg + 9, 2);
1041}
1042
1043static void dib0090_set_bbramp(struct dib0090_state *state, const u16 * cfg)
1044{
1045 state->bb_ramp = cfg;
1046 dib0090_set_boost(state, cfg[0] > 500); /* we want the boost if the gain is higher that 50dB */
1047}
1048
1049static void dib0090_set_bbramp_pwm(struct dib0090_state *state, const u16 * cfg)
1050{
1051 state->bb_ramp = cfg;
1052
1053 dib0090_set_boost(state, cfg[0] > 500); /* we want the boost if the gain is higher that 50dB */
1054
1055 dib0090_write_reg(state, 0x33, 0xffff);
Mauro Carvalho Chehab4bd1a8d2016-10-14 08:16:43 -03001056 dprintk("total BB gain: %ddB, step: %d\n", (u32) cfg[0], dib0090_read_reg(state, 0x33));
Olivier Grenie03245a52009-12-04 13:27:57 -03001057 dib0090_write_regs(state, 0x35, cfg + 3, 4);
1058}
1059
1060void dib0090_pwm_gain_reset(struct dvb_frontend *fe)
1061{
1062 struct dib0090_state *state = fe->tuner_priv;
Hans Verkuil6c0943c2018-11-22 05:03:01 -05001063 const u16 *bb_ramp = bb_ramp_pwm_normal; /* default baseband config */
1064 const u16 *rf_ramp = NULL;
Olivier Grenieaedabf72012-12-31 10:38:44 -03001065 u8 en_pwm_rf_mux = 1;
Olivier Grenie03245a52009-12-04 13:27:57 -03001066
Olivier Grenieaedabf72012-12-31 10:38:44 -03001067 /* reset the AGC */
Olivier Grenie03245a52009-12-04 13:27:57 -03001068 if (state->config->use_pwm_agc) {
Olivier Grenie03245a52009-12-04 13:27:57 -03001069 if (state->current_band == BAND_CBAND) {
Olivier Grenie28fafca2011-01-04 04:27:11 -03001070 if (state->identity.in_soc) {
Hans Verkuil6c0943c2018-11-22 05:03:01 -05001071 bb_ramp = bb_ramp_pwm_normal_socs;
Olivier Grenie28fafca2011-01-04 04:27:11 -03001072 if (state->identity.version == SOC_8090_P1G_11R1 || state->identity.version == SOC_8090_P1G_21R1)
Hans Verkuil6c0943c2018-11-22 05:03:01 -05001073 rf_ramp = rf_ramp_pwm_cband_8090;
Olivier Grenieaedabf72012-12-31 10:38:44 -03001074 else if (state->identity.version == SOC_7090_P1G_11R1 || state->identity.version == SOC_7090_P1G_21R1) {
Olivier Grenie6724a2f2011-08-05 13:49:33 -03001075 if (state->config->is_dib7090e) {
1076 if (state->rf_ramp == NULL)
Hans Verkuil6c0943c2018-11-22 05:03:01 -05001077 rf_ramp = rf_ramp_pwm_cband_7090e_sensitivity;
Olivier Grenie6724a2f2011-08-05 13:49:33 -03001078 else
Hans Verkuil6c0943c2018-11-22 05:03:01 -05001079 rf_ramp = state->rf_ramp;
Olivier Grenie6724a2f2011-08-05 13:49:33 -03001080 } else
Hans Verkuil6c0943c2018-11-22 05:03:01 -05001081 rf_ramp = rf_ramp_pwm_cband_7090p;
Olivier Grenie6724a2f2011-08-05 13:49:33 -03001082 }
Olivier Grenieaedabf72012-12-31 10:38:44 -03001083 } else
Hans Verkuil6c0943c2018-11-22 05:03:01 -05001084 rf_ramp = rf_ramp_pwm_cband;
Olivier Grenie03245a52009-12-04 13:27:57 -03001085 } else
Olivier Grenie03245a52009-12-04 13:27:57 -03001086
Olivier Grenieaedabf72012-12-31 10:38:44 -03001087 if (state->current_band == BAND_VHF) {
1088 if (state->identity.in_soc) {
Hans Verkuil6c0943c2018-11-22 05:03:01 -05001089 bb_ramp = bb_ramp_pwm_normal_socs;
Olivier Grenieaedabf72012-12-31 10:38:44 -03001090 /* rf_ramp = &rf_ramp_pwm_vhf_socs; */ /* TODO */
1091 } else
Hans Verkuil6c0943c2018-11-22 05:03:01 -05001092 rf_ramp = rf_ramp_pwm_vhf;
Olivier Grenieaedabf72012-12-31 10:38:44 -03001093 } else if (state->current_band == BAND_UHF) {
1094 if (state->identity.in_soc) {
Hans Verkuil6c0943c2018-11-22 05:03:01 -05001095 bb_ramp = bb_ramp_pwm_normal_socs;
Olivier Grenieaedabf72012-12-31 10:38:44 -03001096 if (state->identity.version == SOC_8090_P1G_11R1 || state->identity.version == SOC_8090_P1G_21R1)
Hans Verkuil6c0943c2018-11-22 05:03:01 -05001097 rf_ramp = rf_ramp_pwm_uhf_8090;
Olivier Grenieaedabf72012-12-31 10:38:44 -03001098 else if (state->identity.version == SOC_7090_P1G_11R1 || state->identity.version == SOC_7090_P1G_21R1)
Hans Verkuil6c0943c2018-11-22 05:03:01 -05001099 rf_ramp = rf_ramp_pwm_uhf_7090;
Olivier Grenieaedabf72012-12-31 10:38:44 -03001100 } else
Hans Verkuil6c0943c2018-11-22 05:03:01 -05001101 rf_ramp = rf_ramp_pwm_uhf;
Olivier Grenieaedabf72012-12-31 10:38:44 -03001102 }
1103 if (rf_ramp)
1104 dib0090_set_rframp_pwm(state, rf_ramp);
1105 dib0090_set_bbramp_pwm(state, bb_ramp);
1106
1107 /* activate the ramp generator using PWM control */
Mauro Carvalho Chehab57bcbde2016-02-27 07:51:09 -03001108 if (state->rf_ramp)
Mauro Carvalho Chehab4bd1a8d2016-10-14 08:16:43 -03001109 dprintk("ramp RF gain = %d BAND = %s version = %d\n",
Mauro Carvalho Chehabe76bea92016-02-22 11:12:41 -03001110 state->rf_ramp[0],
1111 (state->current_band == BAND_CBAND) ? "CBAND" : "NOT CBAND",
1112 state->identity.version & 0x1f);
Olivier Grenieaedabf72012-12-31 10:38:44 -03001113
Hans Verkuil5848adb2016-04-15 12:35:33 -03001114 if (rf_ramp && ((state->rf_ramp && state->rf_ramp[0] == 0) ||
Mauro Carvalho Chehabe76bea92016-02-22 11:12:41 -03001115 (state->current_band == BAND_CBAND &&
1116 (state->identity.version & 0x1f) <= P1D_E_F))) {
Mauro Carvalho Chehab4bd1a8d2016-10-14 08:16:43 -03001117 dprintk("DE-Engage mux for direct gain reg control\n");
Olivier Grenieaedabf72012-12-31 10:38:44 -03001118 en_pwm_rf_mux = 0;
1119 } else
Mauro Carvalho Chehab4bd1a8d2016-10-14 08:16:43 -03001120 dprintk("Engage mux for PWM control\n");
Olivier Grenieaedabf72012-12-31 10:38:44 -03001121
1122 dib0090_write_reg(state, 0x32, (en_pwm_rf_mux << 12) | (en_pwm_rf_mux << 11));
1123
1124 /* Set fast servo cutoff to start AGC; 0 = 1KHz ; 1 = 50Hz ; 2 = 150Hz ; 3 = 50KHz ; 4 = servo fast*/
1125 if (state->identity.version == SOC_7090_P1G_11R1 || state->identity.version == SOC_7090_P1G_21R1)
1126 dib0090_write_reg(state, 0x04, 3);
Olivier Grenie03245a52009-12-04 13:27:57 -03001127 else
Olivier Grenieaedabf72012-12-31 10:38:44 -03001128 dib0090_write_reg(state, 0x04, 1);
1129 dib0090_write_reg(state, 0x39, (1 << 10)); /* 0 gain by default */
Olivier Grenie03245a52009-12-04 13:27:57 -03001130 }
1131}
Olivier Grenie03245a52009-12-04 13:27:57 -03001132EXPORT_SYMBOL(dib0090_pwm_gain_reset);
Olivier Grenie9c783032009-12-07 07:49:40 -03001133
Olivier Grenie2e802862011-08-05 10:39:15 -03001134void dib0090_set_dc_servo(struct dvb_frontend *fe, u8 DC_servo_cutoff)
1135{
1136 struct dib0090_state *state = fe->tuner_priv;
1137 if (DC_servo_cutoff < 4)
1138 dib0090_write_reg(state, 0x04, DC_servo_cutoff);
1139}
1140EXPORT_SYMBOL(dib0090_set_dc_servo);
1141
Olivier Grenie28fafca2011-01-04 04:27:11 -03001142static u32 dib0090_get_slow_adc_val(struct dib0090_state *state)
1143{
1144 u16 adc_val = dib0090_read_reg(state, 0x1d);
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001145 if (state->identity.in_soc)
Olivier Grenie28fafca2011-01-04 04:27:11 -03001146 adc_val >>= 2;
Olivier Grenie28fafca2011-01-04 04:27:11 -03001147 return adc_val;
1148}
1149
Olivier Grenie03245a52009-12-04 13:27:57 -03001150int dib0090_gain_control(struct dvb_frontend *fe)
1151{
1152 struct dib0090_state *state = fe->tuner_priv;
1153 enum frontend_tune_state *tune_state = &state->tune_state;
1154 int ret = 10;
1155
1156 u16 wbd_val = 0;
1157 u8 apply_gain_immediatly = 1;
1158 s16 wbd_error = 0, adc_error = 0;
1159
1160 if (*tune_state == CT_AGC_START) {
1161 state->agc_freeze = 0;
1162 dib0090_write_reg(state, 0x04, 0x0);
1163
1164#ifdef CONFIG_BAND_SBAND
1165 if (state->current_band == BAND_SBAND) {
1166 dib0090_set_rframp(state, rf_ramp_sband);
1167 dib0090_set_bbramp(state, bb_ramp_boost);
1168 } else
1169#endif
1170#ifdef CONFIG_BAND_VHF
Olivier Grenie28fafca2011-01-04 04:27:11 -03001171 if (state->current_band == BAND_VHF && !state->identity.p1g) {
Olivier Grenieaedabf72012-12-31 10:38:44 -03001172 dib0090_set_rframp(state, rf_ramp_pwm_vhf);
1173 dib0090_set_bbramp(state, bb_ramp_pwm_normal);
Olivier Grenie03245a52009-12-04 13:27:57 -03001174 } else
1175#endif
1176#ifdef CONFIG_BAND_CBAND
Olivier Grenie28fafca2011-01-04 04:27:11 -03001177 if (state->current_band == BAND_CBAND && !state->identity.p1g) {
Olivier Grenieaedabf72012-12-31 10:38:44 -03001178 dib0090_set_rframp(state, rf_ramp_pwm_cband);
1179 dib0090_set_bbramp(state, bb_ramp_pwm_normal);
Olivier Grenie03245a52009-12-04 13:27:57 -03001180 } else
1181#endif
Olivier Grenie28fafca2011-01-04 04:27:11 -03001182 if ((state->current_band == BAND_CBAND || state->current_band == BAND_VHF) && state->identity.p1g) {
Olivier Grenieaedabf72012-12-31 10:38:44 -03001183 dib0090_set_rframp(state, rf_ramp_pwm_cband_7090p);
1184 dib0090_set_bbramp(state, bb_ramp_pwm_normal_socs);
Olivier Grenie28fafca2011-01-04 04:27:11 -03001185 } else {
Olivier Grenieaedabf72012-12-31 10:38:44 -03001186 dib0090_set_rframp(state, rf_ramp_pwm_uhf);
1187 dib0090_set_bbramp(state, bb_ramp_pwm_normal);
Olivier Grenie03245a52009-12-04 13:27:57 -03001188 }
1189
1190 dib0090_write_reg(state, 0x32, 0);
1191 dib0090_write_reg(state, 0x39, 0);
1192
1193 dib0090_wbd_target(state, state->current_rf);
1194
1195 state->rf_gain_limit = state->rf_ramp[0] << WBD_ALPHA;
1196 state->current_gain = ((state->rf_ramp[0] + state->bb_ramp[0]) / 2) << GAIN_ALPHA;
1197
1198 *tune_state = CT_AGC_STEP_0;
1199 } else if (!state->agc_freeze) {
Olivier Grenie28fafca2011-01-04 04:27:11 -03001200 s16 wbd = 0, i, cnt;
Olivier Grenie03245a52009-12-04 13:27:57 -03001201
1202 int adc;
Olivier Grenie28fafca2011-01-04 04:27:11 -03001203 wbd_val = dib0090_get_slow_adc_val(state);
Olivier Grenie03245a52009-12-04 13:27:57 -03001204
Olivier Grenie28fafca2011-01-04 04:27:11 -03001205 if (*tune_state == CT_AGC_STEP_0)
1206 cnt = 5;
1207 else
1208 cnt = 1;
1209
1210 for (i = 0; i < cnt; i++) {
1211 wbd_val = dib0090_get_slow_adc_val(state);
1212 wbd += dib0090_wbd_to_db(state, wbd_val);
1213 }
1214 wbd /= cnt;
Olivier Grenie03245a52009-12-04 13:27:57 -03001215 wbd_error = state->wbd_target - wbd;
1216
1217 if (*tune_state == CT_AGC_STEP_0) {
Olivier Grenie28fafca2011-01-04 04:27:11 -03001218 if (wbd_error < 0 && state->rf_gain_limit > 0 && !state->identity.p1g) {
Olivier Grenie03245a52009-12-04 13:27:57 -03001219#ifdef CONFIG_BAND_CBAND
1220 /* in case of CBAND tune reduce first the lt_gain2 before adjusting the RF gain */
1221 u8 ltg2 = (state->rf_lt_def >> 10) & 0x7;
1222 if (state->current_band == BAND_CBAND && ltg2) {
1223 ltg2 >>= 1;
1224 state->rf_lt_def &= ltg2 << 10; /* reduce in 3 steps from 7 to 0 */
1225 }
1226#endif
1227 } else {
1228 state->agc_step = 0;
1229 *tune_state = CT_AGC_STEP_1;
1230 }
1231 } else {
1232 /* calc the adc power */
1233 adc = state->config->get_adc_power(fe);
1234 adc = (adc * ((s32) 355774) + (((s32) 1) << 20)) >> 21; /* included in [0:-700] */
1235
1236 adc_error = (s16) (((s32) ADC_TARGET) - adc);
1237#ifdef CONFIG_STANDARD_DAB
1238 if (state->fe->dtv_property_cache.delivery_system == STANDARD_DAB)
Olivier Grenie28fafca2011-01-04 04:27:11 -03001239 adc_error -= 10;
Olivier Grenie03245a52009-12-04 13:27:57 -03001240#endif
1241#ifdef CONFIG_STANDARD_DVBT
1242 if (state->fe->dtv_property_cache.delivery_system == STANDARD_DVBT &&
Olivier Grenie28fafca2011-01-04 04:27:11 -03001243 (state->fe->dtv_property_cache.modulation == QAM_64 || state->fe->dtv_property_cache.modulation == QAM_16))
Olivier Grenie03245a52009-12-04 13:27:57 -03001244 adc_error += 60;
1245#endif
1246#ifdef CONFIG_SYS_ISDBT
1247 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 -03001248 0)
1249 &&
1250 ((state->fe->dtv_property_cache.layer[0].modulation ==
1251 QAM_64)
1252 || (state->fe->dtv_property_cache.
1253 layer[0].modulation == QAM_16)))
1254 ||
1255 ((state->fe->dtv_property_cache.layer[1].segment_count >
1256 0)
1257 &&
1258 ((state->fe->dtv_property_cache.layer[1].modulation ==
1259 QAM_64)
1260 || (state->fe->dtv_property_cache.
1261 layer[1].modulation == QAM_16)))
1262 ||
1263 ((state->fe->dtv_property_cache.layer[2].segment_count >
1264 0)
1265 &&
1266 ((state->fe->dtv_property_cache.layer[2].modulation ==
1267 QAM_64)
1268 || (state->fe->dtv_property_cache.
1269 layer[2].modulation == QAM_16)))
1270 )
1271 )
Olivier Grenie03245a52009-12-04 13:27:57 -03001272 adc_error += 60;
1273#endif
1274
1275 if (*tune_state == CT_AGC_STEP_1) { /* quickly go to the correct range of the ADC power */
Dan Gopstein7aa92c42017-12-25 16:16:14 -05001276 if (abs(adc_error) < 50 || state->agc_step++ > 5) {
Olivier Grenie03245a52009-12-04 13:27:57 -03001277
1278#ifdef CONFIG_STANDARD_DAB
1279 if (state->fe->dtv_property_cache.delivery_system == STANDARD_DAB) {
1280 dib0090_write_reg(state, 0x02, (1 << 15) | (15 << 11) | (31 << 6) | (63)); /* cap value = 63 : narrow BB filter : Fc = 1.8MHz */
1281 dib0090_write_reg(state, 0x04, 0x0);
1282 } else
1283#endif
1284 {
1285 dib0090_write_reg(state, 0x02, (1 << 15) | (3 << 11) | (6 << 6) | (32));
1286 dib0090_write_reg(state, 0x04, 0x01); /*0 = 1KHz ; 1 = 150Hz ; 2 = 50Hz ; 3 = 50KHz ; 4 = servo fast */
1287 }
1288
1289 *tune_state = CT_AGC_STOP;
1290 }
1291 } else {
1292 /* everything higher than or equal to CT_AGC_STOP means tracking */
1293 ret = 100; /* 10ms interval */
1294 apply_gain_immediatly = 0;
1295 }
1296 }
1297#ifdef DEBUG_AGC
1298 dprintk
Olivier Grenie28fafca2011-01-04 04:27:11 -03001299 ("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 -03001300 (u32) *tune_state, (u32) adc, (u32) adc_error, (u32) wbd, (u32) wbd_error, (u32) wbd_val,
Olivier Grenie28fafca2011-01-04 04:27:11 -03001301 (u32) state->rf_gain_limit >> WBD_ALPHA, (s32) 200 + adc - (state->current_gain >> GAIN_ALPHA));
Olivier Grenie03245a52009-12-04 13:27:57 -03001302#endif
1303 }
1304
1305 /* apply gain */
1306 if (!state->agc_freeze)
1307 dib0090_gain_apply(state, adc_error, wbd_error, apply_gain_immediatly);
1308 return ret;
1309}
Olivier Grenie28fafca2011-01-04 04:27:11 -03001310
Olivier Grenie03245a52009-12-04 13:27:57 -03001311EXPORT_SYMBOL(dib0090_gain_control);
Olivier Grenie9c783032009-12-07 07:49:40 -03001312
Olivier Grenie03245a52009-12-04 13:27:57 -03001313void dib0090_get_current_gain(struct dvb_frontend *fe, u16 * rf, u16 * bb, u16 * rf_gain_limit, u16 * rflt)
1314{
1315 struct dib0090_state *state = fe->tuner_priv;
1316 if (rf)
1317 *rf = state->gain[0];
1318 if (bb)
1319 *bb = state->gain[1];
1320 if (rf_gain_limit)
1321 *rf_gain_limit = state->rf_gain_limit;
1322 if (rflt)
1323 *rflt = (state->rf_lt_def >> 10) & 0x7;
1324}
Olivier Grenie28fafca2011-01-04 04:27:11 -03001325
Olivier Grenie03245a52009-12-04 13:27:57 -03001326EXPORT_SYMBOL(dib0090_get_current_gain);
Olivier Grenie9c783032009-12-07 07:49:40 -03001327
Olivier Grenie6724a2f2011-08-05 13:49:33 -03001328u16 dib0090_get_wbd_target(struct dvb_frontend *fe)
Olivier Grenie03245a52009-12-04 13:27:57 -03001329{
Olivier Grenie28fafca2011-01-04 04:27:11 -03001330 struct dib0090_state *state = fe->tuner_priv;
1331 u32 f_MHz = state->fe->dtv_property_cache.frequency / 1000000;
1332 s32 current_temp = state->temperature;
1333 s32 wbd_thot, wbd_tcold;
1334 const struct dib0090_wbd_slope *wbd = state->current_wbd_table;
1335
1336 while (f_MHz > wbd->max_freq)
1337 wbd++;
1338
Mauro Carvalho Chehab4bd1a8d2016-10-14 08:16:43 -03001339 dprintk("using wbd-table-entry with max freq %d\n", wbd->max_freq);
Olivier Grenie28fafca2011-01-04 04:27:11 -03001340
1341 if (current_temp < 0)
1342 current_temp = 0;
1343 if (current_temp > 128)
1344 current_temp = 128;
1345
Olivier Grenie28fafca2011-01-04 04:27:11 -03001346 state->wbdmux &= ~(7 << 13);
1347 if (wbd->wbd_gain != 0)
1348 state->wbdmux |= (wbd->wbd_gain << 13);
1349 else
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001350 state->wbdmux |= (4 << 13);
Olivier Grenie28fafca2011-01-04 04:27:11 -03001351
1352 dib0090_write_reg(state, 0x10, state->wbdmux);
1353
Olivier Grenie28fafca2011-01-04 04:27:11 -03001354 wbd_thot = wbd->offset_hot - (((u32) wbd->slope_hot * f_MHz) >> 6);
1355 wbd_tcold = wbd->offset_cold - (((u32) wbd->slope_cold * f_MHz) >> 6);
1356
Olivier Grenie28fafca2011-01-04 04:27:11 -03001357 wbd_tcold += ((wbd_thot - wbd_tcold) * current_temp) >> 7;
1358
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001359 state->wbd_target = dib0090_wbd_to_db(state, state->wbd_offset + wbd_tcold);
Mauro Carvalho Chehab4bd1a8d2016-10-14 08:16:43 -03001360 dprintk("wbd-target: %d dB\n", (u32) state->wbd_target);
1361 dprintk("wbd offset applied is %d\n", wbd_tcold);
Olivier Grenie28fafca2011-01-04 04:27:11 -03001362
1363 return state->wbd_offset + wbd_tcold;
Olivier Grenie03245a52009-12-04 13:27:57 -03001364}
Olivier Grenie6724a2f2011-08-05 13:49:33 -03001365EXPORT_SYMBOL(dib0090_get_wbd_target);
Olivier Grenie28fafca2011-01-04 04:27:11 -03001366
Olivier Grenie6724a2f2011-08-05 13:49:33 -03001367u16 dib0090_get_wbd_offset(struct dvb_frontend *fe)
1368{
1369 struct dib0090_state *state = fe->tuner_priv;
1370 return state->wbd_offset;
1371}
Olivier Grenie03245a52009-12-04 13:27:57 -03001372EXPORT_SYMBOL(dib0090_get_wbd_offset);
Olivier Grenie9c783032009-12-07 07:49:40 -03001373
Olivier Grenie6724a2f2011-08-05 13:49:33 -03001374int dib0090_set_switch(struct dvb_frontend *fe, u8 sw1, u8 sw2, u8 sw3)
1375{
1376 struct dib0090_state *state = fe->tuner_priv;
1377
1378 dib0090_write_reg(state, 0x0b, (dib0090_read_reg(state, 0x0b) & 0xfff8)
1379 | ((sw3 & 1) << 2) | ((sw2 & 1) << 1) | (sw1 & 1));
1380
1381 return 0;
1382}
1383EXPORT_SYMBOL(dib0090_set_switch);
1384
1385int dib0090_set_vga(struct dvb_frontend *fe, u8 onoff)
1386{
1387 struct dib0090_state *state = fe->tuner_priv;
1388
1389 dib0090_write_reg(state, 0x09, (dib0090_read_reg(state, 0x09) & 0x7fff)
1390 | ((onoff & 1) << 15));
1391 return 0;
1392}
1393EXPORT_SYMBOL(dib0090_set_vga);
1394
1395int dib0090_update_rframp_7090(struct dvb_frontend *fe, u8 cfg_sensitivity)
1396{
1397 struct dib0090_state *state = fe->tuner_priv;
1398
1399 if ((!state->identity.p1g) || (!state->identity.in_soc)
1400 || ((state->identity.version != SOC_7090_P1G_21R1)
1401 && (state->identity.version != SOC_7090_P1G_11R1))) {
Mauro Carvalho Chehab4bd1a8d2016-10-14 08:16:43 -03001402 dprintk("%s() function can only be used for dib7090P\n", __func__);
Olivier Grenie6724a2f2011-08-05 13:49:33 -03001403 return -ENODEV;
1404 }
1405
1406 if (cfg_sensitivity)
Hans Verkuil6c0943c2018-11-22 05:03:01 -05001407 state->rf_ramp = rf_ramp_pwm_cband_7090e_sensitivity;
Olivier Grenie6724a2f2011-08-05 13:49:33 -03001408 else
Hans Verkuil6c0943c2018-11-22 05:03:01 -05001409 state->rf_ramp = rf_ramp_pwm_cband_7090e_aci;
Olivier Grenie6724a2f2011-08-05 13:49:33 -03001410 dib0090_pwm_gain_reset(fe);
1411
1412 return 0;
1413}
1414EXPORT_SYMBOL(dib0090_update_rframp_7090);
1415
Olivier Grenie03245a52009-12-04 13:27:57 -03001416static const u16 dib0090_defaults[] = {
1417
1418 25, 0x01,
1419 0x0000,
1420 0x99a0,
1421 0x6008,
1422 0x0000,
Olivier Grenie28fafca2011-01-04 04:27:11 -03001423 0x8bcb,
Olivier Grenie03245a52009-12-04 13:27:57 -03001424 0x0000,
1425 0x0405,
1426 0x0000,
1427 0x0000,
1428 0x0000,
1429 0xb802,
1430 0x0300,
1431 0x2d12,
1432 0xbac0,
1433 0x7c00,
1434 0xdbb9,
1435 0x0954,
1436 0x0743,
1437 0x8000,
1438 0x0001,
1439 0x0040,
1440 0x0100,
1441 0x0000,
1442 0xe910,
1443 0x149e,
1444
1445 1, 0x1c,
1446 0xff2d,
1447
1448 1, 0x39,
1449 0x0000,
1450
Olivier Grenie03245a52009-12-04 13:27:57 -03001451 2, 0x1e,
1452 0x07FF,
1453 0x0007,
1454
1455 1, 0x24,
1456 EN_UHF | EN_CRYSTAL,
1457
1458 2, 0x3c,
1459 0x3ff,
1460 0x111,
1461 0
1462};
1463
Olivier Grenie28fafca2011-01-04 04:27:11 -03001464static const u16 dib0090_p1g_additionnal_defaults[] = {
Olivier Grenie28fafca2011-01-04 04:27:11 -03001465 1, 0x05,
1466 0xabcd,
1467
1468 1, 0x11,
1469 0x00b4,
1470
1471 1, 0x1c,
1472 0xfffd,
1473
1474 1, 0x40,
1475 0x108,
1476 0
1477};
1478
1479static void dib0090_set_default_config(struct dib0090_state *state, const u16 * n)
Olivier Grenie03245a52009-12-04 13:27:57 -03001480{
Olivier Grenie28fafca2011-01-04 04:27:11 -03001481 u16 l, r;
Olivier Grenie03245a52009-12-04 13:27:57 -03001482
Olivier Grenie03245a52009-12-04 13:27:57 -03001483 l = pgm_read_word(n++);
1484 while (l) {
1485 r = pgm_read_word(n++);
1486 do {
Olivier Grenie03245a52009-12-04 13:27:57 -03001487 dib0090_write_reg(state, r, pgm_read_word(n++));
1488 r++;
1489 } while (--l);
1490 l = pgm_read_word(n++);
1491 }
Olivier Grenie28fafca2011-01-04 04:27:11 -03001492}
1493
1494#define CAP_VALUE_MIN (u8) 9
1495#define CAP_VALUE_MAX (u8) 40
1496#define HR_MIN (u8) 25
1497#define HR_MAX (u8) 40
1498#define POLY_MIN (u8) 0
1499#define POLY_MAX (u8) 8
1500
Olivier Greniea685dbb2011-08-05 14:10:40 -03001501static void dib0090_set_EFUSE(struct dib0090_state *state)
Olivier Grenie28fafca2011-01-04 04:27:11 -03001502{
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001503 u8 c, h, n;
1504 u16 e2, e4;
1505 u16 cal;
Olivier Grenie28fafca2011-01-04 04:27:11 -03001506
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001507 e2 = dib0090_read_reg(state, 0x26);
1508 e4 = dib0090_read_reg(state, 0x28);
Olivier Grenie28fafca2011-01-04 04:27:11 -03001509
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001510 if ((state->identity.version == P1D_E_F) ||
1511 (state->identity.version == P1G) || (e2 == 0xffff)) {
Olivier Grenie28fafca2011-01-04 04:27:11 -03001512
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001513 dib0090_write_reg(state, 0x22, 0x10);
1514 cal = (dib0090_read_reg(state, 0x22) >> 6) & 0x3ff;
Olivier Grenie28fafca2011-01-04 04:27:11 -03001515
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001516 if ((cal < 670) || (cal == 1023))
1517 cal = 850;
1518 n = 165 - ((cal * 10)>>6) ;
1519 e2 = e4 = (3<<12) | (34<<6) | (n);
1520 }
Olivier Grenie28fafca2011-01-04 04:27:11 -03001521
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001522 if (e2 != e4)
1523 e2 &= e4; /* Remove the redundancy */
Olivier Grenie28fafca2011-01-04 04:27:11 -03001524
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001525 if (e2 != 0xffff) {
1526 c = e2 & 0x3f;
1527 n = (e2 >> 12) & 0xf;
1528 h = (e2 >> 6) & 0x3f;
Olivier Grenie28fafca2011-01-04 04:27:11 -03001529
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001530 if ((c >= CAP_VALUE_MAX) || (c <= CAP_VALUE_MIN))
1531 c = 32;
Olivier Grenieaedabf72012-12-31 10:38:44 -03001532 else
1533 c += 14;
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001534 if ((h >= HR_MAX) || (h <= HR_MIN))
1535 h = 34;
1536 if ((n >= POLY_MAX) || (n <= POLY_MIN))
1537 n = 3;
Olivier Grenie28fafca2011-01-04 04:27:11 -03001538
Mauro Carvalho Chehab751dc8c2013-04-25 15:30:40 -03001539 dib0090_write_reg(state, 0x13, (h << 10));
1540 e2 = (n << 11) | ((h >> 2)<<6) | c;
1541 dib0090_write_reg(state, 0x2, e2); /* Load the BB_2 */
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001542 }
Olivier Grenie28fafca2011-01-04 04:27:11 -03001543}
1544
1545static int dib0090_reset(struct dvb_frontend *fe)
1546{
1547 struct dib0090_state *state = fe->tuner_priv;
1548
1549 dib0090_reset_digital(fe, state->config);
1550 if (dib0090_identify(fe) < 0)
1551 return -EIO;
1552
1553#ifdef CONFIG_TUNER_DIB0090_P1B_SUPPORT
1554 if (!(state->identity.version & 0x1)) /* it is P1B - reset is already done */
1555 return 0;
1556#endif
1557
1558 if (!state->identity.in_soc) {
1559 if ((dib0090_read_reg(state, 0x1a) >> 5) & 0x2)
1560 dib0090_write_reg(state, 0x1b, (EN_IQADC | EN_BB | EN_BIAS | EN_DIGCLK | EN_PLL | EN_CRYSTAL));
1561 else
1562 dib0090_write_reg(state, 0x1b, (EN_DIGCLK | EN_PLL | EN_CRYSTAL));
1563 }
1564
1565 dib0090_set_default_config(state, dib0090_defaults);
1566
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001567 if (state->identity.in_soc)
1568 dib0090_write_reg(state, 0x18, 0x2910); /* charge pump current = 0 */
Olivier Grenie28fafca2011-01-04 04:27:11 -03001569
1570 if (state->identity.p1g)
1571 dib0090_set_default_config(state, dib0090_p1g_additionnal_defaults);
1572
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001573 /* Update the efuse : Only available for KROSUS > P1C and SOC as well*/
1574 if (((state->identity.version & 0x1f) >= P1D_E_F) || (state->identity.in_soc))
1575 dib0090_set_EFUSE(state);
Olivier Grenie03245a52009-12-04 13:27:57 -03001576
1577 /* Congigure in function of the crystal */
Olivier Grenie2e802862011-08-05 10:39:15 -03001578 if (state->config->force_crystal_mode != 0)
1579 dib0090_write_reg(state, 0x14,
1580 state->config->force_crystal_mode & 3);
1581 else if (state->config->io.clock_khz >= 24000)
Olivier Grenie28fafca2011-01-04 04:27:11 -03001582 dib0090_write_reg(state, 0x14, 1);
Olivier Grenie03245a52009-12-04 13:27:57 -03001583 else
Olivier Grenie28fafca2011-01-04 04:27:11 -03001584 dib0090_write_reg(state, 0x14, 2);
Mauro Carvalho Chehab4bd1a8d2016-10-14 08:16:43 -03001585 dprintk("Pll lock : %d\n", (dib0090_read_reg(state, 0x1a) >> 11) & 0x1);
Olivier Grenie03245a52009-12-04 13:27:57 -03001586
Olivier Grenie28fafca2011-01-04 04:27:11 -03001587 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 -03001588
1589 return 0;
1590}
1591
Olivier Grenie9c783032009-12-07 07:49:40 -03001592#define steps(u) (((u) > 15) ? ((u)-16) : (u))
Olivier Grenie03245a52009-12-04 13:27:57 -03001593#define INTERN_WAIT 10
1594static int dib0090_get_offset(struct dib0090_state *state, enum frontend_tune_state *tune_state)
1595{
1596 int ret = INTERN_WAIT * 10;
1597
1598 switch (*tune_state) {
1599 case CT_TUNER_STEP_2:
1600 /* Turns to positive */
1601 dib0090_write_reg(state, 0x1f, 0x7);
1602 *tune_state = CT_TUNER_STEP_3;
1603 break;
1604
1605 case CT_TUNER_STEP_3:
1606 state->adc_diff = dib0090_read_reg(state, 0x1d);
1607
1608 /* Turns to negative */
1609 dib0090_write_reg(state, 0x1f, 0x4);
1610 *tune_state = CT_TUNER_STEP_4;
1611 break;
1612
1613 case CT_TUNER_STEP_4:
1614 state->adc_diff -= dib0090_read_reg(state, 0x1d);
1615 *tune_state = CT_TUNER_STEP_5;
1616 ret = 0;
1617 break;
1618
1619 default:
1620 break;
1621 }
1622
1623 return ret;
1624}
1625
1626struct dc_calibration {
Olivier Grenie28fafca2011-01-04 04:27:11 -03001627 u8 addr;
1628 u8 offset;
1629 u8 pga:1;
1630 u16 bb1;
1631 u8 i:1;
Olivier Grenie03245a52009-12-04 13:27:57 -03001632};
1633
1634static const struct dc_calibration dc_table[] = {
1635 /* Step1 BB gain1= 26 with boost 1, gain 2 = 0 */
1636 {0x06, 5, 1, (1 << 13) | (0 << 8) | (26 << 3), 1},
1637 {0x07, 11, 1, (1 << 13) | (0 << 8) | (26 << 3), 0},
1638 /* Step 2 BB gain 1 = 26 with boost = 1 & gain 2 = 29 */
1639 {0x06, 0, 0, (1 << 13) | (29 << 8) | (26 << 3), 1},
1640 {0x06, 10, 0, (1 << 13) | (29 << 8) | (26 << 3), 0},
1641 {0},
1642};
1643
Olivier Grenie28fafca2011-01-04 04:27:11 -03001644static const struct dc_calibration dc_p1g_table[] = {
1645 /* Step1 BB gain1= 26 with boost 1, gain 2 = 0 */
1646 /* addr ; trim reg offset ; pga ; CTRL_BB1 value ; i or q */
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001647 {0x06, 5, 1, (1 << 13) | (0 << 8) | (15 << 3), 1},
1648 {0x07, 11, 1, (1 << 13) | (0 << 8) | (15 << 3), 0},
Olivier Grenie28fafca2011-01-04 04:27:11 -03001649 /* Step 2 BB gain 1 = 26 with boost = 1 & gain 2 = 29 */
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001650 {0x06, 0, 0, (1 << 13) | (29 << 8) | (15 << 3), 1},
1651 {0x06, 10, 0, (1 << 13) | (29 << 8) | (15 << 3), 0},
Olivier Grenie28fafca2011-01-04 04:27:11 -03001652 {0},
1653};
1654
Olivier Grenie03245a52009-12-04 13:27:57 -03001655static void dib0090_set_trim(struct dib0090_state *state)
1656{
1657 u16 *val;
1658
1659 if (state->dc->addr == 0x07)
1660 val = &state->bb7;
1661 else
1662 val = &state->bb6;
1663
1664 *val &= ~(0x1f << state->dc->offset);
1665 *val |= state->step << state->dc->offset;
1666
1667 dib0090_write_reg(state, state->dc->addr, *val);
1668}
1669
1670static int dib0090_dc_offset_calibration(struct dib0090_state *state, enum frontend_tune_state *tune_state)
1671{
1672 int ret = 0;
Olivier Grenie28fafca2011-01-04 04:27:11 -03001673 u16 reg;
Olivier Grenie03245a52009-12-04 13:27:57 -03001674
1675 switch (*tune_state) {
Olivier Grenie03245a52009-12-04 13:27:57 -03001676 case CT_TUNER_START:
Olivier Grenie28fafca2011-01-04 04:27:11 -03001677 dprintk("Start DC offset calibration");
Olivier Grenie03245a52009-12-04 13:27:57 -03001678
1679 /* force vcm2 = 0.8V */
1680 state->bb6 = 0;
1681 state->bb7 = 0x040d;
1682
Olivier Grenie28fafca2011-01-04 04:27:11 -03001683 /* the LNA AND LO are off */
1684 reg = dib0090_read_reg(state, 0x24) & 0x0ffb; /* shutdown lna and lo */
1685 dib0090_write_reg(state, 0x24, reg);
1686
1687 state->wbdmux = dib0090_read_reg(state, 0x10);
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001688 dib0090_write_reg(state, 0x10, (state->wbdmux & ~(0xff << 3)) | (0x7 << 3) | 0x3);
1689 dib0090_write_reg(state, 0x23, dib0090_read_reg(state, 0x23) & ~(1 << 14));
Olivier Grenie28fafca2011-01-04 04:27:11 -03001690
Olivier Grenie03245a52009-12-04 13:27:57 -03001691 state->dc = dc_table;
1692
Olivier Grenie28fafca2011-01-04 04:27:11 -03001693 if (state->identity.p1g)
1694 state->dc = dc_p1g_table;
Olivier Grenie03245a52009-12-04 13:27:57 -03001695
1696 /* fall through */
Olivier Grenie03245a52009-12-04 13:27:57 -03001697 case CT_TUNER_STEP_0:
Mauro Carvalho Chehab4bd1a8d2016-10-14 08:16:43 -03001698 dprintk("Start/continue DC calibration for %s path\n",
1699 (state->dc->i == 1) ? "I" : "Q");
Olivier Grenie03245a52009-12-04 13:27:57 -03001700 dib0090_write_reg(state, 0x01, state->dc->bb1);
1701 dib0090_write_reg(state, 0x07, state->bb7 | (state->dc->i << 7));
1702
1703 state->step = 0;
Olivier Grenie03245a52009-12-04 13:27:57 -03001704 state->min_adc_diff = 1023;
Olivier Grenie03245a52009-12-04 13:27:57 -03001705 *tune_state = CT_TUNER_STEP_1;
1706 ret = 50;
1707 break;
1708
1709 case CT_TUNER_STEP_1:
1710 dib0090_set_trim(state);
Olivier Grenie03245a52009-12-04 13:27:57 -03001711 *tune_state = CT_TUNER_STEP_2;
1712 break;
1713
1714 case CT_TUNER_STEP_2:
1715 case CT_TUNER_STEP_3:
1716 case CT_TUNER_STEP_4:
1717 ret = dib0090_get_offset(state, tune_state);
1718 break;
1719
1720 case CT_TUNER_STEP_5: /* found an offset */
Mauro Carvalho Chehab4bd1a8d2016-10-14 08:16:43 -03001721 dprintk("adc_diff = %d, current step= %d\n", (u32) state->adc_diff, state->step);
Olivier Grenie28fafca2011-01-04 04:27:11 -03001722 if (state->step == 0 && state->adc_diff < 0) {
1723 state->min_adc_diff = -1023;
Mauro Carvalho Chehab4bd1a8d2016-10-14 08:16:43 -03001724 dprintk("Change of sign of the minimum adc diff\n");
Olivier Grenie28fafca2011-01-04 04:27:11 -03001725 }
1726
Mauro Carvalho Chehab4bd1a8d2016-10-14 08:16:43 -03001727 dprintk("adc_diff = %d, min_adc_diff = %d current_step = %d\n", state->adc_diff, state->min_adc_diff, state->step);
Olivier Grenie03245a52009-12-04 13:27:57 -03001728
1729 /* first turn for this frequency */
1730 if (state->step == 0) {
1731 if (state->dc->pga && state->adc_diff < 0)
1732 state->step = 0x10;
1733 if (state->dc->pga == 0 && state->adc_diff > 0)
1734 state->step = 0x10;
1735 }
1736
Olivier Grenie28fafca2011-01-04 04:27:11 -03001737 /* Look for a change of Sign in the Adc_diff.min_adc_diff is used to STORE the setp N-1 */
1738 if ((state->adc_diff & 0x8000) == (state->min_adc_diff & 0x8000) && steps(state->step) < 15) {
1739 /* 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 -03001740 state->step++;
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001741 state->min_adc_diff = state->adc_diff;
Olivier Grenie03245a52009-12-04 13:27:57 -03001742 *tune_state = CT_TUNER_STEP_1;
1743 } else {
Olivier Grenie03245a52009-12-04 13:27:57 -03001744 /* the minimum was what we have seen in the step before */
Dan Gopstein7aa92c42017-12-25 16:16:14 -05001745 if (abs(state->adc_diff) > abs(state->min_adc_diff)) {
Mauro Carvalho Chehab4bd1a8d2016-10-14 08:16:43 -03001746 dprintk("Since adc_diff N = %d > adc_diff step N-1 = %d, Come back one step\n", state->adc_diff, state->min_adc_diff);
Olivier Grenie28fafca2011-01-04 04:27:11 -03001747 state->step--;
1748 }
Olivier Grenie03245a52009-12-04 13:27:57 -03001749
Olivier Grenie28fafca2011-01-04 04:27:11 -03001750 dib0090_set_trim(state);
Mauro Carvalho Chehab4bd1a8d2016-10-14 08:16:43 -03001751 dprintk("BB Offset Cal, BBreg=%hd,Offset=%hd,Value Set=%hd\n", state->dc->addr, state->adc_diff, state->step);
Olivier Grenie03245a52009-12-04 13:27:57 -03001752
1753 state->dc++;
1754 if (state->dc->addr == 0) /* done */
1755 *tune_state = CT_TUNER_STEP_6;
1756 else
1757 *tune_state = CT_TUNER_STEP_0;
1758
1759 }
1760 break;
1761
1762 case CT_TUNER_STEP_6:
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001763 dib0090_write_reg(state, 0x07, state->bb7 & ~0x0008);
Olivier Grenie03245a52009-12-04 13:27:57 -03001764 dib0090_write_reg(state, 0x1f, 0x7);
1765 *tune_state = CT_TUNER_START; /* reset done -> real tuning can now begin */
Olivier Grenie28fafca2011-01-04 04:27:11 -03001766 state->calibrate &= ~DC_CAL;
Olivier Grenie03245a52009-12-04 13:27:57 -03001767 default:
1768 break;
1769 }
1770 return ret;
1771}
1772
1773static int dib0090_wbd_calibration(struct dib0090_state *state, enum frontend_tune_state *tune_state)
1774{
Olivier Grenie28fafca2011-01-04 04:27:11 -03001775 u8 wbd_gain;
1776 const struct dib0090_wbd_slope *wbd = state->current_wbd_table;
1777
Olivier Grenie03245a52009-12-04 13:27:57 -03001778 switch (*tune_state) {
1779 case CT_TUNER_START:
Olivier Grenie28fafca2011-01-04 04:27:11 -03001780 while (state->current_rf / 1000 > wbd->max_freq)
1781 wbd++;
1782 if (wbd->wbd_gain != 0)
1783 wbd_gain = wbd->wbd_gain;
1784 else {
1785 wbd_gain = 4;
1786#if defined(CONFIG_BAND_LBAND) || defined(CONFIG_BAND_SBAND)
1787 if ((state->current_band == BAND_LBAND) || (state->current_band == BAND_SBAND))
1788 wbd_gain = 2;
1789#endif
1790 }
Olivier Grenie03245a52009-12-04 13:27:57 -03001791
Olivier Grenie28fafca2011-01-04 04:27:11 -03001792 if (wbd_gain == state->wbd_calibration_gain) { /* the WBD calibration has already been done */
1793 *tune_state = CT_TUNER_START;
1794 state->calibrate &= ~WBD_CAL;
1795 return 0;
1796 }
1797
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001798 dib0090_write_reg(state, 0x10, 0x1b81 | (1 << 10) | (wbd_gain << 13) | (1 << 3));
Olivier Grenie28fafca2011-01-04 04:27:11 -03001799
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001800 dib0090_write_reg(state, 0x24, ((EN_UHF & 0x0fff) | (1 << 1)));
Olivier Grenie03245a52009-12-04 13:27:57 -03001801 *tune_state = CT_TUNER_STEP_0;
Olivier Grenie28fafca2011-01-04 04:27:11 -03001802 state->wbd_calibration_gain = wbd_gain;
Olivier Grenie03245a52009-12-04 13:27:57 -03001803 return 90; /* wait for the WBDMUX to switch and for the ADC to sample */
Olivier Grenie03245a52009-12-04 13:27:57 -03001804
Olivier Grenie28fafca2011-01-04 04:27:11 -03001805 case CT_TUNER_STEP_0:
1806 state->wbd_offset = dib0090_get_slow_adc_val(state);
Mauro Carvalho Chehab4bd1a8d2016-10-14 08:16:43 -03001807 dprintk("WBD calibration offset = %d\n", state->wbd_offset);
Olivier Grenie03245a52009-12-04 13:27:57 -03001808 *tune_state = CT_TUNER_START; /* reset done -> real tuning can now begin */
Olivier Grenie28fafca2011-01-04 04:27:11 -03001809 state->calibrate &= ~WBD_CAL;
Olivier Grenie03245a52009-12-04 13:27:57 -03001810 break;
Olivier Grenie28fafca2011-01-04 04:27:11 -03001811
Olivier Grenie03245a52009-12-04 13:27:57 -03001812 default:
1813 break;
1814 }
1815 return 0;
1816}
1817
1818static void dib0090_set_bandwidth(struct dib0090_state *state)
1819{
1820 u16 tmp;
1821
1822 if (state->fe->dtv_property_cache.bandwidth_hz / 1000 <= 5000)
1823 tmp = (3 << 14);
1824 else if (state->fe->dtv_property_cache.bandwidth_hz / 1000 <= 6000)
1825 tmp = (2 << 14);
1826 else if (state->fe->dtv_property_cache.bandwidth_hz / 1000 <= 7000)
1827 tmp = (1 << 14);
1828 else
1829 tmp = (0 << 14);
1830
1831 state->bb_1_def &= 0x3fff;
1832 state->bb_1_def |= tmp;
1833
1834 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 -03001835
1836 dib0090_write_reg(state, 0x03, 0x6008); /* = 0x6008 : vcm3_trim = 1 ; filter2_gm1_trim = 8 ; filter2_cutoff_freq = 0 */
1837 dib0090_write_reg(state, 0x04, 0x1); /* 0 = 1KHz ; 1 = 50Hz ; 2 = 150Hz ; 3 = 50KHz ; 4 = servo fast */
1838 if (state->identity.in_soc) {
1839 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 */
1840 } else {
1841 dib0090_write_reg(state, 0x02, (5 << 11) | (8 << 6) | (22 & 0x3f)); /* 22 = cap_value */
1842 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 */
1843 }
Olivier Grenie03245a52009-12-04 13:27:57 -03001844}
1845
1846static const struct dib0090_pll dib0090_pll_table[] = {
1847#ifdef CONFIG_BAND_CBAND
1848 {56000, 0, 9, 48, 6},
1849 {70000, 1, 9, 48, 6},
1850 {87000, 0, 8, 32, 4},
1851 {105000, 1, 8, 32, 4},
1852 {115000, 0, 7, 24, 6},
1853 {140000, 1, 7, 24, 6},
1854 {170000, 0, 6, 16, 4},
1855#endif
1856#ifdef CONFIG_BAND_VHF
1857 {200000, 1, 6, 16, 4},
1858 {230000, 0, 5, 12, 6},
1859 {280000, 1, 5, 12, 6},
1860 {340000, 0, 4, 8, 4},
1861 {380000, 1, 4, 8, 4},
1862 {450000, 0, 3, 6, 6},
1863#endif
1864#ifdef CONFIG_BAND_UHF
1865 {580000, 1, 3, 6, 6},
1866 {700000, 0, 2, 4, 4},
1867 {860000, 1, 2, 4, 4},
1868#endif
1869#ifdef CONFIG_BAND_LBAND
1870 {1800000, 1, 0, 2, 4},
1871#endif
1872#ifdef CONFIG_BAND_SBAND
1873 {2900000, 0, 14, 1, 4},
1874#endif
1875};
1876
1877static const struct dib0090_tuning dib0090_tuning_table_fm_vhf_on_cband[] = {
1878
1879#ifdef CONFIG_BAND_CBAND
1880 {184000, 4, 1, 15, 0x280, 0x2912, 0xb94e, EN_CAB},
1881 {227000, 4, 3, 15, 0x280, 0x2912, 0xb94e, EN_CAB},
1882 {380000, 4, 7, 15, 0x280, 0x2912, 0xb94e, EN_CAB},
1883#endif
1884#ifdef CONFIG_BAND_UHF
1885 {520000, 2, 0, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},
1886 {550000, 2, 2, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},
1887 {650000, 2, 3, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},
1888 {750000, 2, 5, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},
1889 {850000, 2, 6, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},
1890 {900000, 2, 7, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},
1891#endif
1892#ifdef CONFIG_BAND_LBAND
1893 {1500000, 4, 0, 20, 0x300, 0x1912, 0x82c9, EN_LBD},
1894 {1600000, 4, 1, 20, 0x300, 0x1912, 0x82c9, EN_LBD},
1895 {1800000, 4, 3, 20, 0x300, 0x1912, 0x82c9, EN_LBD},
1896#endif
1897#ifdef CONFIG_BAND_SBAND
1898 {2300000, 1, 4, 20, 0x300, 0x2d2A, 0x82c7, EN_SBD},
1899 {2900000, 1, 7, 20, 0x280, 0x2deb, 0x8347, EN_SBD},
1900#endif
1901};
1902
1903static const struct dib0090_tuning dib0090_tuning_table[] = {
1904
1905#ifdef CONFIG_BAND_CBAND
1906 {170000, 4, 1, 15, 0x280, 0x2912, 0xb94e, EN_CAB},
1907#endif
1908#ifdef CONFIG_BAND_VHF
1909 {184000, 1, 1, 15, 0x300, 0x4d12, 0xb94e, EN_VHF},
1910 {227000, 1, 3, 15, 0x300, 0x4d12, 0xb94e, EN_VHF},
1911 {380000, 1, 7, 15, 0x300, 0x4d12, 0xb94e, EN_VHF},
1912#endif
1913#ifdef CONFIG_BAND_UHF
1914 {520000, 2, 0, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},
1915 {550000, 2, 2, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},
1916 {650000, 2, 3, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},
1917 {750000, 2, 5, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},
1918 {850000, 2, 6, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},
1919 {900000, 2, 7, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},
1920#endif
1921#ifdef CONFIG_BAND_LBAND
1922 {1500000, 4, 0, 20, 0x300, 0x1912, 0x82c9, EN_LBD},
1923 {1600000, 4, 1, 20, 0x300, 0x1912, 0x82c9, EN_LBD},
1924 {1800000, 4, 3, 20, 0x300, 0x1912, 0x82c9, EN_LBD},
1925#endif
1926#ifdef CONFIG_BAND_SBAND
1927 {2300000, 1, 4, 20, 0x300, 0x2d2A, 0x82c7, EN_SBD},
1928 {2900000, 1, 7, 20, 0x280, 0x2deb, 0x8347, EN_SBD},
1929#endif
1930};
1931
Olivier Grenie28fafca2011-01-04 04:27:11 -03001932static const struct dib0090_tuning dib0090_p1g_tuning_table[] = {
Olivier Grenie28fafca2011-01-04 04:27:11 -03001933#ifdef CONFIG_BAND_CBAND
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001934 {170000, 4, 1, 0x820f, 0x300, 0x2d22, 0x82cb, EN_CAB},
Olivier Grenie28fafca2011-01-04 04:27:11 -03001935#endif
1936#ifdef CONFIG_BAND_VHF
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001937 {184000, 1, 1, 15, 0x300, 0x4d12, 0xb94e, EN_VHF},
1938 {227000, 1, 3, 15, 0x300, 0x4d12, 0xb94e, EN_VHF},
1939 {380000, 1, 7, 15, 0x300, 0x4d12, 0xb94e, EN_VHF},
Olivier Grenie28fafca2011-01-04 04:27:11 -03001940#endif
1941#ifdef CONFIG_BAND_UHF
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001942 {510000, 2, 0, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},
1943 {540000, 2, 1, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},
1944 {600000, 2, 3, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},
1945 {630000, 2, 4, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},
1946 {680000, 2, 5, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},
1947 {720000, 2, 6, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},
1948 {900000, 2, 7, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},
Olivier Grenie28fafca2011-01-04 04:27:11 -03001949#endif
1950#ifdef CONFIG_BAND_LBAND
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001951 {1500000, 4, 0, 20, 0x300, 0x1912, 0x82c9, EN_LBD},
1952 {1600000, 4, 1, 20, 0x300, 0x1912, 0x82c9, EN_LBD},
1953 {1800000, 4, 3, 20, 0x300, 0x1912, 0x82c9, EN_LBD},
Olivier Grenie28fafca2011-01-04 04:27:11 -03001954#endif
1955#ifdef CONFIG_BAND_SBAND
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001956 {2300000, 1, 4, 20, 0x300, 0x2d2A, 0x82c7, EN_SBD},
1957 {2900000, 1, 7, 20, 0x280, 0x2deb, 0x8347, EN_SBD},
Olivier Grenie28fafca2011-01-04 04:27:11 -03001958#endif
1959};
1960
1961static const struct dib0090_pll dib0090_p1g_pll_table[] = {
1962#ifdef CONFIG_BAND_CBAND
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001963 {57000, 0, 11, 48, 6},
1964 {70000, 1, 11, 48, 6},
1965 {86000, 0, 10, 32, 4},
1966 {105000, 1, 10, 32, 4},
1967 {115000, 0, 9, 24, 6},
1968 {140000, 1, 9, 24, 6},
1969 {170000, 0, 8, 16, 4},
Olivier Grenie28fafca2011-01-04 04:27:11 -03001970#endif
1971#ifdef CONFIG_BAND_VHF
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001972 {200000, 1, 8, 16, 4},
1973 {230000, 0, 7, 12, 6},
1974 {280000, 1, 7, 12, 6},
1975 {340000, 0, 6, 8, 4},
1976 {380000, 1, 6, 8, 4},
1977 {455000, 0, 5, 6, 6},
Olivier Grenie28fafca2011-01-04 04:27:11 -03001978#endif
1979#ifdef CONFIG_BAND_UHF
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001980 {580000, 1, 5, 6, 6},
1981 {680000, 0, 4, 4, 4},
1982 {860000, 1, 4, 4, 4},
Olivier Grenie28fafca2011-01-04 04:27:11 -03001983#endif
1984#ifdef CONFIG_BAND_LBAND
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001985 {1800000, 1, 2, 2, 4},
Olivier Grenie28fafca2011-01-04 04:27:11 -03001986#endif
1987#ifdef CONFIG_BAND_SBAND
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001988 {2900000, 0, 1, 1, 6},
Olivier Grenie28fafca2011-01-04 04:27:11 -03001989#endif
1990};
1991
1992static const struct dib0090_tuning dib0090_p1g_tuning_table_fm_vhf_on_cband[] = {
Olivier Grenie28fafca2011-01-04 04:27:11 -03001993#ifdef CONFIG_BAND_CBAND
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001994 {184000, 4, 3, 0x4187, 0x2c0, 0x2d22, 0x81cb, EN_CAB},
1995 {227000, 4, 3, 0x4187, 0x2c0, 0x2d22, 0x81cb, EN_CAB},
1996 {380000, 4, 3, 0x4187, 0x2c0, 0x2d22, 0x81cb, EN_CAB},
Olivier Grenie28fafca2011-01-04 04:27:11 -03001997#endif
1998#ifdef CONFIG_BAND_UHF
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001999 {520000, 2, 0, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},
2000 {550000, 2, 2, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},
2001 {650000, 2, 3, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},
2002 {750000, 2, 5, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},
2003 {850000, 2, 6, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},
2004 {900000, 2, 7, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF},
Olivier Grenie28fafca2011-01-04 04:27:11 -03002005#endif
2006#ifdef CONFIG_BAND_LBAND
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002007 {1500000, 4, 0, 20, 0x300, 0x1912, 0x82c9, EN_LBD},
2008 {1600000, 4, 1, 20, 0x300, 0x1912, 0x82c9, EN_LBD},
2009 {1800000, 4, 3, 20, 0x300, 0x1912, 0x82c9, EN_LBD},
Olivier Grenie28fafca2011-01-04 04:27:11 -03002010#endif
2011#ifdef CONFIG_BAND_SBAND
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002012 {2300000, 1, 4, 20, 0x300, 0x2d2A, 0x82c7, EN_SBD},
2013 {2900000, 1, 7, 20, 0x280, 0x2deb, 0x8347, EN_SBD},
Olivier Grenie28fafca2011-01-04 04:27:11 -03002014#endif
2015};
2016
2017static const struct dib0090_tuning dib0090_tuning_table_cband_7090[] = {
Olivier Grenie28fafca2011-01-04 04:27:11 -03002018#ifdef CONFIG_BAND_CBAND
Olivier Grenie28fafca2011-01-04 04:27:11 -03002019 {300000, 4, 3, 0x018F, 0x2c0, 0x2d22, 0xb9ce, EN_CAB},
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002020 {380000, 4, 10, 0x018F, 0x2c0, 0x2d22, 0xb9ce, EN_CAB},
Olivier Grenie28fafca2011-01-04 04:27:11 -03002021 {570000, 4, 10, 0x8190, 0x2c0, 0x2d22, 0xb9ce, EN_CAB},
2022 {858000, 4, 5, 0x8190, 0x2c0, 0x2d22, 0xb9ce, EN_CAB},
2023#endif
2024};
2025
Olivier Grenie6724a2f2011-08-05 13:49:33 -03002026static const struct dib0090_tuning dib0090_tuning_table_cband_7090e_sensitivity[] = {
2027#ifdef CONFIG_BAND_CBAND
2028 { 300000, 0 , 3, 0x8105, 0x2c0, 0x2d12, 0xb84e, EN_CAB },
2029 { 380000, 0 , 10, 0x810F, 0x2c0, 0x2d12, 0xb84e, EN_CAB },
2030 { 600000, 0 , 10, 0x815E, 0x280, 0x2d12, 0xb84e, EN_CAB },
2031 { 660000, 0 , 5, 0x85E3, 0x280, 0x2d12, 0xb84e, EN_CAB },
2032 { 720000, 0 , 5, 0x852E, 0x280, 0x2d12, 0xb84e, EN_CAB },
2033 { 860000, 0 , 4, 0x85E5, 0x280, 0x2d12, 0xb84e, EN_CAB },
2034#endif
2035};
2036
2037int dib0090_update_tuning_table_7090(struct dvb_frontend *fe,
2038 u8 cfg_sensitivity)
2039{
2040 struct dib0090_state *state = fe->tuner_priv;
2041 const struct dib0090_tuning *tune =
2042 dib0090_tuning_table_cband_7090e_sensitivity;
Colin Ian King6e4e4442017-07-13 08:00:20 -04002043 static const struct dib0090_tuning dib0090_tuning_table_cband_7090e_aci[] = {
Olivier Grenie6724a2f2011-08-05 13:49:33 -03002044 { 300000, 0 , 3, 0x8165, 0x2c0, 0x2d12, 0xb84e, EN_CAB },
2045 { 650000, 0 , 4, 0x815B, 0x280, 0x2d12, 0xb84e, EN_CAB },
2046 { 860000, 0 , 5, 0x84EF, 0x280, 0x2d12, 0xb84e, EN_CAB },
2047 };
2048
2049 if ((!state->identity.p1g) || (!state->identity.in_soc)
2050 || ((state->identity.version != SOC_7090_P1G_21R1)
2051 && (state->identity.version != SOC_7090_P1G_11R1))) {
Mauro Carvalho Chehab4bd1a8d2016-10-14 08:16:43 -03002052 dprintk("%s() function can only be used for dib7090\n", __func__);
Olivier Grenie6724a2f2011-08-05 13:49:33 -03002053 return -ENODEV;
2054 }
2055
2056 if (cfg_sensitivity)
2057 tune = dib0090_tuning_table_cband_7090e_sensitivity;
2058 else
2059 tune = dib0090_tuning_table_cband_7090e_aci;
2060
2061 while (state->rf_request > tune->max_freq)
2062 tune++;
2063
2064 dib0090_write_reg(state, 0x09, (dib0090_read_reg(state, 0x09) & 0x8000)
2065 | (tune->lna_bias & 0x7fff));
2066 dib0090_write_reg(state, 0x0b, (dib0090_read_reg(state, 0x0b) & 0xf83f)
2067 | ((tune->lna_tune << 6) & 0x07c0));
2068 return 0;
2069}
2070EXPORT_SYMBOL(dib0090_update_tuning_table_7090);
2071
Olivier Grenie28fafca2011-01-04 04:27:11 -03002072static int dib0090_captrim_search(struct dib0090_state *state, enum frontend_tune_state *tune_state)
2073{
2074 int ret = 0;
2075 u16 lo4 = 0xe900;
2076
2077 s16 adc_target;
2078 u16 adc;
2079 s8 step_sign;
2080 u8 force_soft_search = 0;
2081
2082 if (state->identity.version == SOC_8090_P1G_11R1 || state->identity.version == SOC_8090_P1G_21R1)
2083 force_soft_search = 1;
2084
2085 if (*tune_state == CT_TUNER_START) {
Mauro Carvalho Chehab4bd1a8d2016-10-14 08:16:43 -03002086 dprintk("Start Captrim search : %s\n",
2087 (force_soft_search == 1) ? "FORCE SOFT SEARCH" : "AUTO");
Olivier Grenie28fafca2011-01-04 04:27:11 -03002088 dib0090_write_reg(state, 0x10, 0x2B1);
2089 dib0090_write_reg(state, 0x1e, 0x0032);
2090
2091 if (!state->tuner_is_tuned) {
2092 /* prepare a complete captrim */
2093 if (!state->identity.p1g || force_soft_search)
2094 state->step = state->captrim = state->fcaptrim = 64;
2095
2096 state->current_rf = state->rf_request;
2097 } else { /* we are already tuned to this frequency - the configuration is correct */
2098 if (!state->identity.p1g || force_soft_search) {
2099 /* do a minimal captrim even if the frequency has not changed */
2100 state->step = 4;
2101 state->captrim = state->fcaptrim = dib0090_read_reg(state, 0x18) & 0x7f;
2102 }
2103 }
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002104 state->adc_diff = 3000;
Olivier Grenie28fafca2011-01-04 04:27:11 -03002105 *tune_state = CT_TUNER_STEP_0;
2106
2107 } else if (*tune_state == CT_TUNER_STEP_0) {
2108 if (state->identity.p1g && !force_soft_search) {
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002109 u8 ratio = 31;
Olivier Grenie28fafca2011-01-04 04:27:11 -03002110
2111 dib0090_write_reg(state, 0x40, (3 << 7) | (ratio << 2) | (1 << 1) | 1);
2112 dib0090_read_reg(state, 0x40);
Olivier Grenie28fafca2011-01-04 04:27:11 -03002113 ret = 50;
2114 } else {
2115 state->step /= 2;
2116 dib0090_write_reg(state, 0x18, lo4 | state->captrim);
2117
2118 if (state->identity.in_soc)
2119 ret = 25;
2120 }
2121 *tune_state = CT_TUNER_STEP_1;
2122
2123 } else if (*tune_state == CT_TUNER_STEP_1) {
2124 if (state->identity.p1g && !force_soft_search) {
2125 dib0090_write_reg(state, 0x40, 0x18c | (0 << 1) | 0);
2126 dib0090_read_reg(state, 0x40);
2127
2128 state->fcaptrim = dib0090_read_reg(state, 0x18) & 0x7F;
Mauro Carvalho Chehab4bd1a8d2016-10-14 08:16:43 -03002129 dprintk("***Final Captrim= 0x%x\n", state->fcaptrim);
Olivier Grenie28fafca2011-01-04 04:27:11 -03002130 *tune_state = CT_TUNER_STEP_3;
2131
2132 } else {
2133 /* MERGE for all krosus before P1G */
2134 adc = dib0090_get_slow_adc_val(state);
Mauro Carvalho Chehab4bd1a8d2016-10-14 08:16:43 -03002135 dprintk("CAPTRIM=%d; ADC = %d (ADC) & %dmV\n", (u32) state->captrim, (u32) adc, (u32) (adc) * (u32) 1800 / (u32) 1024);
Olivier Grenie28fafca2011-01-04 04:27:11 -03002136
2137 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 !!! */
2138 adc_target = 200;
2139 } else
2140 adc_target = 400;
2141
2142 if (adc >= adc_target) {
2143 adc -= adc_target;
2144 step_sign = -1;
2145 } else {
2146 adc = adc_target - adc;
2147 step_sign = 1;
2148 }
2149
2150 if (adc < state->adc_diff) {
Mauro Carvalho Chehab4bd1a8d2016-10-14 08:16:43 -03002151 dprintk("CAPTRIM=%d is closer to target (%d/%d)\n", (u32) state->captrim, (u32) adc, (u32) state->adc_diff);
Olivier Grenie28fafca2011-01-04 04:27:11 -03002152 state->adc_diff = adc;
2153 state->fcaptrim = state->captrim;
Olivier Grenie28fafca2011-01-04 04:27:11 -03002154 }
2155
2156 state->captrim += step_sign * state->step;
2157 if (state->step >= 1)
2158 *tune_state = CT_TUNER_STEP_0;
2159 else
2160 *tune_state = CT_TUNER_STEP_2;
2161
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002162 ret = 25;
Olivier Grenie28fafca2011-01-04 04:27:11 -03002163 }
2164 } else if (*tune_state == CT_TUNER_STEP_2) { /* this step is only used by krosus < P1G */
2165 /*write the final cptrim config */
2166 dib0090_write_reg(state, 0x18, lo4 | state->fcaptrim);
2167
2168 *tune_state = CT_TUNER_STEP_3;
2169
2170 } else if (*tune_state == CT_TUNER_STEP_3) {
2171 state->calibrate &= ~CAPTRIM_CAL;
2172 *tune_state = CT_TUNER_STEP_0;
2173 }
2174
2175 return ret;
2176}
2177
2178static int dib0090_get_temperature(struct dib0090_state *state, enum frontend_tune_state *tune_state)
2179{
2180 int ret = 15;
2181 s16 val;
2182
Olivier Grenie28fafca2011-01-04 04:27:11 -03002183 switch (*tune_state) {
2184 case CT_TUNER_START:
2185 state->wbdmux = dib0090_read_reg(state, 0x10);
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002186 dib0090_write_reg(state, 0x10, (state->wbdmux & ~(0xff << 3)) | (0x8 << 3));
Olivier Grenie28fafca2011-01-04 04:27:11 -03002187
2188 state->bias = dib0090_read_reg(state, 0x13);
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002189 dib0090_write_reg(state, 0x13, state->bias | (0x3 << 8));
Olivier Grenie28fafca2011-01-04 04:27:11 -03002190
2191 *tune_state = CT_TUNER_STEP_0;
2192 /* wait for the WBDMUX to switch and for the ADC to sample */
2193 break;
2194
2195 case CT_TUNER_STEP_0:
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002196 state->adc_diff = dib0090_get_slow_adc_val(state);
2197 dib0090_write_reg(state, 0x13, (state->bias & ~(0x3 << 8)) | (0x2 << 8));
Olivier Grenie28fafca2011-01-04 04:27:11 -03002198 *tune_state = CT_TUNER_STEP_1;
2199 break;
2200
2201 case CT_TUNER_STEP_1:
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002202 val = dib0090_get_slow_adc_val(state);
2203 state->temperature = ((s16) ((val - state->adc_diff) * 180) >> 8) + 55;
Olivier Grenie28fafca2011-01-04 04:27:11 -03002204
Mauro Carvalho Chehab4bd1a8d2016-10-14 08:16:43 -03002205 dprintk("temperature: %d C\n", state->temperature - 30);
Olivier Grenie28fafca2011-01-04 04:27:11 -03002206
2207 *tune_state = CT_TUNER_STEP_2;
2208 break;
2209
2210 case CT_TUNER_STEP_2:
Olivier Grenie28fafca2011-01-04 04:27:11 -03002211 dib0090_write_reg(state, 0x13, state->bias);
2212 dib0090_write_reg(state, 0x10, state->wbdmux); /* write back original WBDMUX */
2213
2214 *tune_state = CT_TUNER_START;
2215 state->calibrate &= ~TEMP_CAL;
2216 if (state->config->analog_output == 0)
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002217 dib0090_write_reg(state, 0x23, dib0090_read_reg(state, 0x23) | (1 << 14));
Olivier Grenie28fafca2011-01-04 04:27:11 -03002218
2219 break;
2220
2221 default:
2222 ret = 0;
2223 break;
2224 }
2225 return ret;
2226}
2227
Olivier Grenie03245a52009-12-04 13:27:57 -03002228#define WBD 0x781 /* 1 1 1 1 0000 0 0 1 */
2229static int dib0090_tune(struct dvb_frontend *fe)
2230{
2231 struct dib0090_state *state = fe->tuner_priv;
2232 const struct dib0090_tuning *tune = state->current_tune_table_index;
2233 const struct dib0090_pll *pll = state->current_pll_table_index;
2234 enum frontend_tune_state *tune_state = &state->tune_state;
2235
Olivier Grenie28fafca2011-01-04 04:27:11 -03002236 u16 lo5, lo6, Den, tmp;
Olivier Grenie03245a52009-12-04 13:27:57 -03002237 u32 FBDiv, Rest, FREF, VCOF_kHz = 0;
Olivier Grenie03245a52009-12-04 13:27:57 -03002238 int ret = 10; /* 1ms is the default delay most of the time */
2239 u8 c, i;
2240
Olivier Grenie28fafca2011-01-04 04:27:11 -03002241 /************************* VCO ***************************/
Olivier Grenie03245a52009-12-04 13:27:57 -03002242 /* Default values for FG */
2243 /* from these are needed : */
2244 /* Cp,HFdiv,VCOband,SD,Num,Den,FB and REFDiv */
2245
Olivier Grenie28fafca2011-01-04 04:27:11 -03002246 /* in any case we first need to do a calibration if needed */
2247 if (*tune_state == CT_TUNER_START) {
2248 /* deactivate DataTX before some calibrations */
2249 if (state->calibrate & (DC_CAL | TEMP_CAL | WBD_CAL))
2250 dib0090_write_reg(state, 0x23, dib0090_read_reg(state, 0x23) & ~(1 << 14));
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002251 else
2252 /* Activate DataTX in case a calibration has been done before */
2253 if (state->config->analog_output == 0)
2254 dib0090_write_reg(state, 0x23, dib0090_read_reg(state, 0x23) | (1 << 14));
Olivier Grenie03245a52009-12-04 13:27:57 -03002255 }
2256
Olivier Grenie28fafca2011-01-04 04:27:11 -03002257 if (state->calibrate & DC_CAL)
2258 return dib0090_dc_offset_calibration(state, tune_state);
2259 else if (state->calibrate & WBD_CAL) {
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002260 if (state->current_rf == 0)
Olivier Grenie28fafca2011-01-04 04:27:11 -03002261 state->current_rf = state->fe->dtv_property_cache.frequency / 1000;
Olivier Grenie28fafca2011-01-04 04:27:11 -03002262 return dib0090_wbd_calibration(state, tune_state);
2263 } else if (state->calibrate & TEMP_CAL)
2264 return dib0090_get_temperature(state, tune_state);
2265 else if (state->calibrate & CAPTRIM_CAL)
2266 return dib0090_captrim_search(state, tune_state);
2267
Olivier Grenie03245a52009-12-04 13:27:57 -03002268 if (*tune_state == CT_TUNER_START) {
Olivier Grenie28fafca2011-01-04 04:27:11 -03002269 /* 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 */
2270 if (state->config->use_pwm_agc && state->identity.in_soc) {
2271 tmp = dib0090_read_reg(state, 0x39);
2272 if ((tmp >> 10) & 0x1)
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002273 dib0090_write_reg(state, 0x39, tmp & ~(1 << 10));
Olivier Grenie28fafca2011-01-04 04:27:11 -03002274 }
Olivier Grenie03245a52009-12-04 13:27:57 -03002275
Olivier Grenie28fafca2011-01-04 04:27:11 -03002276 state->current_band = (u8) BAND_OF_FREQUENCY(state->fe->dtv_property_cache.frequency / 1000);
2277 state->rf_request =
2278 state->fe->dtv_property_cache.frequency / 1000 + (state->current_band ==
2279 BAND_UHF ? state->config->freq_offset_khz_uhf : state->config->
2280 freq_offset_khz_vhf);
2281
2282 /* in ISDB-T 1seg we shift tuning frequency */
2283 if ((state->fe->dtv_property_cache.delivery_system == SYS_ISDBT && state->fe->dtv_property_cache.isdbt_sb_mode == 1
2284 && state->fe->dtv_property_cache.isdbt_partial_reception == 0)) {
2285 const struct dib0090_low_if_offset_table *LUT_offset = state->config->low_if;
2286 u8 found_offset = 0;
2287 u32 margin_khz = 100;
2288
2289 if (LUT_offset != NULL) {
2290 while (LUT_offset->RF_freq != 0xffff) {
2291 if (((state->rf_request > (LUT_offset->RF_freq - margin_khz))
2292 && (state->rf_request < (LUT_offset->RF_freq + margin_khz)))
2293 && LUT_offset->std == state->fe->dtv_property_cache.delivery_system) {
2294 state->rf_request += LUT_offset->offset_khz;
2295 found_offset = 1;
2296 break;
2297 }
2298 LUT_offset++;
2299 }
2300 }
2301
2302 if (found_offset == 0)
2303 state->rf_request += 400;
2304 }
2305 if (state->current_rf != state->rf_request || (state->current_standard != state->fe->dtv_property_cache.delivery_system)) {
2306 state->tuner_is_tuned = 0;
Olivier Grenie03245a52009-12-04 13:27:57 -03002307 state->current_rf = 0;
Olivier Grenie28fafca2011-01-04 04:27:11 -03002308 state->current_standard = 0;
Olivier Grenie03245a52009-12-04 13:27:57 -03002309
Olivier Grenie28fafca2011-01-04 04:27:11 -03002310 tune = dib0090_tuning_table;
2311 if (state->identity.p1g)
2312 tune = dib0090_p1g_tuning_table;
Olivier Grenie03245a52009-12-04 13:27:57 -03002313
Olivier Grenie28fafca2011-01-04 04:27:11 -03002314 tmp = (state->identity.version >> 5) & 0x7;
2315
2316 if (state->identity.in_soc) {
2317 if (state->config->force_cband_input) { /* Use the CBAND input for all band */
2318 if (state->current_band & BAND_CBAND || state->current_band & BAND_FM || state->current_band & BAND_VHF
2319 || state->current_band & BAND_UHF) {
2320 state->current_band = BAND_CBAND;
Olivier Grenie6724a2f2011-08-05 13:49:33 -03002321 if (state->config->is_dib7090e)
2322 tune = dib0090_tuning_table_cband_7090e_sensitivity;
2323 else
2324 tune = dib0090_tuning_table_cband_7090;
Olivier Grenie28fafca2011-01-04 04:27:11 -03002325 }
2326 } else { /* Use the CBAND input for all band under UHF */
2327 if (state->current_band & BAND_CBAND || state->current_band & BAND_FM || state->current_band & BAND_VHF) {
2328 state->current_band = BAND_CBAND;
Olivier Grenie6724a2f2011-08-05 13:49:33 -03002329 if (state->config->is_dib7090e)
2330 tune = dib0090_tuning_table_cband_7090e_sensitivity;
2331 else
2332 tune = dib0090_tuning_table_cband_7090;
Olivier Grenie28fafca2011-01-04 04:27:11 -03002333 }
2334 }
2335 } else
2336 if (tmp == 0x4 || tmp == 0x7) {
2337 /* CBAND tuner version for VHF */
2338 if (state->current_band == BAND_FM || state->current_band == BAND_CBAND || state->current_band == BAND_VHF) {
2339 state->current_band = BAND_CBAND; /* Force CBAND */
2340
2341 tune = dib0090_tuning_table_fm_vhf_on_cband;
2342 if (state->identity.p1g)
2343 tune = dib0090_p1g_tuning_table_fm_vhf_on_cband;
2344 }
2345 }
2346
2347 pll = dib0090_pll_table;
2348 if (state->identity.p1g)
2349 pll = dib0090_p1g_pll_table;
2350
2351 /* Look for the interval */
2352 while (state->rf_request > tune->max_freq)
2353 tune++;
2354 while (state->rf_request > pll->max_freq)
2355 pll++;
2356
2357 state->current_tune_table_index = tune;
2358 state->current_pll_table_index = pll;
2359
Olivier Grenie03245a52009-12-04 13:27:57 -03002360 dib0090_write_reg(state, 0x0b, 0xb800 | (tune->switch_trim));
2361
Olivier Grenie28fafca2011-01-04 04:27:11 -03002362 VCOF_kHz = (pll->hfdiv * state->rf_request) * 2;
Olivier Grenie03245a52009-12-04 13:27:57 -03002363
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002364 FREF = state->config->io.clock_khz;
Olivier Grenie28fafca2011-01-04 04:27:11 -03002365 if (state->config->fref_clock_ratio != 0)
2366 FREF /= state->config->fref_clock_ratio;
Olivier Grenie03245a52009-12-04 13:27:57 -03002367
Olivier Grenie03245a52009-12-04 13:27:57 -03002368 FBDiv = (VCOF_kHz / pll->topresc / FREF);
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002369 Rest = (VCOF_kHz / pll->topresc) - FBDiv * FREF;
Olivier Grenie03245a52009-12-04 13:27:57 -03002370
2371 if (Rest < LPF)
2372 Rest = 0;
2373 else if (Rest < 2 * LPF)
2374 Rest = 2 * LPF;
2375 else if (Rest > (FREF - LPF)) {
2376 Rest = 0;
2377 FBDiv += 1;
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002378 } else if (Rest > (FREF - 2 * LPF))
Olivier Grenie03245a52009-12-04 13:27:57 -03002379 Rest = FREF - 2 * LPF;
2380 Rest = (Rest * 6528) / (FREF / 10);
Olivier Grenie28fafca2011-01-04 04:27:11 -03002381 state->rest = Rest;
2382
2383 /* external loop filter, otherwise:
2384 * lo5 = (0 << 15) | (0 << 12) | (0 << 11) | (3 << 9) | (4 << 6) | (3 << 4) | 4;
2385 * lo6 = 0x0e34 */
2386
2387 if (Rest == 0) {
2388 if (pll->vco_band)
2389 lo5 = 0x049f;
Olivier Grenie28fafca2011-01-04 04:27:11 -03002390 else
2391 lo5 = 0x041f;
2392 } else {
2393 if (pll->vco_band)
2394 lo5 = 0x049e;
2395 else if (state->config->analog_output)
2396 lo5 = 0x041d;
2397 else
2398 lo5 = 0x041c;
2399 }
2400
2401 if (state->identity.p1g) { /* Bias is done automatically in P1G */
2402 if (state->identity.in_soc) {
2403 if (state->identity.version == SOC_8090_P1G_11R1)
2404 lo5 = 0x46f;
2405 else
2406 lo5 = 0x42f;
2407 } else
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002408 lo5 = 0x42c;
Olivier Grenie28fafca2011-01-04 04:27:11 -03002409 }
2410
2411 lo5 |= (pll->hfdiv_code << 11) | (pll->vco_band << 7); /* bit 15 is the split to the slave, we do not do it here */
2412
Olivier Grenie28fafca2011-01-04 04:27:11 -03002413 if (!state->config->io.pll_int_loop_filt) {
2414 if (state->identity.in_soc)
2415 lo6 = 0xff98;
2416 else if (state->identity.p1g || (Rest == 0))
2417 lo6 = 0xfff8;
2418 else
2419 lo6 = 0xff28;
2420 } else
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002421 lo6 = (state->config->io.pll_int_loop_filt << 3);
Olivier Grenie03245a52009-12-04 13:27:57 -03002422
2423 Den = 1;
2424
Olivier Grenie03245a52009-12-04 13:27:57 -03002425 if (Rest > 0) {
Gustavo A. R. Silva87c01482017-08-17 21:23:44 -04002426 lo6 |= (1 << 2) | 2;
Olivier Grenie03245a52009-12-04 13:27:57 -03002427 Den = 255;
2428 }
Olivier Grenie03245a52009-12-04 13:27:57 -03002429 dib0090_write_reg(state, 0x15, (u16) FBDiv);
Olivier Grenie28fafca2011-01-04 04:27:11 -03002430 if (state->config->fref_clock_ratio != 0)
2431 dib0090_write_reg(state, 0x16, (Den << 8) | state->config->fref_clock_ratio);
2432 else
2433 dib0090_write_reg(state, 0x16, (Den << 8) | 1);
Olivier Grenie03245a52009-12-04 13:27:57 -03002434 dib0090_write_reg(state, 0x17, (u16) Rest);
Olivier Grenie03245a52009-12-04 13:27:57 -03002435 dib0090_write_reg(state, 0x19, lo5);
Olivier Grenie03245a52009-12-04 13:27:57 -03002436 dib0090_write_reg(state, 0x1c, lo6);
2437
2438 lo6 = tune->tuner_enable;
2439 if (state->config->analog_output)
2440 lo6 = (lo6 & 0xff9f) | 0x2;
2441
Olivier Grenie28fafca2011-01-04 04:27:11 -03002442 dib0090_write_reg(state, 0x24, lo6 | EN_LO | state->config->use_pwm_agc * EN_CRYSTAL);
Olivier Grenie03245a52009-12-04 13:27:57 -03002443
Olivier Grenie03245a52009-12-04 13:27:57 -03002444 }
Olivier Grenie03245a52009-12-04 13:27:57 -03002445
Olivier Grenie28fafca2011-01-04 04:27:11 -03002446 state->current_rf = state->rf_request;
2447 state->current_standard = state->fe->dtv_property_cache.delivery_system;
Olivier Grenie03245a52009-12-04 13:27:57 -03002448
2449 ret = 20;
Mauro Carvalho Chehab868c9a12019-02-18 14:28:55 -05002450 state->calibrate = CAPTRIM_CAL; /* captrim search now */
Olivier Grenie28fafca2011-01-04 04:27:11 -03002451 }
Olivier Grenie03245a52009-12-04 13:27:57 -03002452
Olivier Grenie28fafca2011-01-04 04:27:11 -03002453 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 */
2454 const struct dib0090_wbd_slope *wbd = state->current_wbd_table;
Olivier Grenie03245a52009-12-04 13:27:57 -03002455
Olivier Grenie28fafca2011-01-04 04:27:11 -03002456 while (state->current_rf / 1000 > wbd->max_freq)
2457 wbd++;
Olivier Grenie03245a52009-12-04 13:27:57 -03002458
Olivier Grenie03245a52009-12-04 13:27:57 -03002459 dib0090_write_reg(state, 0x1e, 0x07ff);
Mauro Carvalho Chehab4bd1a8d2016-10-14 08:16:43 -03002460 dprintk("Final Captrim: %d\n", (u32) state->fcaptrim);
2461 dprintk("HFDIV code: %d\n", (u32) pll->hfdiv_code);
2462 dprintk("VCO = %d\n", (u32) pll->vco_band);
2463 dprintk("VCOF in kHz: %d ((%d*%d) << 1))\n", (u32) ((pll->hfdiv * state->rf_request) * 2), (u32) pll->hfdiv, (u32) state->rf_request);
2464 dprintk("REFDIV: %d, FREF: %d\n", (u32) 1, (u32) state->config->io.clock_khz);
2465 dprintk("FBDIV: %d, Rest: %d\n", (u32) dib0090_read_reg(state, 0x15), (u32) dib0090_read_reg(state, 0x17));
2466 dprintk("Num: %d, Den: %d, SD: %d\n", (u32) dib0090_read_reg(state, 0x17), (u32) (dib0090_read_reg(state, 0x16) >> 8),
Olivier Grenie28fafca2011-01-04 04:27:11 -03002467 (u32) dib0090_read_reg(state, 0x1c) & 0x3);
Olivier Grenie03245a52009-12-04 13:27:57 -03002468
Olivier Grenie28fafca2011-01-04 04:27:11 -03002469#define WBD 0x781 /* 1 1 1 1 0000 0 0 1 */
Olivier Grenie03245a52009-12-04 13:27:57 -03002470 c = 4;
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002471 i = 3;
Olivier Grenie28fafca2011-01-04 04:27:11 -03002472
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002473 if (wbd->wbd_gain != 0)
Olivier Grenie28fafca2011-01-04 04:27:11 -03002474 c = wbd->wbd_gain;
2475
Olivier Grenie28fafca2011-01-04 04:27:11 -03002476 state->wbdmux = (c << 13) | (i << 11) | (WBD | (state->config->use_pwm_agc << 1));
2477 dib0090_write_reg(state, 0x10, state->wbdmux);
2478
2479 if ((tune->tuner_enable == EN_CAB) && state->identity.p1g) {
Mauro Carvalho Chehab4bd1a8d2016-10-14 08:16:43 -03002480 dprintk("P1G : The cable band is selected and lna_tune = %d\n", tune->lna_tune);
Olivier Grenie28fafca2011-01-04 04:27:11 -03002481 dib0090_write_reg(state, 0x09, tune->lna_bias);
2482 dib0090_write_reg(state, 0x0b, 0xb800 | (tune->lna_tune << 6) | (tune->switch_trim));
2483 } else
2484 dib0090_write_reg(state, 0x09, (tune->lna_tune << 5) | tune->lna_bias);
2485
Olivier Grenie03245a52009-12-04 13:27:57 -03002486 dib0090_write_reg(state, 0x0c, tune->v2i);
2487 dib0090_write_reg(state, 0x0d, tune->mix);
2488 dib0090_write_reg(state, 0x0e, tune->load);
Olivier Grenie28fafca2011-01-04 04:27:11 -03002489 *tune_state = CT_TUNER_STEP_1;
Olivier Grenie03245a52009-12-04 13:27:57 -03002490
Olivier Grenie28fafca2011-01-04 04:27:11 -03002491 } else if (*tune_state == CT_TUNER_STEP_1) {
Olivier Grenie03245a52009-12-04 13:27:57 -03002492 /* initialize the lt gain register */
2493 state->rf_lt_def = 0x7c00;
Olivier Grenie03245a52009-12-04 13:27:57 -03002494
2495 dib0090_set_bandwidth(state);
2496 state->tuner_is_tuned = 1;
Olivier Grenie28fafca2011-01-04 04:27:11 -03002497
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002498 state->calibrate |= WBD_CAL;
2499 state->calibrate |= TEMP_CAL;
Olivier Grenie03245a52009-12-04 13:27:57 -03002500 *tune_state = CT_TUNER_STOP;
2501 } else
2502 ret = FE_CALLBACK_TIME_NEVER;
2503 return ret;
2504}
2505
Mauro Carvalho Chehabf2709c22016-11-18 20:30:51 -02002506static void dib0090_release(struct dvb_frontend *fe)
2507{
2508 kfree(fe->tuner_priv);
2509 fe->tuner_priv = NULL;
2510}
2511
Olivier Grenie03245a52009-12-04 13:27:57 -03002512enum frontend_tune_state dib0090_get_tune_state(struct dvb_frontend *fe)
2513{
2514 struct dib0090_state *state = fe->tuner_priv;
2515
2516 return state->tune_state;
2517}
Olivier Grenie28fafca2011-01-04 04:27:11 -03002518
Olivier Grenie03245a52009-12-04 13:27:57 -03002519EXPORT_SYMBOL(dib0090_get_tune_state);
2520
2521int dib0090_set_tune_state(struct dvb_frontend *fe, enum frontend_tune_state tune_state)
2522{
2523 struct dib0090_state *state = fe->tuner_priv;
2524
2525 state->tune_state = tune_state;
2526 return 0;
2527}
Olivier Grenie28fafca2011-01-04 04:27:11 -03002528
Olivier Grenie03245a52009-12-04 13:27:57 -03002529EXPORT_SYMBOL(dib0090_set_tune_state);
2530
2531static int dib0090_get_frequency(struct dvb_frontend *fe, u32 * frequency)
2532{
2533 struct dib0090_state *state = fe->tuner_priv;
2534
2535 *frequency = 1000 * state->current_rf;
2536 return 0;
2537}
2538
Mauro Carvalho Chehab14d24d12011-12-24 12:24:33 -03002539static int dib0090_set_params(struct dvb_frontend *fe)
Olivier Grenie03245a52009-12-04 13:27:57 -03002540{
2541 struct dib0090_state *state = fe->tuner_priv;
Olivier Grenie28fafca2011-01-04 04:27:11 -03002542 u32 ret;
Olivier Grenie03245a52009-12-04 13:27:57 -03002543
2544 state->tune_state = CT_TUNER_START;
2545
2546 do {
2547 ret = dib0090_tune(fe);
Mauro Carvalho Chehab0de04ca2014-07-04 14:15:36 -03002548 if (ret == FE_CALLBACK_TIME_NEVER)
Olivier Grenie03245a52009-12-04 13:27:57 -03002549 break;
Mauro Carvalho Chehab0de04ca2014-07-04 14:15:36 -03002550
2551 /*
2552 * Despite dib0090_tune returns time at a 0.1 ms range,
2553 * the actual sleep time depends on CONFIG_HZ. The worse case
2554 * is when CONFIG_HZ=100. In such case, the minimum granularity
2555 * is 10ms. On some real field tests, the tuner sometimes don't
2556 * lock when this timer is lower than 10ms. So, enforce a 10ms
2557 * granularity and use usleep_range() instead of msleep().
2558 */
2559 ret = 10 * (ret + 99)/100;
2560 usleep_range(ret * 1000, (ret + 1) * 1000);
Olivier Grenie03245a52009-12-04 13:27:57 -03002561 } while (state->tune_state != CT_TUNER_STOP);
2562
2563 return 0;
2564}
2565
2566static const struct dvb_tuner_ops dib0090_ops = {
2567 .info = {
2568 .name = "DiBcom DiB0090",
Mauro Carvalho Chehaba3f90c72018-07-05 18:59:35 -04002569 .frequency_min_hz = 45 * MHz,
2570 .frequency_max_hz = 860 * MHz,
2571 .frequency_step_hz = 1 * kHz,
Olivier Grenie03245a52009-12-04 13:27:57 -03002572 },
Mauro Carvalho Chehabf2709c22016-11-18 20:30:51 -02002573 .release = dib0090_release,
Olivier Grenie03245a52009-12-04 13:27:57 -03002574
2575 .init = dib0090_wakeup,
2576 .sleep = dib0090_sleep,
2577 .set_params = dib0090_set_params,
2578 .get_frequency = dib0090_get_frequency,
2579};
2580
Olivier Grenie28fafca2011-01-04 04:27:11 -03002581static const struct dvb_tuner_ops dib0090_fw_ops = {
2582 .info = {
2583 .name = "DiBcom DiB0090",
Mauro Carvalho Chehaba3f90c72018-07-05 18:59:35 -04002584 .frequency_min_hz = 45 * MHz,
2585 .frequency_max_hz = 860 * MHz,
2586 .frequency_step_hz = 1 * kHz,
Olivier Grenie28fafca2011-01-04 04:27:11 -03002587 },
Mauro Carvalho Chehabf2709c22016-11-18 20:30:51 -02002588 .release = dib0090_release,
Olivier Grenie28fafca2011-01-04 04:27:11 -03002589
2590 .init = NULL,
2591 .sleep = NULL,
2592 .set_params = NULL,
2593 .get_frequency = NULL,
2594};
2595
2596static const struct dib0090_wbd_slope dib0090_wbd_table_default[] = {
2597 {470, 0, 250, 0, 100, 4},
2598 {860, 51, 866, 21, 375, 4},
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002599 {1700, 0, 800, 0, 850, 4},
2600 {2900, 0, 250, 0, 100, 6},
Olivier Grenie28fafca2011-01-04 04:27:11 -03002601 {0xFFFF, 0, 0, 0, 0, 0},
2602};
2603
Olivier Grenie03245a52009-12-04 13:27:57 -03002604struct dvb_frontend *dib0090_register(struct dvb_frontend *fe, struct i2c_adapter *i2c, const struct dib0090_config *config)
2605{
2606 struct dib0090_state *st = kzalloc(sizeof(struct dib0090_state), GFP_KERNEL);
2607 if (st == NULL)
2608 return NULL;
2609
2610 st->config = config;
2611 st->i2c = i2c;
2612 st->fe = fe;
Patrick Boettcher79fcce32011-08-03 12:08:21 -03002613 mutex_init(&st->i2c_buffer_lock);
Olivier Grenie03245a52009-12-04 13:27:57 -03002614 fe->tuner_priv = st;
2615
Olivier Grenie28fafca2011-01-04 04:27:11 -03002616 if (config->wbd == NULL)
2617 st->current_wbd_table = dib0090_wbd_table_default;
2618 else
2619 st->current_wbd_table = config->wbd;
2620
Olivier Grenie03245a52009-12-04 13:27:57 -03002621 if (dib0090_reset(fe) != 0)
2622 goto free_mem;
2623
Mauro Carvalho Chehab4bd1a8d2016-10-14 08:16:43 -03002624 pr_info("DiB0090: successfully identified\n");
Olivier Grenie03245a52009-12-04 13:27:57 -03002625 memcpy(&fe->ops.tuner_ops, &dib0090_ops, sizeof(struct dvb_tuner_ops));
2626
2627 return fe;
2628 free_mem:
2629 kfree(st);
2630 fe->tuner_priv = NULL;
2631 return NULL;
2632}
Olivier Grenie28fafca2011-01-04 04:27:11 -03002633
Olivier Grenie03245a52009-12-04 13:27:57 -03002634EXPORT_SYMBOL(dib0090_register);
2635
Olivier Grenie28fafca2011-01-04 04:27:11 -03002636struct dvb_frontend *dib0090_fw_register(struct dvb_frontend *fe, struct i2c_adapter *i2c, const struct dib0090_config *config)
2637{
2638 struct dib0090_fw_state *st = kzalloc(sizeof(struct dib0090_fw_state), GFP_KERNEL);
2639 if (st == NULL)
2640 return NULL;
2641
2642 st->config = config;
2643 st->i2c = i2c;
2644 st->fe = fe;
Patrick Boettcher79fcce32011-08-03 12:08:21 -03002645 mutex_init(&st->i2c_buffer_lock);
Olivier Grenie28fafca2011-01-04 04:27:11 -03002646 fe->tuner_priv = st;
2647
2648 if (dib0090_fw_reset_digital(fe, st->config) != 0)
2649 goto free_mem;
2650
Mauro Carvalho Chehab4bd1a8d2016-10-14 08:16:43 -03002651 dprintk("DiB0090 FW: successfully identified\n");
Olivier Grenie28fafca2011-01-04 04:27:11 -03002652 memcpy(&fe->ops.tuner_ops, &dib0090_fw_ops, sizeof(struct dvb_tuner_ops));
2653
2654 return fe;
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002655free_mem:
Olivier Grenie28fafca2011-01-04 04:27:11 -03002656 kfree(st);
2657 fe->tuner_priv = NULL;
2658 return NULL;
2659}
Olivier Grenie28fafca2011-01-04 04:27:11 -03002660EXPORT_SYMBOL(dib0090_fw_register);
2661
Patrick Boettcher99e44da2016-01-24 12:56:58 -02002662MODULE_AUTHOR("Patrick Boettcher <patrick.boettcher@posteo.de>");
2663MODULE_AUTHOR("Olivier Grenie <olivier.grenie@parrot.com>");
Olivier Grenie03245a52009-12-04 13:27:57 -03002664MODULE_DESCRIPTION("Driver for the DiBcom 0090 base-band RF Tuner");
2665MODULE_LICENSE("GPL");