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