Merge branch 'usb-next' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb
[linux-btrfs-devel.git] / drivers / media / dvb / frontends / dib0070.c
blob1d47d4da7d4c4222373e8e89f55cd4fd1cd36e5e
1 /*
2 * Linux-DVB Driver for DiBcom's DiB0070 base-band RF Tuner.
4 * Copyright (C) 2005-9 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; either version 2 of the
9 * License, or (at your option) any later version.
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
15 * GNU General Public License for more details.
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.
22 * This code is more or less generated from another driver, please
23 * excuse some codingstyle oddities.
27 #include <linux/kernel.h>
28 #include <linux/slab.h>
29 #include <linux/i2c.h>
31 #include "dvb_frontend.h"
33 #include "dib0070.h"
34 #include "dibx000_common.h"
36 static int debug;
37 module_param(debug, int, 0644);
38 MODULE_PARM_DESC(debug, "turn on debugging (default: 0)");
40 #define dprintk(args...) do { \
41 if (debug) { \
42 printk(KERN_DEBUG "DiB0070: "); \
43 printk(args); \
44 printk("\n"); \
45 } \
46 } while (0)
48 #define DIB0070_P1D 0x00
49 #define DIB0070_P1F 0x01
50 #define DIB0070_P1G 0x03
51 #define DIB0070S_P1A 0x02
53 struct dib0070_state {
54 struct i2c_adapter *i2c;
55 struct dvb_frontend *fe;
56 const struct dib0070_config *cfg;
57 u16 wbd_ff_offset;
58 u8 revision;
60 enum frontend_tune_state tune_state;
61 u32 current_rf;
63 /* for the captrim binary search */
64 s8 step;
65 u16 adc_diff;
67 s8 captrim;
68 s8 fcaptrim;
69 u16 lo4;
71 const struct dib0070_tuning *current_tune_table_index;
72 const struct dib0070_lna_match *lna_match;
74 u8 wbd_gain_current;
75 u16 wbd_offset_3_3[2];
77 /* for the I2C transfer */
78 struct i2c_msg msg[2];
79 u8 i2c_write_buffer[3];
80 u8 i2c_read_buffer[2];
83 static uint16_t dib0070_read_reg(struct dib0070_state *state, u8 reg)
85 state->i2c_write_buffer[0] = reg;
87 memset(state->msg, 0, 2 * sizeof(struct i2c_msg));
88 state->msg[0].addr = state->cfg->i2c_address;
89 state->msg[0].flags = 0;
90 state->msg[0].buf = state->i2c_write_buffer;
91 state->msg[0].len = 1;
92 state->msg[1].addr = state->cfg->i2c_address;
93 state->msg[1].flags = I2C_M_RD;
94 state->msg[1].buf = state->i2c_read_buffer;
95 state->msg[1].len = 2;
97 if (i2c_transfer(state->i2c, state->msg, 2) != 2) {
98 printk(KERN_WARNING "DiB0070 I2C read failed\n");
99 return 0;
101 return (state->i2c_read_buffer[0] << 8) | state->i2c_read_buffer[1];
104 static int dib0070_write_reg(struct dib0070_state *state, u8 reg, u16 val)
106 state->i2c_write_buffer[0] = reg;
107 state->i2c_write_buffer[1] = val >> 8;
108 state->i2c_write_buffer[2] = val & 0xff;
110 memset(state->msg, 0, sizeof(struct i2c_msg));
111 state->msg[0].addr = state->cfg->i2c_address;
112 state->msg[0].flags = 0;
113 state->msg[0].buf = state->i2c_write_buffer;
114 state->msg[0].len = 3;
116 if (i2c_transfer(state->i2c, state->msg, 1) != 1) {
117 printk(KERN_WARNING "DiB0070 I2C write failed\n");
118 return -EREMOTEIO;
120 return 0;
123 #define HARD_RESET(state) do { \
124 state->cfg->sleep(state->fe, 0); \
125 if (state->cfg->reset) { \
126 state->cfg->reset(state->fe,1); msleep(10); \
127 state->cfg->reset(state->fe,0); msleep(10); \
129 } while (0)
131 static int dib0070_set_bandwidth(struct dvb_frontend *fe, struct dvb_frontend_parameters *ch)
133 struct dib0070_state *state = fe->tuner_priv;
134 u16 tmp = dib0070_read_reg(state, 0x02) & 0x3fff;
136 if (state->fe->dtv_property_cache.bandwidth_hz/1000 > 7000)
137 tmp |= (0 << 14);
138 else if (state->fe->dtv_property_cache.bandwidth_hz/1000 > 6000)
139 tmp |= (1 << 14);
140 else if (state->fe->dtv_property_cache.bandwidth_hz/1000 > 5000)
141 tmp |= (2 << 14);
142 else
143 tmp |= (3 << 14);
145 dib0070_write_reg(state, 0x02, tmp);
147 /* sharpen the BB filter in ISDB-T to have higher immunity to adjacent channels */
148 if (state->fe->dtv_property_cache.delivery_system == SYS_ISDBT) {
149 u16 value = dib0070_read_reg(state, 0x17);
151 dib0070_write_reg(state, 0x17, value & 0xfffc);
152 tmp = dib0070_read_reg(state, 0x01) & 0x01ff;
153 dib0070_write_reg(state, 0x01, tmp | (60 << 9));
155 dib0070_write_reg(state, 0x17, value);
157 return 0;
160 static int dib0070_captrim(struct dib0070_state *state, enum frontend_tune_state *tune_state)
162 int8_t step_sign;
163 u16 adc;
164 int ret = 0;
166 if (*tune_state == CT_TUNER_STEP_0) {
168 dib0070_write_reg(state, 0x0f, 0xed10);
169 dib0070_write_reg(state, 0x17, 0x0034);
171 dib0070_write_reg(state, 0x18, 0x0032);
172 state->step = state->captrim = state->fcaptrim = 64;
173 state->adc_diff = 3000;
174 ret = 20;
176 *tune_state = CT_TUNER_STEP_1;
177 } else if (*tune_state == CT_TUNER_STEP_1) {
178 state->step /= 2;
179 dib0070_write_reg(state, 0x14, state->lo4 | state->captrim);
180 ret = 15;
182 *tune_state = CT_TUNER_STEP_2;
183 } else if (*tune_state == CT_TUNER_STEP_2) {
185 adc = dib0070_read_reg(state, 0x19);
187 dprintk("CAPTRIM=%hd; ADC = %hd (ADC) & %dmV", state->captrim, adc, (u32) adc*(u32)1800/(u32)1024);
189 if (adc >= 400) {
190 adc -= 400;
191 step_sign = -1;
192 } else {
193 adc = 400 - adc;
194 step_sign = 1;
197 if (adc < state->adc_diff) {
198 dprintk("CAPTRIM=%hd is closer to target (%hd/%hd)", state->captrim, adc, state->adc_diff);
199 state->adc_diff = adc;
200 state->fcaptrim = state->captrim;
205 state->captrim += (step_sign * state->step);
207 if (state->step >= 1)
208 *tune_state = CT_TUNER_STEP_1;
209 else
210 *tune_state = CT_TUNER_STEP_3;
212 } else if (*tune_state == CT_TUNER_STEP_3) {
213 dib0070_write_reg(state, 0x14, state->lo4 | state->fcaptrim);
214 dib0070_write_reg(state, 0x18, 0x07ff);
215 *tune_state = CT_TUNER_STEP_4;
218 return ret;
221 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)
223 struct dib0070_state *state = fe->tuner_priv;
224 u16 lo5 = (third_order_filt << 14) | (0 << 13) | (1 << 12) | (3 << 9) | (cp_current << 6) | (hf_div_trim << 3) | (vco_bias_trim << 0);
225 dprintk("CTRL_LO5: 0x%x", lo5);
226 return dib0070_write_reg(state, 0x15, lo5);
229 void dib0070_ctrl_agc_filter(struct dvb_frontend *fe, u8 open)
231 struct dib0070_state *state = fe->tuner_priv;
233 if (open) {
234 dib0070_write_reg(state, 0x1b, 0xff00);
235 dib0070_write_reg(state, 0x1a, 0x0000);
236 } else {
237 dib0070_write_reg(state, 0x1b, 0x4112);
238 if (state->cfg->vga_filter != 0) {
239 dib0070_write_reg(state, 0x1a, state->cfg->vga_filter);
240 dprintk("vga filter register is set to %x", state->cfg->vga_filter);
241 } else
242 dib0070_write_reg(state, 0x1a, 0x0009);
246 EXPORT_SYMBOL(dib0070_ctrl_agc_filter);
247 struct dib0070_tuning {
248 u32 max_freq; /* for every frequency less than or equal to that field: this information is correct */
249 u8 switch_trim;
250 u8 vco_band;
251 u8 hfdiv;
252 u8 vco_multi;
253 u8 presc;
254 u8 wbdmux;
255 u16 tuner_enable;
258 struct dib0070_lna_match {
259 u32 max_freq; /* for every frequency less than or equal to that field: this information is correct */
260 u8 lna_band;
263 static const struct dib0070_tuning dib0070s_tuning_table[] = {
264 { 570000, 2, 1, 3, 6, 6, 2, 0x4000 | 0x0800 }, /* UHF */
265 { 700000, 2, 0, 2, 4, 2, 2, 0x4000 | 0x0800 },
266 { 863999, 2, 1, 2, 4, 2, 2, 0x4000 | 0x0800 },
267 { 1500000, 0, 1, 1, 2, 2, 4, 0x2000 | 0x0400 }, /* LBAND */
268 { 1600000, 0, 1, 1, 2, 2, 4, 0x2000 | 0x0400 },
269 { 2000000, 0, 1, 1, 2, 2, 4, 0x2000 | 0x0400 },
270 { 0xffffffff, 0, 0, 8, 1, 2, 1, 0x8000 | 0x1000 }, /* SBAND */
273 static const struct dib0070_tuning dib0070_tuning_table[] = {
274 { 115000, 1, 0, 7, 24, 2, 1, 0x8000 | 0x1000 }, /* FM below 92MHz cannot be tuned */
275 { 179500, 1, 0, 3, 16, 2, 1, 0x8000 | 0x1000 }, /* VHF */
276 { 189999, 1, 1, 3, 16, 2, 1, 0x8000 | 0x1000 },
277 { 250000, 1, 0, 6, 12, 2, 1, 0x8000 | 0x1000 },
278 { 569999, 2, 1, 5, 6, 2, 2, 0x4000 | 0x0800 }, /* UHF */
279 { 699999, 2, 0, 1, 4, 2, 2, 0x4000 | 0x0800 },
280 { 863999, 2, 1, 1, 4, 2, 2, 0x4000 | 0x0800 },
281 { 0xffffffff, 0, 1, 0, 2, 2, 4, 0x2000 | 0x0400 }, /* LBAND or everything higher than UHF */
284 static const struct dib0070_lna_match dib0070_lna_flip_chip[] = {
285 { 180000, 0 }, /* VHF */
286 { 188000, 1 },
287 { 196400, 2 },
288 { 250000, 3 },
289 { 550000, 0 }, /* UHF */
290 { 590000, 1 },
291 { 666000, 3 },
292 { 864000, 5 },
293 { 1500000, 0 }, /* LBAND or everything higher than UHF */
294 { 1600000, 1 },
295 { 2000000, 3 },
296 { 0xffffffff, 7 },
299 static const struct dib0070_lna_match dib0070_lna[] = {
300 { 180000, 0 }, /* VHF */
301 { 188000, 1 },
302 { 196400, 2 },
303 { 250000, 3 },
304 { 550000, 2 }, /* UHF */
305 { 650000, 3 },
306 { 750000, 5 },
307 { 850000, 6 },
308 { 864000, 7 },
309 { 1500000, 0 }, /* LBAND or everything higher than UHF */
310 { 1600000, 1 },
311 { 2000000, 3 },
312 { 0xffffffff, 7 },
315 #define LPF 100
316 static int dib0070_tune_digital(struct dvb_frontend *fe, struct dvb_frontend_parameters *ch)
318 struct dib0070_state *state = fe->tuner_priv;
320 const struct dib0070_tuning *tune;
321 const struct dib0070_lna_match *lna_match;
323 enum frontend_tune_state *tune_state = &state->tune_state;
324 int ret = 10; /* 1ms is the default delay most of the time */
326 u8 band = (u8)BAND_OF_FREQUENCY(fe->dtv_property_cache.frequency/1000);
327 u32 freq = fe->dtv_property_cache.frequency/1000 + (band == BAND_VHF ? state->cfg->freq_offset_khz_vhf : state->cfg->freq_offset_khz_uhf);
329 #ifdef CONFIG_SYS_ISDBT
330 if (state->fe->dtv_property_cache.delivery_system == SYS_ISDBT && state->fe->dtv_property_cache.isdbt_sb_mode == 1)
331 if (((state->fe->dtv_property_cache.isdbt_sb_segment_count % 2)
332 && (state->fe->dtv_property_cache.isdbt_sb_segment_idx == ((state->fe->dtv_property_cache.isdbt_sb_segment_count / 2) + 1)))
333 || (((state->fe->dtv_property_cache.isdbt_sb_segment_count % 2) == 0)
334 && (state->fe->dtv_property_cache.isdbt_sb_segment_idx == (state->fe->dtv_property_cache.isdbt_sb_segment_count / 2)))
335 || (((state->fe->dtv_property_cache.isdbt_sb_segment_count % 2) == 0)
336 && (state->fe->dtv_property_cache.isdbt_sb_segment_idx == ((state->fe->dtv_property_cache.isdbt_sb_segment_count / 2) + 1))))
337 freq += 850;
338 #endif
339 if (state->current_rf != freq) {
341 switch (state->revision) {
342 case DIB0070S_P1A:
343 tune = dib0070s_tuning_table;
344 lna_match = dib0070_lna;
345 break;
346 default:
347 tune = dib0070_tuning_table;
348 if (state->cfg->flip_chip)
349 lna_match = dib0070_lna_flip_chip;
350 else
351 lna_match = dib0070_lna;
352 break;
354 while (freq > tune->max_freq) /* find the right one */
355 tune++;
356 while (freq > lna_match->max_freq) /* find the right one */
357 lna_match++;
359 state->current_tune_table_index = tune;
360 state->lna_match = lna_match;
363 if (*tune_state == CT_TUNER_START) {
364 dprintk("Tuning for Band: %hd (%d kHz)", band, freq);
365 if (state->current_rf != freq) {
366 u8 REFDIV;
367 u32 FBDiv, Rest, FREF, VCOF_kHz;
368 u8 Den;
370 state->current_rf = freq;
371 state->lo4 = (state->current_tune_table_index->vco_band << 11) | (state->current_tune_table_index->hfdiv << 7);
374 dib0070_write_reg(state, 0x17, 0x30);
377 VCOF_kHz = state->current_tune_table_index->vco_multi * freq * 2;
379 switch (band) {
380 case BAND_VHF:
381 REFDIV = (u8) ((state->cfg->clock_khz + 9999) / 10000);
382 break;
383 case BAND_FM:
384 REFDIV = (u8) ((state->cfg->clock_khz) / 1000);
385 break;
386 default:
387 REFDIV = (u8) (state->cfg->clock_khz / 10000);
388 break;
390 FREF = state->cfg->clock_khz / REFDIV;
394 switch (state->revision) {
395 case DIB0070S_P1A:
396 FBDiv = (VCOF_kHz / state->current_tune_table_index->presc / FREF);
397 Rest = (VCOF_kHz / state->current_tune_table_index->presc) - FBDiv * FREF;
398 break;
400 case DIB0070_P1G:
401 case DIB0070_P1F:
402 default:
403 FBDiv = (freq / (FREF / 2));
404 Rest = 2 * freq - FBDiv * FREF;
405 break;
408 if (Rest < LPF)
409 Rest = 0;
410 else if (Rest < 2 * LPF)
411 Rest = 2 * LPF;
412 else if (Rest > (FREF - LPF)) {
413 Rest = 0;
414 FBDiv += 1;
415 } else if (Rest > (FREF - 2 * LPF))
416 Rest = FREF - 2 * LPF;
417 Rest = (Rest * 6528) / (FREF / 10);
419 Den = 1;
420 if (Rest > 0) {
421 state->lo4 |= (1 << 14) | (1 << 12);
422 Den = 255;
426 dib0070_write_reg(state, 0x11, (u16)FBDiv);
427 dib0070_write_reg(state, 0x12, (Den << 8) | REFDIV);
428 dib0070_write_reg(state, 0x13, (u16) Rest);
430 if (state->revision == DIB0070S_P1A) {
432 if (band == BAND_SBAND) {
433 dib0070_set_ctrl_lo5(fe, 2, 4, 3, 0);
434 dib0070_write_reg(state, 0x1d, 0xFFFF);
435 } else
436 dib0070_set_ctrl_lo5(fe, 5, 4, 3, 1);
439 dib0070_write_reg(state, 0x20,
440 0x0040 | 0x0020 | 0x0010 | 0x0008 | 0x0002 | 0x0001 | state->current_tune_table_index->tuner_enable);
442 dprintk("REFDIV: %hd, FREF: %d", REFDIV, FREF);
443 dprintk("FBDIV: %d, Rest: %d", FBDiv, Rest);
444 dprintk("Num: %hd, Den: %hd, SD: %hd", (u16) Rest, Den, (state->lo4 >> 12) & 0x1);
445 dprintk("HFDIV code: %hd", state->current_tune_table_index->hfdiv);
446 dprintk("VCO = %hd", state->current_tune_table_index->vco_band);
447 dprintk("VCOF: ((%hd*%d) << 1))", state->current_tune_table_index->vco_multi, freq);
449 *tune_state = CT_TUNER_STEP_0;
450 } else { /* we are already tuned to this frequency - the configuration is correct */
451 ret = 50; /* wakeup time */
452 *tune_state = CT_TUNER_STEP_5;
454 } else if ((*tune_state > CT_TUNER_START) && (*tune_state < CT_TUNER_STEP_4)) {
456 ret = dib0070_captrim(state, tune_state);
458 } else if (*tune_state == CT_TUNER_STEP_4) {
459 const struct dib0070_wbd_gain_cfg *tmp = state->cfg->wbd_gain;
460 if (tmp != NULL) {
461 while (freq/1000 > tmp->freq) /* find the right one */
462 tmp++;
463 dib0070_write_reg(state, 0x0f,
464 (0 << 15) | (1 << 14) | (3 << 12)
465 | (tmp->wbd_gain_val << 9) | (0 << 8) | (1 << 7)
466 | (state->current_tune_table_index->wbdmux << 0));
467 state->wbd_gain_current = tmp->wbd_gain_val;
468 } else {
469 dib0070_write_reg(state, 0x0f,
470 (0 << 15) | (1 << 14) | (3 << 12) | (6 << 9) | (0 << 8) | (1 << 7) | (state->current_tune_table_index->
471 wbdmux << 0));
472 state->wbd_gain_current = 6;
475 dib0070_write_reg(state, 0x06, 0x3fff);
476 dib0070_write_reg(state, 0x07,
477 (state->current_tune_table_index->switch_trim << 11) | (7 << 8) | (state->lna_match->lna_band << 3) | (3 << 0));
478 dib0070_write_reg(state, 0x08, (state->lna_match->lna_band << 10) | (3 << 7) | (127));
479 dib0070_write_reg(state, 0x0d, 0x0d80);
482 dib0070_write_reg(state, 0x18, 0x07ff);
483 dib0070_write_reg(state, 0x17, 0x0033);
486 *tune_state = CT_TUNER_STEP_5;
487 } else if (*tune_state == CT_TUNER_STEP_5) {
488 dib0070_set_bandwidth(fe, ch);
489 *tune_state = CT_TUNER_STOP;
490 } else {
491 ret = FE_CALLBACK_TIME_NEVER; /* tuner finished, time to call again infinite */
493 return ret;
497 static int dib0070_tune(struct dvb_frontend *fe, struct dvb_frontend_parameters *p)
499 struct dib0070_state *state = fe->tuner_priv;
500 uint32_t ret;
502 state->tune_state = CT_TUNER_START;
504 do {
505 ret = dib0070_tune_digital(fe, p);
506 if (ret != FE_CALLBACK_TIME_NEVER)
507 msleep(ret/10);
508 else
509 break;
510 } while (state->tune_state != CT_TUNER_STOP);
512 return 0;
515 static int dib0070_wakeup(struct dvb_frontend *fe)
517 struct dib0070_state *state = fe->tuner_priv;
518 if (state->cfg->sleep)
519 state->cfg->sleep(fe, 0);
520 return 0;
523 static int dib0070_sleep(struct dvb_frontend *fe)
525 struct dib0070_state *state = fe->tuner_priv;
526 if (state->cfg->sleep)
527 state->cfg->sleep(fe, 1);
528 return 0;
531 u8 dib0070_get_rf_output(struct dvb_frontend *fe)
533 struct dib0070_state *state = fe->tuner_priv;
534 return (dib0070_read_reg(state, 0x07) >> 11) & 0x3;
536 EXPORT_SYMBOL(dib0070_get_rf_output);
538 int dib0070_set_rf_output(struct dvb_frontend *fe, u8 no)
540 struct dib0070_state *state = fe->tuner_priv;
541 u16 rxrf2 = dib0070_read_reg(state, 0x07) & 0xfe7ff;
542 if (no > 3)
543 no = 3;
544 if (no < 1)
545 no = 1;
546 return dib0070_write_reg(state, 0x07, rxrf2 | (no << 11));
548 EXPORT_SYMBOL(dib0070_set_rf_output);
550 static const u16 dib0070_p1f_defaults[] =
553 7, 0x02,
554 0x0008,
555 0x0000,
556 0x0000,
557 0x0000,
558 0x0000,
559 0x0002,
560 0x0100,
562 3, 0x0d,
563 0x0d80,
564 0x0001,
565 0x0000,
567 4, 0x11,
568 0x0000,
569 0x0103,
570 0x0000,
571 0x0000,
573 3, 0x16,
574 0x0004 | 0x0040,
575 0x0030,
576 0x07ff,
578 6, 0x1b,
579 0x4112,
580 0xff00,
581 0xc07f,
582 0x0000,
583 0x0180,
584 0x4000 | 0x0800 | 0x0040 | 0x0020 | 0x0010 | 0x0008 | 0x0002 | 0x0001,
589 static u16 dib0070_read_wbd_offset(struct dib0070_state *state, u8 gain)
591 u16 tuner_en = dib0070_read_reg(state, 0x20);
592 u16 offset;
594 dib0070_write_reg(state, 0x18, 0x07ff);
595 dib0070_write_reg(state, 0x20, 0x0800 | 0x4000 | 0x0040 | 0x0020 | 0x0010 | 0x0008 | 0x0002 | 0x0001);
596 dib0070_write_reg(state, 0x0f, (1 << 14) | (2 << 12) | (gain << 9) | (1 << 8) | (1 << 7) | (0 << 0));
597 msleep(9);
598 offset = dib0070_read_reg(state, 0x19);
599 dib0070_write_reg(state, 0x20, tuner_en);
600 return offset;
603 static void dib0070_wbd_offset_calibration(struct dib0070_state *state)
605 u8 gain;
606 for (gain = 6; gain < 8; gain++) {
607 state->wbd_offset_3_3[gain - 6] = ((dib0070_read_wbd_offset(state, gain) * 8 * 18 / 33 + 1) / 2);
608 dprintk("Gain: %d, WBDOffset (3.3V) = %hd", gain, state->wbd_offset_3_3[gain-6]);
612 u16 dib0070_wbd_offset(struct dvb_frontend *fe)
614 struct dib0070_state *state = fe->tuner_priv;
615 const struct dib0070_wbd_gain_cfg *tmp = state->cfg->wbd_gain;
616 u32 freq = fe->dtv_property_cache.frequency/1000;
618 if (tmp != NULL) {
619 while (freq/1000 > tmp->freq) /* find the right one */
620 tmp++;
621 state->wbd_gain_current = tmp->wbd_gain_val;
622 } else
623 state->wbd_gain_current = 6;
625 return state->wbd_offset_3_3[state->wbd_gain_current - 6];
627 EXPORT_SYMBOL(dib0070_wbd_offset);
629 #define pgm_read_word(w) (*w)
630 static int dib0070_reset(struct dvb_frontend *fe)
632 struct dib0070_state *state = fe->tuner_priv;
633 u16 l, r, *n;
635 HARD_RESET(state);
638 #ifndef FORCE_SBAND_TUNER
639 if ((dib0070_read_reg(state, 0x22) >> 9) & 0x1)
640 state->revision = (dib0070_read_reg(state, 0x1f) >> 8) & 0xff;
641 else
642 #else
643 #warning forcing SBAND
644 #endif
645 state->revision = DIB0070S_P1A;
647 /* P1F or not */
648 dprintk("Revision: %x", state->revision);
650 if (state->revision == DIB0070_P1D) {
651 dprintk("Error: this driver is not to be used meant for P1D or earlier");
652 return -EINVAL;
655 n = (u16 *) dib0070_p1f_defaults;
656 l = pgm_read_word(n++);
657 while (l) {
658 r = pgm_read_word(n++);
659 do {
660 dib0070_write_reg(state, (u8)r, pgm_read_word(n++));
661 r++;
662 } while (--l);
663 l = pgm_read_word(n++);
666 if (state->cfg->force_crystal_mode != 0)
667 r = state->cfg->force_crystal_mode;
668 else if (state->cfg->clock_khz >= 24000)
669 r = 1;
670 else
671 r = 2;
674 r |= state->cfg->osc_buffer_state << 3;
676 dib0070_write_reg(state, 0x10, r);
677 dib0070_write_reg(state, 0x1f, (1 << 8) | ((state->cfg->clock_pad_drive & 0xf) << 5));
679 if (state->cfg->invert_iq) {
680 r = dib0070_read_reg(state, 0x02) & 0xffdf;
681 dib0070_write_reg(state, 0x02, r | (1 << 5));
684 if (state->revision == DIB0070S_P1A)
685 dib0070_set_ctrl_lo5(fe, 2, 4, 3, 0);
686 else
687 dib0070_set_ctrl_lo5(fe, 5, 4, state->cfg->charge_pump, state->cfg->enable_third_order_filter);
689 dib0070_write_reg(state, 0x01, (54 << 9) | 0xc8);
691 dib0070_wbd_offset_calibration(state);
693 return 0;
696 static int dib0070_get_frequency(struct dvb_frontend *fe, u32 *frequency)
698 struct dib0070_state *state = fe->tuner_priv;
700 *frequency = 1000 * state->current_rf;
701 return 0;
704 static int dib0070_release(struct dvb_frontend *fe)
706 kfree(fe->tuner_priv);
707 fe->tuner_priv = NULL;
708 return 0;
711 static const struct dvb_tuner_ops dib0070_ops = {
712 .info = {
713 .name = "DiBcom DiB0070",
714 .frequency_min = 45000000,
715 .frequency_max = 860000000,
716 .frequency_step = 1000,
718 .release = dib0070_release,
720 .init = dib0070_wakeup,
721 .sleep = dib0070_sleep,
722 .set_params = dib0070_tune,
724 .get_frequency = dib0070_get_frequency,
725 // .get_bandwidth = dib0070_get_bandwidth
728 struct dvb_frontend *dib0070_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct dib0070_config *cfg)
730 struct dib0070_state *state = kzalloc(sizeof(struct dib0070_state), GFP_KERNEL);
731 if (state == NULL)
732 return NULL;
734 state->cfg = cfg;
735 state->i2c = i2c;
736 state->fe = fe;
737 fe->tuner_priv = state;
739 if (dib0070_reset(fe) != 0)
740 goto free_mem;
742 printk(KERN_INFO "DiB0070: successfully identified\n");
743 memcpy(&fe->ops.tuner_ops, &dib0070_ops, sizeof(struct dvb_tuner_ops));
745 fe->tuner_priv = state;
746 return fe;
748 free_mem:
749 kfree(state);
750 fe->tuner_priv = NULL;
751 return NULL;
753 EXPORT_SYMBOL(dib0070_attach);
755 MODULE_AUTHOR("Patrick Boettcher <pboettcher@dibcom.fr>");
756 MODULE_DESCRIPTION("Driver for the DiBcom 0070 base-band RF Tuner");
757 MODULE_LICENSE("GPL");