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
37static int debug;
38module_param(debug, int, 0644);
39MODULE_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
54struct 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
85static 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
117static 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
153static 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
182static 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
243static 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
251void 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
268EXPORT_SYMBOL(dib0070_ctrl_agc_filter);
269struct 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
280struct 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
285static 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
295static 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
306static 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
321static 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
338static 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
519static 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
537static 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
545static 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
553u8 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}
558EXPORT_SYMBOL(dib0070_get_rf_output);
559
560int 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}
570EXPORT_SYMBOL(dib0070_set_rf_output);
571
572static 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
611static 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
625static 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
634u16 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}
649EXPORT_SYMBOL(dib0070_wbd_offset);
650
651#define pgm_read_word(w) (*w)
652static 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
718static 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
726static int dib0070_release(struct dvb_frontend *fe)
727{
728	kfree(fe->tuner_priv);
729	fe->tuner_priv = NULL;
730	return 0;
731}
732
733static 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
750struct 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
771free_mem:
772	kfree(state);
773	fe->tuner_priv = NULL;
774	return NULL;
775}
776EXPORT_SYMBOL(dib0070_attach);
777
778MODULE_AUTHOR("Patrick Boettcher <pboettcher@dibcom.fr>");
779MODULE_DESCRIPTION("Driver for the DiBcom 0070 base-band RF Tuner");
780MODULE_LICENSE("GPL");
781