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