Add the rt linux 4.1.3-rt3 as base
[kvmfornfv.git] / kernel / 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/slab.h>
29 #include <linux/i2c.h>
30 #include <linux/mutex.h>
31
32 #include "dvb_frontend.h"
33
34 #include "dib0070.h"
35 #include "dibx000_common.h"
36
37 static int debug;
38 module_param(debug, int, 0644);
39 MODULE_PARM_DESC(debug, "turn on debugging (default: 0)");
40
41 #define dprintk(args...) do { \
42         if (debug) { \
43                 printk(KERN_DEBUG "DiB0070: "); \
44                 printk(args); \
45                 printk("\n"); \
46         } \
47 } while (0)
48
49 #define DIB0070_P1D  0x00
50 #define DIB0070_P1F  0x01
51 #define DIB0070_P1G  0x03
52 #define DIB0070S_P1A 0x02
53
54 struct 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;
60
61     enum frontend_tune_state tune_state;
62     u32 current_rf;
63
64     /* for the captrim binary search */
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
75     u8  wbd_gain_current;
76         u16 wbd_offset_3_3[2];
77
78         /* for the I2C transfer */
79         struct i2c_msg msg[2];
80         u8 i2c_write_buffer[3];
81         u8 i2c_read_buffer[2];
82         struct mutex i2c_buffer_lock;
83 };
84
85 static u16 dib0070_read_reg(struct dib0070_state *state, u8 reg)
86 {
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
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) {
107                 printk(KERN_WARNING "DiB0070 I2C read failed\n");
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;
115 }
116
117 static int dib0070_write_reg(struct dib0070_state *state, u8 reg, u16 val)
118 {
119         int ret;
120
121         if (mutex_lock_interruptible(&state->i2c_buffer_lock) < 0) {
122                 dprintk("could not acquire lock");
123                 return -EINVAL;
124         }
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) {
136                 printk(KERN_WARNING "DiB0070 I2C write failed\n");
137                 ret = -EREMOTEIO;
138         } else
139                 ret = 0;
140
141         mutex_unlock(&state->i2c_buffer_lock);
142         return ret;
143 }
144
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)
152
153 static int dib0070_set_bandwidth(struct dvb_frontend *fe)
154 {
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     }
179         return 0;
180 }
181
182 static int dib0070_captrim(struct dib0070_state *state, enum frontend_tune_state *tune_state)
183 {
184         int8_t step_sign;
185         u16 adc;
186         int ret = 0;
187
188         if (*tune_state == CT_TUNER_STEP_0) {
189
190                 dib0070_write_reg(state, 0x0f, 0xed10);
191                 dib0070_write_reg(state, 0x17,    0x0034);
192
193                 dib0070_write_reg(state, 0x18, 0x0032);
194                 state->step = state->captrim = state->fcaptrim = 64;
195                 state->adc_diff = 3000;
196                 ret = 20;
197
198         *tune_state = CT_TUNER_STEP_1;
199         } else if (*tune_state == CT_TUNER_STEP_1) {
200                 state->step /= 2;
201                 dib0070_write_reg(state, 0x14, state->lo4 | state->captrim);
202                 ret = 15;
203
204                 *tune_state = CT_TUNER_STEP_2;
205         } else if (*tune_state == CT_TUNER_STEP_2) {
206
207                 adc = dib0070_read_reg(state, 0x19);
208
209                 dprintk("CAPTRIM=%hd; ADC = %hd (ADC) & %dmV", state->captrim, adc, (u32) adc*(u32)1800/(u32)1024);
210
211                 if (adc >= 400) {
212                         adc -= 400;
213                         step_sign = -1;
214                 } else {
215                         adc = 400 - adc;
216                         step_sign = 1;
217                 }
218
219                 if (adc < state->adc_diff) {
220                         dprintk("CAPTRIM=%hd is closer to target (%hd/%hd)", state->captrim, adc, state->adc_diff);
221                         state->adc_diff = adc;
222                         state->fcaptrim = state->captrim;
223
224
225
226                 }
227                 state->captrim += (step_sign * state->step);
228
229                 if (state->step >= 1)
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) {
235                 dib0070_write_reg(state, 0x14, state->lo4 | state->fcaptrim);
236                 dib0070_write_reg(state, 0x18, 0x07ff);
237                 *tune_state = CT_TUNER_STEP_4;
238         }
239
240         return ret;
241 }
242
243 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)
244 {
245         struct dib0070_state *state = fe->tuner_priv;
246     u16 lo5 = (third_order_filt << 14) | (0 << 13) | (1 << 12) | (3 << 9) | (cp_current << 6) | (hf_div_trim << 3) | (vco_bias_trim << 0);
247         dprintk("CTRL_LO5: 0x%x", lo5);
248         return dib0070_write_reg(state, 0x15, lo5);
249 }
250
251 void dib0070_ctrl_agc_filter(struct dvb_frontend *fe, u8 open)
252 {
253         struct dib0070_state *state = fe->tuner_priv;
254
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);
260         if (state->cfg->vga_filter != 0) {
261                 dib0070_write_reg(state, 0x1a, state->cfg->vga_filter);
262                 dprintk("vga filter register is set to %x", state->cfg->vga_filter);
263         } else
264                 dib0070_write_reg(state, 0x1a, 0x0009);
265         }
266 }
267
268 EXPORT_SYMBOL(dib0070_ctrl_agc_filter);
269 struct dib0070_tuning {
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;
278 };
279
280 struct dib0070_lna_match {
281     u32 max_freq; /* for every frequency less than or equal to that field: this information is correct */
282     u8 lna_band;
283 };
284
285 static const struct dib0070_tuning dib0070s_tuning_table[] = {
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 */
293 };
294
295 static const struct dib0070_tuning dib0070_tuning_table[] = {
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 */
301     {     699999, 2, 0, 1,  4, 2, 2, 0x4000 | 0x0800 },
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 */
304 };
305
306 static const struct dib0070_lna_match dib0070_lna_flip_chip[] = {
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 },
319 };
320
321 static const struct dib0070_lna_match dib0070_lna[] = {
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 },
335 };
336
337 #define LPF     100
338 static int dib0070_tune_digital(struct dvb_frontend *fe)
339 {
340     struct dib0070_state *state = fe->tuner_priv;
341
342     const struct dib0070_tuning *tune;
343     const struct dib0070_lna_match *lna_match;
344
345     enum frontend_tune_state *tune_state = &state->tune_state;
346     int ret = 10; /* 1ms is the default delay most of the time */
347
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);
350
351 #ifdef CONFIG_SYS_ISDBT
352     if (state->fe->dtv_property_cache.delivery_system == SYS_ISDBT && state->fe->dtv_property_cache.isdbt_sb_mode == 1)
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))))
359                         freq += 850;
360 #endif
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) {
386         dprintk("Tuning for Band: %hd (%d kHz)", band, freq);
387         if (state->current_rf != freq) {
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;
472         } else { /* we are already tuned to this frequency - the configuration is correct  */
473                 ret = 50; /* wakeup time */
474                 *tune_state = CT_TUNER_STEP_5;
475         }
476     } else if ((*tune_state > CT_TUNER_START) && (*tune_state < CT_TUNER_STEP_4)) {
477
478         ret = dib0070_captrim(state, tune_state);
479
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) {
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;
490         } else {
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));
494             state->wbd_gain_current = 6;
495         }
496
497         dib0070_write_reg(state, 0x06, 0x3fff);
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));
500         dib0070_write_reg(state, 0x08, (state->lna_match->lna_band << 10) | (3 << 7) | (127));
501         dib0070_write_reg(state, 0x0d, 0x0d80);
502
503
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) {
510         dib0070_set_bandwidth(fe);
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;
516 }
517
518
519 static int dib0070_tune(struct dvb_frontend *fe)
520 {
521     struct dib0070_state *state = fe->tuner_priv;
522     uint32_t ret;
523
524     state->tune_state = CT_TUNER_START;
525
526     do {
527         ret = dib0070_tune_digital(fe);
528         if (ret != FE_CALLBACK_TIME_NEVER)
529                 msleep(ret/10);
530         else
531             break;
532     } while (state->tune_state != CT_TUNER_STOP);
533
534     return 0;
535 }
536
537 static int dib0070_wakeup(struct dvb_frontend *fe)
538 {
539         struct dib0070_state *state = fe->tuner_priv;
540         if (state->cfg->sleep)
541                 state->cfg->sleep(fe, 0);
542         return 0;
543 }
544
545 static int dib0070_sleep(struct dvb_frontend *fe)
546 {
547         struct dib0070_state *state = fe->tuner_priv;
548         if (state->cfg->sleep)
549                 state->cfg->sleep(fe, 1);
550         return 0;
551 }
552
553 u8 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 }
558 EXPORT_SYMBOL(dib0070_get_rf_output);
559
560 int 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;
564         if (no > 3)
565                 no = 3;
566         if (no < 1)
567                 no = 1;
568         return dib0070_write_reg(state, 0x07, rxrf2 | (no << 11));
569 }
570 EXPORT_SYMBOL(dib0070_set_rf_output);
571
572 static const u16 dib0070_p1f_defaults[] =
573
574 {
575         7, 0x02,
576                 0x0008,
577                 0x0000,
578                 0x0000,
579                 0x0000,
580                 0x0000,
581                 0x0002,
582                 0x0100,
583
584         3, 0x0d,
585                 0x0d80,
586                 0x0001,
587                 0x0000,
588
589         4, 0x11,
590                 0x0000,
591                 0x0103,
592                 0x0000,
593                 0x0000,
594
595         3, 0x16,
596                 0x0004 | 0x0040,
597                 0x0030,
598                 0x07ff,
599
600         6, 0x1b,
601                 0x4112,
602                 0xff00,
603                 0xc07f,
604                 0x0000,
605                 0x0180,
606                 0x4000 | 0x0800 | 0x0040 | 0x0020 | 0x0010 | 0x0008 | 0x0002 | 0x0001,
607
608         0,
609 };
610
611 static u16 dib0070_read_wbd_offset(struct dib0070_state *state, u8 gain)
612 {
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;
623 }
624
625 static void dib0070_wbd_offset_calibration(struct dib0070_state *state)
626 {
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);
630         dprintk("Gain: %d, WBDOffset (3.3V) = %hd", gain, state->wbd_offset_3_3[gain-6]);
631     }
632 }
633
634 u16 dib0070_wbd_offset(struct dvb_frontend *fe)
635 {
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;
644         } else
645         state->wbd_gain_current = 6;
646
647     return state->wbd_offset_3_3[state->wbd_gain_current - 6];
648 }
649 EXPORT_SYMBOL(dib0070_wbd_offset);
650
651 #define pgm_read_word(w) (*w)
652 static int dib0070_reset(struct dvb_frontend *fe)
653 {
654     struct dib0070_state *state = fe->tuner_priv;
655         u16 l, r, *n;
656
657         HARD_RESET(state);
658
659
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
664 #else
665 #warning forcing SBAND
666 #endif
667                 state->revision = DIB0070S_P1A;
668
669         /* P1F or not */
670         dprintk("Revision: %x", state->revision);
671
672         if (state->revision == DIB0070_P1D) {
673                 dprintk("Error: this driver is not to be used meant for P1D or earlier");
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 {
682                         dib0070_write_reg(state, (u8)r, pgm_read_word(n++));
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
695
696         r |= state->cfg->osc_buffer_state << 3;
697
698         dib0070_write_reg(state, 0x10, r);
699         dib0070_write_reg(state, 0x1f, (1 << 8) | ((state->cfg->clock_pad_drive & 0xf) << 5));
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
706     if (state->revision == DIB0070S_P1A)
707         dib0070_set_ctrl_lo5(fe, 2, 4, 3, 0);
708     else
709                 dib0070_set_ctrl_lo5(fe, 5, 4, state->cfg->charge_pump, state->cfg->enable_third_order_filter);
710
711         dib0070_write_reg(state, 0x01, (54 << 9) | 0xc8);
712
713     dib0070_wbd_offset_calibration(state);
714
715     return 0;
716 }
717
718 static 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;
724 }
725
726 static int dib0070_release(struct dvb_frontend *fe)
727 {
728         kfree(fe->tuner_priv);
729         fe->tuner_priv = NULL;
730         return 0;
731 }
732
733 static const struct dvb_tuner_ops dib0070_ops = {
734         .info = {
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,
747 //      .get_bandwidth = dib0070_get_bandwidth
748 };
749
750 struct dvb_frontend *dib0070_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct dib0070_config *cfg)
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;
758         state->fe  = fe;
759         mutex_init(&state->i2c_buffer_lock);
760         fe->tuner_priv = state;
761
762         if (dib0070_reset(fe) != 0)
763                 goto free_mem;
764
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
771 free_mem:
772         kfree(state);
773         fe->tuner_priv = NULL;
774         return NULL;
775 }
776 EXPORT_SYMBOL(dib0070_attach);
777
778 MODULE_AUTHOR("Patrick Boettcher <pboettcher@dibcom.fr>");
779 MODULE_DESCRIPTION("Driver for the DiBcom 0070 base-band RF Tuner");
780 MODULE_LICENSE("GPL");