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