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