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