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