Merge tag 'for-linus-5.4-rc1-tag' of git://git.kernel.org/pub/scm/linux/kernel/git...
[linux-2.6-block.git] / drivers / media / dvb-frontends / dib0070.c
CommitLineData
c942fddf 1// SPDX-License-Identifier: GPL-2.0-or-later
01373a5c
PB
2/*
3 * Linux-DVB Driver for DiBcom's DiB0070 base-band RF Tuner.
4 *
7e5ce651 5 * Copyright (C) 2005-9 DiBcom (http://www.dibcom.fr/)
01373a5c 6 *
7e5ce651
PB
7 * This code is more or less generated from another driver, please
8 * excuse some codingstyle oddities.
01373a5c 9 */
7e5ce651 10
fb11cbd1
MCC
11#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
12
01373a5c 13#include <linux/kernel.h>
5a0e3ad6 14#include <linux/slab.h>
01373a5c 15#include <linux/i2c.h>
79fcce32 16#include <linux/mutex.h>
01373a5c 17
fada1935 18#include <media/dvb_frontend.h>
01373a5c
PB
19
20#include "dib0070.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
fb11cbd1
MCC
27#define dprintk(fmt, arg...) do { \
28 if (debug) \
29 printk(KERN_DEBUG pr_fmt("%s: " fmt), \
30 __func__, ##arg); \
7e5ce651 31} while (0)
01373a5c
PB
32
33#define DIB0070_P1D 0x00
34#define DIB0070_P1F 0x01
35#define DIB0070_P1G 0x03
36#define DIB0070S_P1A 0x02
37
38struct dib0070_state {
39 struct i2c_adapter *i2c;
40 struct dvb_frontend *fe;
41 const struct dib0070_config *cfg;
42 u16 wbd_ff_offset;
43 u8 revision;
7e5ce651 44
f3f8ef22
MCC
45 enum frontend_tune_state tune_state;
46 u32 current_rf;
7e5ce651 47
f3f8ef22 48 /* for the captrim binary search */
7e5ce651
PB
49 s8 step;
50 u16 adc_diff;
51
52 s8 captrim;
53 s8 fcaptrim;
54 u16 lo4;
55
56 const struct dib0070_tuning *current_tune_table_index;
57 const struct dib0070_lna_match *lna_match;
58
f3f8ef22 59 u8 wbd_gain_current;
7e5ce651 60 u16 wbd_offset_3_3[2];
5a0deeed
OG
61
62 /* for the I2C transfer */
63 struct i2c_msg msg[2];
64 u8 i2c_write_buffer[3];
65 u8 i2c_read_buffer[2];
79fcce32 66 struct mutex i2c_buffer_lock;
01373a5c
PB
67};
68
79fcce32 69static u16 dib0070_read_reg(struct dib0070_state *state, u8 reg)
01373a5c 70{
79fcce32
PB
71 u16 ret;
72
73 if (mutex_lock_interruptible(&state->i2c_buffer_lock) < 0) {
fb11cbd1 74 dprintk("could not acquire lock\n");
79fcce32
PB
75 return 0;
76 }
77
5a0deeed
OG
78 state->i2c_write_buffer[0] = reg;
79
80 memset(state->msg, 0, 2 * sizeof(struct i2c_msg));
81 state->msg[0].addr = state->cfg->i2c_address;
82 state->msg[0].flags = 0;
83 state->msg[0].buf = state->i2c_write_buffer;
84 state->msg[0].len = 1;
85 state->msg[1].addr = state->cfg->i2c_address;
86 state->msg[1].flags = I2C_M_RD;
87 state->msg[1].buf = state->i2c_read_buffer;
88 state->msg[1].len = 2;
89
90 if (i2c_transfer(state->i2c, state->msg, 2) != 2) {
fb11cbd1 91 pr_warn("DiB0070 I2C read failed\n");
79fcce32
PB
92 ret = 0;
93 } else
94 ret = (state->i2c_read_buffer[0] << 8)
95 | state->i2c_read_buffer[1];
96
97 mutex_unlock(&state->i2c_buffer_lock);
98 return ret;
01373a5c
PB
99}
100
101static int dib0070_write_reg(struct dib0070_state *state, u8 reg, u16 val)
102{
79fcce32
PB
103 int ret;
104
105 if (mutex_lock_interruptible(&state->i2c_buffer_lock) < 0) {
fb11cbd1 106 dprintk("could not acquire lock\n");
79fcce32
PB
107 return -EINVAL;
108 }
5a0deeed
OG
109 state->i2c_write_buffer[0] = reg;
110 state->i2c_write_buffer[1] = val >> 8;
111 state->i2c_write_buffer[2] = val & 0xff;
112
113 memset(state->msg, 0, sizeof(struct i2c_msg));
114 state->msg[0].addr = state->cfg->i2c_address;
115 state->msg[0].flags = 0;
116 state->msg[0].buf = state->i2c_write_buffer;
117 state->msg[0].len = 3;
118
119 if (i2c_transfer(state->i2c, state->msg, 1) != 1) {
fb11cbd1 120 pr_warn("DiB0070 I2C write failed\n");
79fcce32
PB
121 ret = -EREMOTEIO;
122 } else
123 ret = 0;
124
125 mutex_unlock(&state->i2c_buffer_lock);
126 return ret;
01373a5c
PB
127}
128
7e5ce651
PB
129#define HARD_RESET(state) do { \
130 state->cfg->sleep(state->fe, 0); \
131 if (state->cfg->reset) { \
132 state->cfg->reset(state->fe,1); msleep(10); \
133 state->cfg->reset(state->fe,0); msleep(10); \
134 } \
135} while (0)
01373a5c 136
c79c9fb3 137static int dib0070_set_bandwidth(struct dvb_frontend *fe)
f3f8ef22
MCC
138 {
139 struct dib0070_state *state = fe->tuner_priv;
140 u16 tmp = dib0070_read_reg(state, 0x02) & 0x3fff;
141
142 if (state->fe->dtv_property_cache.bandwidth_hz/1000 > 7000)
143 tmp |= (0 << 14);
144 else if (state->fe->dtv_property_cache.bandwidth_hz/1000 > 6000)
145 tmp |= (1 << 14);
146 else if (state->fe->dtv_property_cache.bandwidth_hz/1000 > 5000)
147 tmp |= (2 << 14);
148 else
149 tmp |= (3 << 14);
150
151 dib0070_write_reg(state, 0x02, tmp);
152
153 /* sharpen the BB filter in ISDB-T to have higher immunity to adjacent channels */
154 if (state->fe->dtv_property_cache.delivery_system == SYS_ISDBT) {
155 u16 value = dib0070_read_reg(state, 0x17);
156
157 dib0070_write_reg(state, 0x17, value & 0xfffc);
158 tmp = dib0070_read_reg(state, 0x01) & 0x01ff;
159 dib0070_write_reg(state, 0x01, tmp | (60 << 9));
160
161 dib0070_write_reg(state, 0x17, value);
162 }
01373a5c
PB
163 return 0;
164}
165
2a6a30e0 166static int dib0070_captrim(struct dib0070_state *state, enum frontend_tune_state *tune_state)
01373a5c 167{
7e5ce651
PB
168 int8_t step_sign;
169 u16 adc;
170 int ret = 0;
01373a5c 171
7e5ce651 172 if (*tune_state == CT_TUNER_STEP_0) {
2a6a30e0 173 dib0070_write_reg(state, 0x0f, 0xed10);
03245a5e 174 dib0070_write_reg(state, 0x17, 0x0034);
01373a5c 175
2a6a30e0
PB
176 dib0070_write_reg(state, 0x18, 0x0032);
177 state->step = state->captrim = state->fcaptrim = 64;
178 state->adc_diff = 3000;
7e5ce651 179 ret = 20;
01373a5c 180
f3f8ef22 181 *tune_state = CT_TUNER_STEP_1;
7e5ce651 182 } else if (*tune_state == CT_TUNER_STEP_1) {
2a6a30e0
PB
183 state->step /= 2;
184 dib0070_write_reg(state, 0x14, state->lo4 | state->captrim);
7e5ce651 185 ret = 15;
01373a5c 186
7e5ce651
PB
187 *tune_state = CT_TUNER_STEP_2;
188 } else if (*tune_state == CT_TUNER_STEP_2) {
01373a5c 189
2a6a30e0 190 adc = dib0070_read_reg(state, 0x19);
01373a5c 191
fb11cbd1 192 dprintk("CAPTRIM=%hd; ADC = %hd (ADC) & %dmV\n", state->captrim, adc, (u32) adc*(u32)1800/(u32)1024);
01373a5c
PB
193
194 if (adc >= 400) {
195 adc -= 400;
196 step_sign = -1;
197 } else {
198 adc = 400 - adc;
199 step_sign = 1;
200 }
201
2a6a30e0 202 if (adc < state->adc_diff) {
fb11cbd1 203 dprintk("CAPTRIM=%hd is closer to target (%hd/%hd)\n", state->captrim, adc, state->adc_diff);
2a6a30e0
PB
204 state->adc_diff = adc;
205 state->fcaptrim = state->captrim;
01373a5c 206 }
2a6a30e0 207 state->captrim += (step_sign * state->step);
7e5ce651 208
2a6a30e0 209 if (state->step >= 1)
7e5ce651
PB
210 *tune_state = CT_TUNER_STEP_1;
211 else
212 *tune_state = CT_TUNER_STEP_3;
213
214 } else if (*tune_state == CT_TUNER_STEP_3) {
2a6a30e0
PB
215 dib0070_write_reg(state, 0x14, state->lo4 | state->fcaptrim);
216 dib0070_write_reg(state, 0x18, 0x07ff);
7e5ce651
PB
217 *tune_state = CT_TUNER_STEP_4;
218 }
01373a5c 219
7e5ce651 220 return ret;
01373a5c
PB
221}
222
7e5ce651 223static int dib0070_set_ctrl_lo5(struct dvb_frontend *fe, u8 vco_bias_trim, u8 hf_div_trim, u8 cp_current, u8 third_order_filt)
01373a5c 224{
7e5ce651 225 struct dib0070_state *state = fe->tuner_priv;
f3f8ef22
MCC
226 u16 lo5 = (third_order_filt << 14) | (0 << 13) | (1 << 12) | (3 << 9) | (cp_current << 6) | (hf_div_trim << 3) | (vco_bias_trim << 0);
227
fb11cbd1 228 dprintk("CTRL_LO5: 0x%x\n", lo5);
7e5ce651
PB
229 return dib0070_write_reg(state, 0x15, lo5);
230}
01373a5c 231
2a6a30e0 232void dib0070_ctrl_agc_filter(struct dvb_frontend *fe, u8 open)
7e5ce651 233{
2a6a30e0 234 struct dib0070_state *state = fe->tuner_priv;
01373a5c 235
2a6a30e0
PB
236 if (open) {
237 dib0070_write_reg(state, 0x1b, 0xff00);
238 dib0070_write_reg(state, 0x1a, 0x0000);
239 } else {
240 dib0070_write_reg(state, 0x1b, 0x4112);
f3f8ef22
MCC
241 if (state->cfg->vga_filter != 0) {
242 dib0070_write_reg(state, 0x1a, state->cfg->vga_filter);
fb11cbd1 243 dprintk("vga filter register is set to %x\n", state->cfg->vga_filter);
f3f8ef22
MCC
244 } else
245 dib0070_write_reg(state, 0x1a, 0x0009);
2a6a30e0
PB
246 }
247}
01373a5c 248
2a6a30e0
PB
249EXPORT_SYMBOL(dib0070_ctrl_agc_filter);
250struct dib0070_tuning {
f3f8ef22
MCC
251 u32 max_freq; /* for every frequency less than or equal to that field: this information is correct */
252 u8 switch_trim;
253 u8 vco_band;
254 u8 hfdiv;
255 u8 vco_multi;
256 u8 presc;
257 u8 wbdmux;
258 u16 tuner_enable;
7e5ce651 259};
01373a5c 260
2a6a30e0 261struct dib0070_lna_match {
f3f8ef22
MCC
262 u32 max_freq; /* for every frequency less than or equal to that field: this information is correct */
263 u8 lna_band;
7e5ce651 264};
01373a5c 265
2a6a30e0 266static const struct dib0070_tuning dib0070s_tuning_table[] = {
f3f8ef22
MCC
267 { 570000, 2, 1, 3, 6, 6, 2, 0x4000 | 0x0800 }, /* UHF */
268 { 700000, 2, 0, 2, 4, 2, 2, 0x4000 | 0x0800 },
269 { 863999, 2, 1, 2, 4, 2, 2, 0x4000 | 0x0800 },
270 { 1500000, 0, 1, 1, 2, 2, 4, 0x2000 | 0x0400 }, /* LBAND */
271 { 1600000, 0, 1, 1, 2, 2, 4, 0x2000 | 0x0400 },
272 { 2000000, 0, 1, 1, 2, 2, 4, 0x2000 | 0x0400 },
273 { 0xffffffff, 0, 0, 8, 1, 2, 1, 0x8000 | 0x1000 }, /* SBAND */
2a6a30e0 274};
01373a5c 275
2a6a30e0 276static const struct dib0070_tuning dib0070_tuning_table[] = {
f3f8ef22
MCC
277 { 115000, 1, 0, 7, 24, 2, 1, 0x8000 | 0x1000 }, /* FM below 92MHz cannot be tuned */
278 { 179500, 1, 0, 3, 16, 2, 1, 0x8000 | 0x1000 }, /* VHF */
279 { 189999, 1, 1, 3, 16, 2, 1, 0x8000 | 0x1000 },
280 { 250000, 1, 0, 6, 12, 2, 1, 0x8000 | 0x1000 },
281 { 569999, 2, 1, 5, 6, 2, 2, 0x4000 | 0x0800 }, /* UHF */
282 { 699999, 2, 0, 1, 4, 2, 2, 0x4000 | 0x0800 },
283 { 863999, 2, 1, 1, 4, 2, 2, 0x4000 | 0x0800 },
284 { 0xffffffff, 0, 1, 0, 2, 2, 4, 0x2000 | 0x0400 }, /* LBAND or everything higher than UHF */
7e5ce651 285};
01373a5c 286
2a6a30e0 287static const struct dib0070_lna_match dib0070_lna_flip_chip[] = {
f3f8ef22
MCC
288 { 180000, 0 }, /* VHF */
289 { 188000, 1 },
290 { 196400, 2 },
291 { 250000, 3 },
292 { 550000, 0 }, /* UHF */
293 { 590000, 1 },
294 { 666000, 3 },
295 { 864000, 5 },
296 { 1500000, 0 }, /* LBAND or everything higher than UHF */
297 { 1600000, 1 },
298 { 2000000, 3 },
299 { 0xffffffff, 7 },
2a6a30e0 300};
01373a5c 301
2a6a30e0 302static const struct dib0070_lna_match dib0070_lna[] = {
f3f8ef22
MCC
303 { 180000, 0 }, /* VHF */
304 { 188000, 1 },
305 { 196400, 2 },
306 { 250000, 3 },
307 { 550000, 2 }, /* UHF */
308 { 650000, 3 },
309 { 750000, 5 },
310 { 850000, 6 },
311 { 864000, 7 },
312 { 1500000, 0 }, /* LBAND or everything higher than UHF */
313 { 1600000, 1 },
314 { 2000000, 3 },
315 { 0xffffffff, 7 },
7e5ce651 316};
01373a5c 317
9c783036 318#define LPF 100
c79c9fb3 319static int dib0070_tune_digital(struct dvb_frontend *fe)
7e5ce651 320{
f3f8ef22 321 struct dib0070_state *state = fe->tuner_priv;
7e5ce651 322
f3f8ef22
MCC
323 const struct dib0070_tuning *tune;
324 const struct dib0070_lna_match *lna_match;
7e5ce651 325
f3f8ef22
MCC
326 enum frontend_tune_state *tune_state = &state->tune_state;
327 int ret = 10; /* 1ms is the default delay most of the time */
2a6a30e0 328
f3f8ef22
MCC
329 u8 band = (u8)BAND_OF_FREQUENCY(fe->dtv_property_cache.frequency/1000);
330 u32 freq = fe->dtv_property_cache.frequency/1000 + (band == BAND_VHF ? state->cfg->freq_offset_khz_vhf : state->cfg->freq_offset_khz_uhf);
2a6a30e0
PB
331
332#ifdef CONFIG_SYS_ISDBT
f3f8ef22
MCC
333 if (state->fe->dtv_property_cache.delivery_system == SYS_ISDBT && state->fe->dtv_property_cache.isdbt_sb_mode == 1)
334 if (((state->fe->dtv_property_cache.isdbt_sb_segment_count % 2)
335 && (state->fe->dtv_property_cache.isdbt_sb_segment_idx == ((state->fe->dtv_property_cache.isdbt_sb_segment_count / 2) + 1)))
336 || (((state->fe->dtv_property_cache.isdbt_sb_segment_count % 2) == 0)
337 && (state->fe->dtv_property_cache.isdbt_sb_segment_idx == (state->fe->dtv_property_cache.isdbt_sb_segment_count / 2)))
338 || (((state->fe->dtv_property_cache.isdbt_sb_segment_count % 2) == 0)
339 && (state->fe->dtv_property_cache.isdbt_sb_segment_idx == ((state->fe->dtv_property_cache.isdbt_sb_segment_count / 2) + 1))))
340 freq += 850;
7e5ce651 341#endif
2a6a30e0 342 if (state->current_rf != freq) {
9c783036
OG
343
344 switch (state->revision) {
345 case DIB0070S_P1A:
f3f8ef22
MCC
346 tune = dib0070s_tuning_table;
347 lna_match = dib0070_lna;
348 break;
9c783036 349 default:
f3f8ef22
MCC
350 tune = dib0070_tuning_table;
351 if (state->cfg->flip_chip)
352 lna_match = dib0070_lna_flip_chip;
353 else
354 lna_match = dib0070_lna;
355 break;
9c783036 356 }
f3f8ef22
MCC
357 while (freq > tune->max_freq) /* find the right one */
358 tune++;
359 while (freq > lna_match->max_freq) /* find the right one */
360 lna_match++;
9c783036 361
f3f8ef22
MCC
362 state->current_tune_table_index = tune;
363 state->lna_match = lna_match;
364 }
9c783036 365
f3f8ef22 366 if (*tune_state == CT_TUNER_START) {
fb11cbd1 367 dprintk("Tuning for Band: %hd (%d kHz)\n", band, freq);
f3f8ef22
MCC
368 if (state->current_rf != freq) {
369 u8 REFDIV;
370 u32 FBDiv, Rest, FREF, VCOF_kHz;
371 u8 Den;
372
373 state->current_rf = freq;
374 state->lo4 = (state->current_tune_table_index->vco_band << 11) | (state->current_tune_table_index->hfdiv << 7);
375
376
377 dib0070_write_reg(state, 0x17, 0x30);
378
379
380 VCOF_kHz = state->current_tune_table_index->vco_multi * freq * 2;
381
382 switch (band) {
383 case BAND_VHF:
384 REFDIV = (u8) ((state->cfg->clock_khz + 9999) / 10000);
385 break;
386 case BAND_FM:
387 REFDIV = (u8) ((state->cfg->clock_khz) / 1000);
388 break;
389 default:
390 REFDIV = (u8) (state->cfg->clock_khz / 10000);
391 break;
392 }
393 FREF = state->cfg->clock_khz / REFDIV;
394
395
396
397 switch (state->revision) {
398 case DIB0070S_P1A:
399 FBDiv = (VCOF_kHz / state->current_tune_table_index->presc / FREF);
400 Rest = (VCOF_kHz / state->current_tune_table_index->presc) - FBDiv * FREF;
401 break;
402
403 case DIB0070_P1G:
404 case DIB0070_P1F:
405 default:
406 FBDiv = (freq / (FREF / 2));
407 Rest = 2 * freq - FBDiv * FREF;
408 break;
409 }
410
411 if (Rest < LPF)
412 Rest = 0;
413 else if (Rest < 2 * LPF)
414 Rest = 2 * LPF;
415 else if (Rest > (FREF - LPF)) {
416 Rest = 0;
417 FBDiv += 1;
418 } else if (Rest > (FREF - 2 * LPF))
419 Rest = FREF - 2 * LPF;
420 Rest = (Rest * 6528) / (FREF / 10);
421
422 Den = 1;
423 if (Rest > 0) {
424 state->lo4 |= (1 << 14) | (1 << 12);
425 Den = 255;
426 }
427
428
429 dib0070_write_reg(state, 0x11, (u16)FBDiv);
430 dib0070_write_reg(state, 0x12, (Den << 8) | REFDIV);
431 dib0070_write_reg(state, 0x13, (u16) Rest);
432
433 if (state->revision == DIB0070S_P1A) {
434
435 if (band == BAND_SBAND) {
436 dib0070_set_ctrl_lo5(fe, 2, 4, 3, 0);
437 dib0070_write_reg(state, 0x1d, 0xFFFF);
438 } else
439 dib0070_set_ctrl_lo5(fe, 5, 4, 3, 1);
440 }
441
442 dib0070_write_reg(state, 0x20,
443 0x0040 | 0x0020 | 0x0010 | 0x0008 | 0x0002 | 0x0001 | state->current_tune_table_index->tuner_enable);
444
fb11cbd1
MCC
445 dprintk("REFDIV: %hd, FREF: %d\n", REFDIV, FREF);
446 dprintk("FBDIV: %d, Rest: %d\n", FBDiv, Rest);
447 dprintk("Num: %hd, Den: %hd, SD: %hd\n", (u16) Rest, Den, (state->lo4 >> 12) & 0x1);
448 dprintk("HFDIV code: %hd\n", state->current_tune_table_index->hfdiv);
449 dprintk("VCO = %hd\n", state->current_tune_table_index->vco_band);
450 dprintk("VCOF: ((%hd*%d) << 1))\n", state->current_tune_table_index->vco_multi, freq);
f3f8ef22
MCC
451
452 *tune_state = CT_TUNER_STEP_0;
453 } else { /* we are already tuned to this frequency - the configuration is correct */
454 ret = 50; /* wakeup time */
455 *tune_state = CT_TUNER_STEP_5;
9c783036 456 }
f3f8ef22 457 } else if ((*tune_state > CT_TUNER_START) && (*tune_state < CT_TUNER_STEP_4)) {
9c783036 458
f3f8ef22 459 ret = dib0070_captrim(state, tune_state);
2a6a30e0 460
f3f8ef22
MCC
461 } else if (*tune_state == CT_TUNER_STEP_4) {
462 const struct dib0070_wbd_gain_cfg *tmp = state->cfg->wbd_gain;
463 if (tmp != NULL) {
464 while (freq/1000 > tmp->freq) /* find the right one */
465 tmp++;
2a6a30e0 466 dib0070_write_reg(state, 0x0f,
f3f8ef22
MCC
467 (0 << 15) | (1 << 14) | (3 << 12)
468 | (tmp->wbd_gain_val << 9) | (0 << 8) | (1 << 7)
469 | (state->current_tune_table_index->wbdmux << 0));
470 state->wbd_gain_current = tmp->wbd_gain_val;
471 } else {
472 dib0070_write_reg(state, 0x0f,
473 (0 << 15) | (1 << 14) | (3 << 12)
474 | (6 << 9) | (0 << 8) | (1 << 7)
475 | (state->current_tune_table_index->wbdmux << 0));
476 state->wbd_gain_current = 6;
477 }
01373a5c 478
f3f8ef22 479 dib0070_write_reg(state, 0x06, 0x3fff);
2a6a30e0
PB
480 dib0070_write_reg(state, 0x07,
481 (state->current_tune_table_index->switch_trim << 11) | (7 << 8) | (state->lna_match->lna_band << 3) | (3 << 0));
f3f8ef22
MCC
482 dib0070_write_reg(state, 0x08, (state->lna_match->lna_band << 10) | (3 << 7) | (127));
483 dib0070_write_reg(state, 0x0d, 0x0d80);
7e5ce651 484
7e5ce651 485
f3f8ef22
MCC
486 dib0070_write_reg(state, 0x18, 0x07ff);
487 dib0070_write_reg(state, 0x17, 0x0033);
03245a5e
OG
488
489
f3f8ef22
MCC
490 *tune_state = CT_TUNER_STEP_5;
491 } else if (*tune_state == CT_TUNER_STEP_5) {
492 dib0070_set_bandwidth(fe);
493 *tune_state = CT_TUNER_STOP;
494 } else {
495 ret = FE_CALLBACK_TIME_NEVER; /* tuner finished, time to call again infinite */
496 }
497 return ret;
7e5ce651
PB
498}
499
03245a5e 500
14d24d14 501static int dib0070_tune(struct dvb_frontend *fe)
7e5ce651 502{
f3f8ef22
MCC
503 struct dib0070_state *state = fe->tuner_priv;
504 uint32_t ret;
7e5ce651 505
f3f8ef22 506 state->tune_state = CT_TUNER_START;
7e5ce651 507
f3f8ef22
MCC
508 do {
509 ret = dib0070_tune_digital(fe);
510 if (ret != FE_CALLBACK_TIME_NEVER)
511 msleep(ret/10);
512 else
513 break;
514 } while (state->tune_state != CT_TUNER_STOP);
7e5ce651 515
f3f8ef22 516 return 0;
01373a5c
PB
517}
518
519static int dib0070_wakeup(struct dvb_frontend *fe)
520{
2a6a30e0
PB
521 struct dib0070_state *state = fe->tuner_priv;
522 if (state->cfg->sleep)
523 state->cfg->sleep(fe, 0);
01373a5c
PB
524 return 0;
525}
526
527static int dib0070_sleep(struct dvb_frontend *fe)
528{
2a6a30e0
PB
529 struct dib0070_state *state = fe->tuner_priv;
530 if (state->cfg->sleep)
531 state->cfg->sleep(fe, 1);
01373a5c
PB
532 return 0;
533}
534
03245a5e
OG
535u8 dib0070_get_rf_output(struct dvb_frontend *fe)
536{
537 struct dib0070_state *state = fe->tuner_priv;
538 return (dib0070_read_reg(state, 0x07) >> 11) & 0x3;
539}
03245a5e 540EXPORT_SYMBOL(dib0070_get_rf_output);
9c783036 541
03245a5e
OG
542int dib0070_set_rf_output(struct dvb_frontend *fe, u8 no)
543{
544 struct dib0070_state *state = fe->tuner_priv;
545 u16 rxrf2 = dib0070_read_reg(state, 0x07) & 0xfe7ff;
9c783036
OG
546 if (no > 3)
547 no = 3;
548 if (no < 1)
549 no = 1;
03245a5e
OG
550 return dib0070_write_reg(state, 0x07, rxrf2 | (no << 11));
551}
03245a5e 552EXPORT_SYMBOL(dib0070_set_rf_output);
9c783036 553
03245a5e
OG
554static const u16 dib0070_p1f_defaults[] =
555
556{
01373a5c 557 7, 0x02,
03245a5e
OG
558 0x0008,
559 0x0000,
560 0x0000,
561 0x0000,
562 0x0000,
563 0x0002,
564 0x0100,
01373a5c
PB
565
566 3, 0x0d,
03245a5e
OG
567 0x0d80,
568 0x0001,
569 0x0000,
01373a5c
PB
570
571 4, 0x11,
03245a5e
OG
572 0x0000,
573 0x0103,
574 0x0000,
575 0x0000,
01373a5c
PB
576
577 3, 0x16,
03245a5e
OG
578 0x0004 | 0x0040,
579 0x0030,
580 0x07ff,
01373a5c
PB
581
582 6, 0x1b,
03245a5e
OG
583 0x4112,
584 0xff00,
585 0xc07f,
586 0x0000,
587 0x0180,
588 0x4000 | 0x0800 | 0x0040 | 0x0020 | 0x0010 | 0x0008 | 0x0002 | 0x0001,
01373a5c
PB
589
590 0,
591};
592
7e5ce651 593static u16 dib0070_read_wbd_offset(struct dib0070_state *state, u8 gain)
01373a5c 594{
f3f8ef22
MCC
595 u16 tuner_en = dib0070_read_reg(state, 0x20);
596 u16 offset;
597
598 dib0070_write_reg(state, 0x18, 0x07ff);
599 dib0070_write_reg(state, 0x20, 0x0800 | 0x4000 | 0x0040 | 0x0020 | 0x0010 | 0x0008 | 0x0002 | 0x0001);
600 dib0070_write_reg(state, 0x0f, (1 << 14) | (2 << 12) | (gain << 9) | (1 << 8) | (1 << 7) | (0 << 0));
601 msleep(9);
602 offset = dib0070_read_reg(state, 0x19);
603 dib0070_write_reg(state, 0x20, tuner_en);
604 return offset;
7e5ce651 605}
3cb2c39d 606
7e5ce651
PB
607static void dib0070_wbd_offset_calibration(struct dib0070_state *state)
608{
f3f8ef22
MCC
609 u8 gain;
610 for (gain = 6; gain < 8; gain++) {
611 state->wbd_offset_3_3[gain - 6] = ((dib0070_read_wbd_offset(state, gain) * 8 * 18 / 33 + 1) / 2);
fb11cbd1 612 dprintk("Gain: %d, WBDOffset (3.3V) = %hd\n", gain, state->wbd_offset_3_3[gain-6]);
f3f8ef22 613 }
01373a5c
PB
614}
615
616u16 dib0070_wbd_offset(struct dvb_frontend *fe)
617{
f3f8ef22
MCC
618 struct dib0070_state *state = fe->tuner_priv;
619 const struct dib0070_wbd_gain_cfg *tmp = state->cfg->wbd_gain;
620 u32 freq = fe->dtv_property_cache.frequency/1000;
621
622 if (tmp != NULL) {
623 while (freq/1000 > tmp->freq) /* find the right one */
624 tmp++;
625 state->wbd_gain_current = tmp->wbd_gain_val;
2a6a30e0 626 } else
f3f8ef22 627 state->wbd_gain_current = 6;
2a6a30e0 628
f3f8ef22 629 return state->wbd_offset_3_3[state->wbd_gain_current - 6];
01373a5c 630}
01373a5c 631EXPORT_SYMBOL(dib0070_wbd_offset);
2a6a30e0 632
01373a5c 633#define pgm_read_word(w) (*w)
7e5ce651 634static int dib0070_reset(struct dvb_frontend *fe)
01373a5c 635{
f3f8ef22 636 struct dib0070_state *state = fe->tuner_priv;
01373a5c
PB
637 u16 l, r, *n;
638
639 HARD_RESET(state);
640
03245a5e 641
01373a5c
PB
642#ifndef FORCE_SBAND_TUNER
643 if ((dib0070_read_reg(state, 0x22) >> 9) & 0x1)
644 state->revision = (dib0070_read_reg(state, 0x1f) >> 8) & 0xff;
645 else
7e5ce651
PB
646#else
647#warning forcing SBAND
01373a5c 648#endif
f3f8ef22 649 state->revision = DIB0070S_P1A;
01373a5c
PB
650
651 /* P1F or not */
fb11cbd1 652 dprintk("Revision: %x\n", state->revision);
01373a5c
PB
653
654 if (state->revision == DIB0070_P1D) {
fb11cbd1 655 dprintk("Error: this driver is not to be used meant for P1D or earlier\n");
01373a5c
PB
656 return -EINVAL;
657 }
658
659 n = (u16 *) dib0070_p1f_defaults;
660 l = pgm_read_word(n++);
661 while (l) {
662 r = pgm_read_word(n++);
663 do {
03245a5e 664 dib0070_write_reg(state, (u8)r, pgm_read_word(n++));
01373a5c
PB
665 r++;
666 } while (--l);
667 l = pgm_read_word(n++);
668 }
669
670 if (state->cfg->force_crystal_mode != 0)
671 r = state->cfg->force_crystal_mode;
672 else if (state->cfg->clock_khz >= 24000)
673 r = 1;
674 else
675 r = 2;
676
03245a5e 677
01373a5c
PB
678 r |= state->cfg->osc_buffer_state << 3;
679
680 dib0070_write_reg(state, 0x10, r);
7e5ce651 681 dib0070_write_reg(state, 0x1f, (1 << 8) | ((state->cfg->clock_pad_drive & 0xf) << 5));
01373a5c
PB
682
683 if (state->cfg->invert_iq) {
684 r = dib0070_read_reg(state, 0x02) & 0xffdf;
685 dib0070_write_reg(state, 0x02, r | (1 << 5));
686 }
687
f3f8ef22
MCC
688 if (state->revision == DIB0070S_P1A)
689 dib0070_set_ctrl_lo5(fe, 2, 4, 3, 0);
690 else
691 dib0070_set_ctrl_lo5(fe, 5, 4, state->cfg->charge_pump,
692 state->cfg->enable_third_order_filter);
01373a5c
PB
693
694 dib0070_write_reg(state, 0x01, (54 << 9) | 0xc8);
7e5ce651 695
f3f8ef22 696 dib0070_wbd_offset_calibration(state);
7e5ce651 697
f3f8ef22 698 return 0;
03245a5e
OG
699}
700
701static int dib0070_get_frequency(struct dvb_frontend *fe, u32 *frequency)
702{
f3f8ef22 703 struct dib0070_state *state = fe->tuner_priv;
03245a5e 704
f3f8ef22
MCC
705 *frequency = 1000 * state->current_rf;
706 return 0;
01373a5c
PB
707}
708
f2709c20
MCC
709static void dib0070_release(struct dvb_frontend *fe)
710{
711 kfree(fe->tuner_priv);
712 fe->tuner_priv = NULL;
713}
714
7e5ce651 715static const struct dvb_tuner_ops dib0070_ops = {
01373a5c 716 .info = {
a3f90c75
MCC
717 .name = "DiBcom DiB0070",
718 .frequency_min_hz = 45 * MHz,
719 .frequency_max_hz = 860 * MHz,
720 .frequency_step_hz = 1 * kHz,
03245a5e 721 },
f2709c20 722 .release = dib0070_release,
03245a5e
OG
723
724 .init = dib0070_wakeup,
725 .sleep = dib0070_sleep,
726 .set_params = dib0070_tune,
727
728 .get_frequency = dib0070_get_frequency,
2a6a30e0 729// .get_bandwidth = dib0070_get_bandwidth
01373a5c
PB
730};
731
9c783036 732struct dvb_frontend *dib0070_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct dib0070_config *cfg)
01373a5c
PB
733{
734 struct dib0070_state *state = kzalloc(sizeof(struct dib0070_state), GFP_KERNEL);
735 if (state == NULL)
736 return NULL;
737
738 state->cfg = cfg;
739 state->i2c = i2c;
03245a5e 740 state->fe = fe;
79fcce32 741 mutex_init(&state->i2c_buffer_lock);
01373a5c
PB
742 fe->tuner_priv = state;
743
7e5ce651 744 if (dib0070_reset(fe) != 0)
01373a5c
PB
745 goto free_mem;
746
fb11cbd1 747 pr_info("DiB0070: successfully identified\n");
01373a5c
PB
748 memcpy(&fe->ops.tuner_ops, &dib0070_ops, sizeof(struct dvb_tuner_ops));
749
750 fe->tuner_priv = state;
751 return fe;
752
03245a5e 753free_mem:
01373a5c
PB
754 kfree(state);
755 fe->tuner_priv = NULL;
756 return NULL;
757}
758EXPORT_SYMBOL(dib0070_attach);
759
99e44da7 760MODULE_AUTHOR("Patrick Boettcher <patrick.boettcher@posteo.de>");
01373a5c
PB
761MODULE_DESCRIPTION("Driver for the DiBcom 0070 base-band RF Tuner");
762MODULE_LICENSE("GPL");