2 * Linux-DVB Driver for DiBcom's DiB0070 base-band RF Tuner.
4 * Copyright (C) 2005-7 DiBcom (http://www.dibcom.fr/)
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License as
8 * published by the Free Software Foundation, version 2.
10 #include <linux/kernel.h>
11 #include <linux/i2c.h>
13 #include "dvb_frontend.h"
16 #include "dibx000_common.h"
19 module_param(debug
, int, 0644);
20 MODULE_PARM_DESC(debug
, "turn on debugging (default: 0)");
22 #define dprintk(args...) do { if (debug) { printk(KERN_DEBUG "DiB0070: "); printk(args); printk("\n"); } } while (0)
24 #define DIB0070_P1D 0x00
25 #define DIB0070_P1F 0x01
26 #define DIB0070_P1G 0x03
27 #define DIB0070S_P1A 0x02
29 struct dib0070_state
{
30 struct i2c_adapter
*i2c
;
31 struct dvb_frontend
*fe
;
32 const struct dib0070_config
*cfg
;
37 static uint16_t dib0070_read_reg(struct dib0070_state
*state
, u8 reg
)
40 struct i2c_msg msg
[2] = {
41 { .addr
= state
->cfg
->i2c_address
, .flags
= 0, .buf
= ®
, .len
= 1 },
42 { .addr
= state
->cfg
->i2c_address
, .flags
= I2C_M_RD
, .buf
= b
, .len
= 2 },
44 if (i2c_transfer(state
->i2c
, msg
, 2) != 2) {
45 printk(KERN_WARNING
"DiB0070 I2C read failed\n");
48 return (b
[0] << 8) | b
[1];
51 static int dib0070_write_reg(struct dib0070_state
*state
, u8 reg
, u16 val
)
53 u8 b
[3] = { reg
, val
>> 8, val
& 0xff };
54 struct i2c_msg msg
= { .addr
= state
->cfg
->i2c_address
, .flags
= 0, .buf
= b
, .len
= 3 };
55 if (i2c_transfer(state
->i2c
, &msg
, 1) != 1) {
56 printk(KERN_WARNING
"DiB0070 I2C write failed\n");
62 #define HARD_RESET(state) do { if (state->cfg->reset) { state->cfg->reset(state->fe,1); msleep(10); state->cfg->reset(state->fe,0); msleep(10); } } while (0)
64 static int dib0070_set_bandwidth(struct dvb_frontend
*fe
, struct dvb_frontend_parameters
*ch
)
66 struct dib0070_state
*st
= fe
->tuner_priv
;
68 tmp
= dib0070_read_reg(st
, 0x02) & 0x3fff;
70 switch(BANDWIDTH_TO_KHZ(ch
->u
.ofdm
.bandwidth
)) {
85 dib0070_write_reg(st
, 0x02, tmp
);
89 static void dib0070_captrim(struct dib0070_state
*st
, u16 LO4
)
91 int8_t captrim
, fcaptrim
, step_sign
, step
;
92 u16 adc
, adc_diff
= 3000;
96 dib0070_write_reg(st
, 0x0f, 0xed10);
97 dib0070_write_reg(st
, 0x17, 0x0034);
99 dib0070_write_reg(st
, 0x18, 0x0032);
102 step
= captrim
= fcaptrim
= 64;
106 dib0070_write_reg(st
, 0x14, LO4
| captrim
);
108 adc
= dib0070_read_reg(st
, 0x19);
110 dprintk( "CAPTRIM=%hd; ADC = %hd (ADC) & %dmV", captrim
, adc
, (u32
) adc
*(u32
)1800/(u32
)1024);
120 if (adc
< adc_diff
) {
121 dprintk( "CAPTRIM=%hd is closer to target (%hd/%hd)", captrim
, adc
, adc_diff
);
128 captrim
+= (step_sign
* step
);
131 dib0070_write_reg(st
, 0x14, LO4
| fcaptrim
);
132 dib0070_write_reg(st
, 0x18, 0x07ff);
135 #define LPF 100 // define for the loop filter 100kHz by default 16-07-06
136 #define LO4_SET_VCO_HFDIV(l, v, h) l |= ((v) << 11) | ((h) << 7)
137 #define LO4_SET_SD(l, s) l |= ((s) << 14) | ((s) << 12)
138 #define LO4_SET_CTRIM(l, c) l |= (c) << 10
139 static int dib0070_tune_digital(struct dvb_frontend
*fe
, struct dvb_frontend_parameters
*ch
)
141 struct dib0070_state
*st
= fe
->tuner_priv
;
142 u32 freq
= ch
->frequency
/1000 + (BAND_OF_FREQUENCY(ch
->frequency
/1000) == BAND_VHF
? st
->cfg
->freq_offset_khz_vhf
: st
->cfg
->freq_offset_khz_uhf
);
144 u8 band
= BAND_OF_FREQUENCY(freq
), c
;
146 /*******************VCO***********************************/
149 u8 REFDIV
, PRESC
= 2;
150 u32 FBDiv
, Rest
, FREF
, VCOF_kHz
;
152 /*******************FrontEnd******************************/
155 dprintk( "Tuning for Band: %hd (%d kHz)", band
, freq
);
158 dib0070_write_reg(st
, 0x17, 0x30);
160 dib0070_set_bandwidth(fe
, ch
); /* c is used as HF */
161 switch (st
->revision
) {
165 LO4_SET_VCO_HFDIV(lo4
, 1, 1);
169 LO4_SET_VCO_HFDIV(lo4
, 0, 0);
170 LO4_SET_CTRIM(lo4
, 1);
176 LO4_SET_VCO_HFDIV(lo4
, 1, 3);
178 } else if (freq
< 680000) {
179 LO4_SET_VCO_HFDIV(lo4
, 0, 2);
182 LO4_SET_VCO_HFDIV(lo4
, 1, 2);
193 LO4_SET_VCO_HFDIV(lo4
, 0, 7);
197 LO4_SET_VCO_HFDIV(lo4
, 1, 0);
202 LO4_SET_VCO_HFDIV(lo4
, 0, 3);
204 } else if (freq
< 190000) {
205 LO4_SET_VCO_HFDIV(lo4
, 1, 3);
208 LO4_SET_VCO_HFDIV(lo4
, 0, 6);
216 LO4_SET_VCO_HFDIV(lo4
, 1, 5);
218 } else if (freq
< 700000) {
219 LO4_SET_VCO_HFDIV(lo4
, 0, 1);
222 LO4_SET_VCO_HFDIV(lo4
, 1, 1);
230 dprintk( "HFDIV code: %hd", (lo4
>> 7) & 0xf);
231 dprintk( "VCO = %hd", (lo4
>> 11) & 0x3);
234 VCOF_kHz
= (c
* freq
) * 2;
235 dprintk( "VCOF in kHz: %d ((%hd*%d) << 1))",VCOF_kHz
, c
, freq
);
239 REFDIV
= (u8
) ((st
->cfg
->clock_khz
+ 9999) / 10000);
242 REFDIV
= (u8
) ((st
->cfg
->clock_khz
) / 1000);
245 REFDIV
= (u8
) ( st
->cfg
->clock_khz
/ 10000);
248 FREF
= st
->cfg
->clock_khz
/ REFDIV
;
250 dprintk( "REFDIV: %hd, FREF: %d", REFDIV
, FREF
);
254 switch (st
->revision
) {
256 FBDiv
= (VCOF_kHz
/ PRESC
/ FREF
);
257 Rest
= (VCOF_kHz
/ PRESC
) - FBDiv
* FREF
;
263 FBDiv
= (freq
/ (FREF
/ 2));
264 Rest
= 2 * freq
- FBDiv
* FREF
;
269 if (Rest
< LPF
) Rest
= 0;
270 else if (Rest
< 2 * LPF
) Rest
= 2 * LPF
;
271 else if (Rest
> (FREF
- LPF
)) { Rest
= 0 ; FBDiv
+= 1; }
272 else if (Rest
> (FREF
- 2 * LPF
)) Rest
= FREF
- 2 * LPF
;
273 Rest
= (Rest
* 6528) / (FREF
/ 10);
274 dprintk( "FBDIV: %d, Rest: %d", FBDiv
, Rest
);
284 dprintk( "Num: %hd, Den: %hd, SD: %hd",Num
, Den
, (lo4
>> 12) & 0x1);
288 dib0070_write_reg(st
, 0x11, (u16
)FBDiv
);
291 dib0070_write_reg(st
, 0x12, (Den
<< 8) | REFDIV
);
294 dib0070_write_reg(st
, 0x13, Num
);
297 value
= 0x0040 | 0x0020 | 0x0010 | 0x0008 | 0x0002 | 0x0001;
300 case BAND_UHF
: value
|= 0x4000 | 0x0800; break;
301 case BAND_LBAND
: value
|= 0x2000 | 0x0400; break;
302 default: value
|= 0x8000 | 0x1000; break;
304 dib0070_write_reg(st
, 0x20, value
);
306 dib0070_captrim(st
, lo4
);
307 if (st
->revision
== DIB0070S_P1A
) {
308 if (band
== BAND_SBAND
)
309 dib0070_write_reg(st
, 0x15, 0x16e2);
311 dib0070_write_reg(st
, 0x15, 0x56e5);
317 case BAND_UHF
: value
= 0x7c82; break;
318 case BAND_LBAND
: value
= 0x7c84; break;
319 default: value
= 0x7c81; break;
321 dib0070_write_reg(st
, 0x0f, value
);
322 dib0070_write_reg(st
, 0x06, 0x3fff);
325 /* c == TUNE, value = SWITCH */
334 if (freq
<= 180000) c
= 0;
335 else if (freq
<= 188200) c
= 1;
336 else if (freq
<= 196400) c
= 2;
342 if (freq
<= 1500000) c
= 0;
343 else if (freq
<= 1600000) c
= 1;
349 dib0070_write_reg(st
, 0x1d,0xFFFF);
354 if (st
->cfg
->flip_chip
) {
355 if (freq
<= 550000) c
= 0;
356 else if (freq
<= 590000) c
= 1;
357 else if (freq
<= 666000) c
= 3;
360 if (freq
<= 550000) c
= 2;
361 else if (freq
<= 650000) c
= 3;
362 else if (freq
<= 750000) c
= 5;
363 else if (freq
<= 850000) c
= 6;
370 /* default: LNA_MATCH=7, BIAS=3 */
371 dib0070_write_reg(st
, 0x07, (value
<< 11) | (7 << 8) | (c
<< 3) | (3 << 0));
372 dib0070_write_reg(st
, 0x08, (c
<< 10) | (3 << 7) | (127));
373 dib0070_write_reg(st
, 0x0d, 0x0d80);
376 dib0070_write_reg(st
, 0x18, 0x07ff);
377 dib0070_write_reg(st
, 0x17, 0x0033);
382 static int dib0070_wakeup(struct dvb_frontend
*fe
)
384 struct dib0070_state
*st
= fe
->tuner_priv
;
386 st
->cfg
->sleep(fe
, 0);
390 static int dib0070_sleep(struct dvb_frontend
*fe
)
392 struct dib0070_state
*st
= fe
->tuner_priv
;
394 st
->cfg
->sleep(fe
, 1);
398 static u16 dib0070_p1f_defaults
[] =
432 0x4000 | 0x0800 | 0x0040 | 0x0020 | 0x0010 | 0x0008 | 0x0002 | 0x0001,
437 static void dib0070_wbd_calibration(struct dvb_frontend
*fe
)
440 struct dib0070_state
*state
= fe
->tuner_priv
;
442 if (state
->cfg
->sleep
)
443 state
->cfg
->sleep(fe
, 0);
445 dib0070_write_reg(state
, 0x0f, 0x6d81);
446 dib0070_write_reg(state
, 0x20, 0x0040 | 0x0020 | 0x0010 | 0x0008 | 0x0002 | 0x0001);
448 wbd_offs
= dib0070_read_reg(state
, 0x19);
449 dib0070_write_reg(state
, 0x20, 0);
450 state
->wbd_ff_offset
= ((wbd_offs
* 8 * 18 / 33 + 1) / 2);
451 dprintk( "WBDStart = %d (Vargen) - FF = %hd", (u32
) wbd_offs
* 1800/1024, state
->wbd_ff_offset
);
453 if (state
->cfg
->sleep
)
454 state
->cfg
->sleep(fe
, 1);
458 u16
dib0070_wbd_offset(struct dvb_frontend
*fe
)
460 struct dib0070_state
*st
= fe
->tuner_priv
;
461 return st
->wbd_ff_offset
;
464 EXPORT_SYMBOL(dib0070_wbd_offset
);
465 static int dib0070_set_ctrl_lo5(struct dvb_frontend
*fe
, u8 vco_bias_trim
, u8 hf_div_trim
, u8 cp_current
, u8 third_order_filt
)
467 struct dib0070_state
*state
= fe
->tuner_priv
;
468 u16 lo5
= (third_order_filt
<< 14) | (0 << 13) | (1 << 12) | (3 << 9) | (cp_current
<< 6) | (hf_div_trim
<< 3) | (vco_bias_trim
<< 0);
469 dprintk( "CTRL_LO5: 0x%x", lo5
);
470 return dib0070_write_reg(state
, 0x15, lo5
);
473 #define pgm_read_word(w) (*w)
474 static int dib0070_reset(struct dib0070_state
*state
)
481 #ifndef FORCE_SBAND_TUNER
482 if ((dib0070_read_reg(state
, 0x22) >> 9) & 0x1)
483 state
->revision
= (dib0070_read_reg(state
, 0x1f) >> 8) & 0xff;
486 state
->revision
= DIB0070S_P1A
;
489 dprintk( "Revision: %x", state
->revision
);
491 if (state
->revision
== DIB0070_P1D
) {
492 dprintk( "Error: this driver is not to be used meant for P1D or earlier");
496 n
= (u16
*) dib0070_p1f_defaults
;
497 l
= pgm_read_word(n
++);
499 r
= pgm_read_word(n
++);
501 dib0070_write_reg(state
, (u8
)r
, pgm_read_word(n
++));
504 l
= pgm_read_word(n
++);
507 if (state
->cfg
->force_crystal_mode
!= 0)
508 r
= state
->cfg
->force_crystal_mode
;
509 else if (state
->cfg
->clock_khz
>= 24000)
514 r
|= state
->cfg
->osc_buffer_state
<< 3;
516 dib0070_write_reg(state
, 0x10, r
);
517 dib0070_write_reg(state
, 0x1f, (1 << 8) | ((state
->cfg
->clock_pad_drive
& 0xf) << 4));
519 if (state
->cfg
->invert_iq
) {
520 r
= dib0070_read_reg(state
, 0x02) & 0xffdf;
521 dib0070_write_reg(state
, 0x02, r
| (1 << 5));
525 if (state
->revision
== DIB0070S_P1A
)
526 dib0070_set_ctrl_lo5(state
->fe
, 4, 7, 3, 1);
528 dib0070_set_ctrl_lo5(state
->fe
, 4, 4, 2, 0);
530 dib0070_write_reg(state
, 0x01, (54 << 9) | 0xc8);
535 static int dib0070_release(struct dvb_frontend
*fe
)
537 kfree(fe
->tuner_priv
);
538 fe
->tuner_priv
= NULL
;
542 static struct dvb_tuner_ops dib0070_ops
= {
544 .name
= "DiBcom DiB0070",
545 .frequency_min
= 45000000,
546 .frequency_max
= 860000000,
547 .frequency_step
= 1000,
549 .release
= dib0070_release
,
551 .init
= dib0070_wakeup
,
552 .sleep
= dib0070_sleep
,
553 .set_params
= dib0070_tune_digital
,
554 // .get_frequency = dib0070_get_frequency,
555 // .get_bandwidth = dib0070_get_bandwidth
558 struct dvb_frontend
* dib0070_attach(struct dvb_frontend
*fe
, struct i2c_adapter
*i2c
, struct dib0070_config
*cfg
)
560 struct dib0070_state
*state
= kzalloc(sizeof(struct dib0070_state
), GFP_KERNEL
);
567 fe
->tuner_priv
= state
;
569 if (dib0070_reset(state
) != 0)
572 dib0070_wbd_calibration(fe
);
574 printk(KERN_INFO
"DiB0070: successfully identified\n");
575 memcpy(&fe
->ops
.tuner_ops
, &dib0070_ops
, sizeof(struct dvb_tuner_ops
));
577 fe
->tuner_priv
= state
;
582 fe
->tuner_priv
= NULL
;
585 EXPORT_SYMBOL(dib0070_attach
);
587 MODULE_AUTHOR("Patrick Boettcher <pboettcher@dibcom.fr>");
588 MODULE_DESCRIPTION("Driver for the DiBcom 0070 base-band RF Tuner");
589 MODULE_LICENSE("GPL");