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 
23 static int debug;
24 module_param(debug, int, 0644);
25 MODULE_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 
38 struct 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 
69 static 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 
101 static 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 
137 static 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 
166 static 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=%hd; ADC = %hd (ADC) & %dmV\n", state->captrim, adc, (u32) adc*(u32)1800/(u32)1024);
193 
194 		if (adc >= 400) {
195 			adc -= 400;
196 			step_sign = -1;
197 		} else {
198 			adc = 400 - adc;
199 			step_sign = 1;
200 		}
201 
202 		if (adc < state->adc_diff) {
203 			dprintk("CAPTRIM=%hd is closer to target (%hd/%hd)\n", state->captrim, adc, state->adc_diff);
204 			state->adc_diff = adc;
205 			state->fcaptrim = state->captrim;
206 		}
207 		state->captrim += (step_sign * state->step);
208 
209 		if (state->step >= 1)
210 			*tune_state = CT_TUNER_STEP_1;
211 		else
212 			*tune_state = CT_TUNER_STEP_3;
213 
214 	} else if (*tune_state == CT_TUNER_STEP_3) {
215 		dib0070_write_reg(state, 0x14, state->lo4 | state->fcaptrim);
216 		dib0070_write_reg(state, 0x18, 0x07ff);
217 		*tune_state = CT_TUNER_STEP_4;
218 	}
219 
220 	return ret;
221 }
222 
223 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)
224 {
225 	struct dib0070_state *state = fe->tuner_priv;
226 	u16 lo5 = (third_order_filt << 14) | (0 << 13) | (1 << 12) | (3 << 9) | (cp_current << 6) | (hf_div_trim << 3) | (vco_bias_trim << 0);
227 
228 	dprintk("CTRL_LO5: 0x%x\n", lo5);
229 	return dib0070_write_reg(state, 0x15, lo5);
230 }
231 
232 void dib0070_ctrl_agc_filter(struct dvb_frontend *fe, u8 open)
233 {
234 	struct dib0070_state *state = fe->tuner_priv;
235 
236 	if (open) {
237 		dib0070_write_reg(state, 0x1b, 0xff00);
238 		dib0070_write_reg(state, 0x1a, 0x0000);
239 	} else {
240 		dib0070_write_reg(state, 0x1b, 0x4112);
241 		if (state->cfg->vga_filter != 0) {
242 			dib0070_write_reg(state, 0x1a, state->cfg->vga_filter);
243 			dprintk("vga filter register is set to %x\n", state->cfg->vga_filter);
244 		} else
245 			dib0070_write_reg(state, 0x1a, 0x0009);
246 	}
247 }
248 
249 EXPORT_SYMBOL(dib0070_ctrl_agc_filter);
250 struct dib0070_tuning {
251 	u32 max_freq; /* for every frequency less than or equal to that field: this information is correct */
252 	u8 switch_trim;
253 	u8 vco_band;
254 	u8 hfdiv;
255 	u8 vco_multi;
256 	u8 presc;
257 	u8 wbdmux;
258 	u16 tuner_enable;
259 };
260 
261 struct dib0070_lna_match {
262 	u32 max_freq; /* for every frequency less than or equal to that field: this information is correct */
263 	u8 lna_band;
264 };
265 
266 static const struct dib0070_tuning dib0070s_tuning_table[] = {
267 	{     570000, 2, 1, 3, 6, 6, 2, 0x4000 | 0x0800 }, /* UHF */
268 	{     700000, 2, 0, 2, 4, 2, 2, 0x4000 | 0x0800 },
269 	{     863999, 2, 1, 2, 4, 2, 2, 0x4000 | 0x0800 },
270 	{    1500000, 0, 1, 1, 2, 2, 4, 0x2000 | 0x0400 }, /* LBAND */
271 	{    1600000, 0, 1, 1, 2, 2, 4, 0x2000 | 0x0400 },
272 	{    2000000, 0, 1, 1, 2, 2, 4, 0x2000 | 0x0400 },
273 	{ 0xffffffff, 0, 0, 8, 1, 2, 1, 0x8000 | 0x1000 }, /* SBAND */
274 };
275 
276 static const struct dib0070_tuning dib0070_tuning_table[] = {
277 	{     115000, 1, 0, 7, 24, 2, 1, 0x8000 | 0x1000 }, /* FM below 92MHz cannot be tuned */
278 	{     179500, 1, 0, 3, 16, 2, 1, 0x8000 | 0x1000 }, /* VHF */
279 	{     189999, 1, 1, 3, 16, 2, 1, 0x8000 | 0x1000 },
280 	{     250000, 1, 0, 6, 12, 2, 1, 0x8000 | 0x1000 },
281 	{     569999, 2, 1, 5,  6, 2, 2, 0x4000 | 0x0800 }, /* UHF */
282 	{     699999, 2, 0, 1,  4, 2, 2, 0x4000 | 0x0800 },
283 	{     863999, 2, 1, 1,  4, 2, 2, 0x4000 | 0x0800 },
284 	{ 0xffffffff, 0, 1, 0,  2, 2, 4, 0x2000 | 0x0400 }, /* LBAND or everything higher than UHF */
285 };
286 
287 static const struct dib0070_lna_match dib0070_lna_flip_chip[] = {
288 	{     180000, 0 }, /* VHF */
289 	{     188000, 1 },
290 	{     196400, 2 },
291 	{     250000, 3 },
292 	{     550000, 0 }, /* UHF */
293 	{     590000, 1 },
294 	{     666000, 3 },
295 	{     864000, 5 },
296 	{    1500000, 0 }, /* LBAND or everything higher than UHF */
297 	{    1600000, 1 },
298 	{    2000000, 3 },
299 	{ 0xffffffff, 7 },
300 };
301 
302 static const struct dib0070_lna_match dib0070_lna[] = {
303 	{     180000, 0 }, /* VHF */
304 	{     188000, 1 },
305 	{     196400, 2 },
306 	{     250000, 3 },
307 	{     550000, 2 }, /* UHF */
308 	{     650000, 3 },
309 	{     750000, 5 },
310 	{     850000, 6 },
311 	{     864000, 7 },
312 	{    1500000, 0 }, /* LBAND or everything higher than UHF */
313 	{    1600000, 1 },
314 	{    2000000, 3 },
315 	{ 0xffffffff, 7 },
316 };
317 
318 #define LPF	100
319 static int dib0070_tune_digital(struct dvb_frontend *fe)
320 {
321 	struct dib0070_state *state = fe->tuner_priv;
322 
323 	const struct dib0070_tuning *tune;
324 	const struct dib0070_lna_match *lna_match;
325 
326 	enum frontend_tune_state *tune_state = &state->tune_state;
327 	int ret = 10; /* 1ms is the default delay most of the time */
328 
329 	u8  band = (u8)BAND_OF_FREQUENCY(fe->dtv_property_cache.frequency/1000);
330 	u32 freq = fe->dtv_property_cache.frequency/1000 + (band == BAND_VHF ? state->cfg->freq_offset_khz_vhf : state->cfg->freq_offset_khz_uhf);
331 
332 #ifdef CONFIG_SYS_ISDBT
333 	if (state->fe->dtv_property_cache.delivery_system == SYS_ISDBT && state->fe->dtv_property_cache.isdbt_sb_mode == 1)
334 			if (((state->fe->dtv_property_cache.isdbt_sb_segment_count % 2)
335 			&& (state->fe->dtv_property_cache.isdbt_sb_segment_idx == ((state->fe->dtv_property_cache.isdbt_sb_segment_count / 2) + 1)))
336 			|| (((state->fe->dtv_property_cache.isdbt_sb_segment_count % 2) == 0)
337 				&& (state->fe->dtv_property_cache.isdbt_sb_segment_idx == (state->fe->dtv_property_cache.isdbt_sb_segment_count / 2)))
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) + 1))))
340 				freq += 850;
341 #endif
342 	if (state->current_rf != freq) {
343 
344 		switch (state->revision) {
345 		case DIB0070S_P1A:
346 		tune = dib0070s_tuning_table;
347 		lna_match = dib0070_lna;
348 		break;
349 		default:
350 		tune = dib0070_tuning_table;
351 		if (state->cfg->flip_chip)
352 			lna_match = dib0070_lna_flip_chip;
353 		else
354 			lna_match = dib0070_lna;
355 		break;
356 		}
357 		while (freq > tune->max_freq) /* find the right one */
358 			tune++;
359 		while (freq > lna_match->max_freq) /* find the right one */
360 			lna_match++;
361 
362 		state->current_tune_table_index = tune;
363 		state->lna_match = lna_match;
364 	}
365 
366 	if (*tune_state == CT_TUNER_START) {
367 		dprintk("Tuning for Band: %hd (%d kHz)\n", band, freq);
368 		if (state->current_rf != freq) {
369 			u8 REFDIV;
370 			u32 FBDiv, Rest, FREF, VCOF_kHz;
371 			u8 Den;
372 
373 			state->current_rf = freq;
374 			state->lo4 = (state->current_tune_table_index->vco_band << 11) | (state->current_tune_table_index->hfdiv << 7);
375 
376 
377 			dib0070_write_reg(state, 0x17, 0x30);
378 
379 
380 			VCOF_kHz = state->current_tune_table_index->vco_multi * freq * 2;
381 
382 			switch (band) {
383 			case BAND_VHF:
384 				REFDIV = (u8) ((state->cfg->clock_khz + 9999) / 10000);
385 				break;
386 			case BAND_FM:
387 				REFDIV = (u8) ((state->cfg->clock_khz) / 1000);
388 				break;
389 			default:
390 				REFDIV = (u8) (state->cfg->clock_khz  / 10000);
391 				break;
392 			}
393 			FREF = state->cfg->clock_khz / REFDIV;
394 
395 
396 
397 			switch (state->revision) {
398 			case DIB0070S_P1A:
399 				FBDiv = (VCOF_kHz / state->current_tune_table_index->presc / FREF);
400 				Rest  = (VCOF_kHz / state->current_tune_table_index->presc) - FBDiv * FREF;
401 				break;
402 
403 			case DIB0070_P1G:
404 			case DIB0070_P1F:
405 			default:
406 				FBDiv = (freq / (FREF / 2));
407 				Rest  = 2 * freq - FBDiv * FREF;
408 				break;
409 			}
410 
411 			if (Rest < LPF)
412 				Rest = 0;
413 			else if (Rest < 2 * LPF)
414 				Rest = 2 * LPF;
415 			else if (Rest > (FREF - LPF)) {
416 				Rest = 0;
417 				FBDiv += 1;
418 			} else if (Rest > (FREF - 2 * LPF))
419 				Rest = FREF - 2 * LPF;
420 			Rest = (Rest * 6528) / (FREF / 10);
421 
422 			Den = 1;
423 			if (Rest > 0) {
424 				state->lo4 |= (1 << 14) | (1 << 12);
425 				Den = 255;
426 			}
427 
428 
429 			dib0070_write_reg(state, 0x11, (u16)FBDiv);
430 			dib0070_write_reg(state, 0x12, (Den << 8) | REFDIV);
431 			dib0070_write_reg(state, 0x13, (u16) Rest);
432 
433 			if (state->revision == DIB0070S_P1A) {
434 
435 				if (band == BAND_SBAND) {
436 					dib0070_set_ctrl_lo5(fe, 2, 4, 3, 0);
437 					dib0070_write_reg(state, 0x1d, 0xFFFF);
438 				} else
439 					dib0070_set_ctrl_lo5(fe, 5, 4, 3, 1);
440 			}
441 
442 			dib0070_write_reg(state, 0x20,
443 				0x0040 | 0x0020 | 0x0010 | 0x0008 | 0x0002 | 0x0001 | state->current_tune_table_index->tuner_enable);
444 
445 			dprintk("REFDIV: %hd, FREF: %d\n", REFDIV, FREF);
446 			dprintk("FBDIV: %d, Rest: %d\n", FBDiv, Rest);
447 			dprintk("Num: %hd, Den: %hd, SD: %hd\n", (u16) Rest, Den, (state->lo4 >> 12) & 0x1);
448 			dprintk("HFDIV code: %hd\n", state->current_tune_table_index->hfdiv);
449 			dprintk("VCO = %hd\n", state->current_tune_table_index->vco_band);
450 			dprintk("VCOF: ((%hd*%d) << 1))\n", state->current_tune_table_index->vco_multi, freq);
451 
452 			*tune_state = CT_TUNER_STEP_0;
453 		} else { /* we are already tuned to this frequency - the configuration is correct  */
454 			ret = 50; /* wakeup time */
455 			*tune_state = CT_TUNER_STEP_5;
456 		}
457 	} else if ((*tune_state > CT_TUNER_START) && (*tune_state < CT_TUNER_STEP_4)) {
458 
459 		ret = dib0070_captrim(state, tune_state);
460 
461 	} else if (*tune_state == CT_TUNER_STEP_4) {
462 		const struct dib0070_wbd_gain_cfg *tmp = state->cfg->wbd_gain;
463 		if (tmp != NULL) {
464 			while (freq/1000 > tmp->freq) /* find the right one */
465 				tmp++;
466 			dib0070_write_reg(state, 0x0f,
467 				(0 << 15) | (1 << 14) | (3 << 12)
468 				| (tmp->wbd_gain_val << 9) | (0 << 8) | (1 << 7)
469 				| (state->current_tune_table_index->wbdmux << 0));
470 			state->wbd_gain_current = tmp->wbd_gain_val;
471 		} else {
472 			dib0070_write_reg(state, 0x0f,
473 					  (0 << 15) | (1 << 14) | (3 << 12)
474 					  | (6 << 9) | (0 << 8) | (1 << 7)
475 					  | (state->current_tune_table_index->wbdmux << 0));
476 			state->wbd_gain_current = 6;
477 		}
478 
479 		dib0070_write_reg(state, 0x06, 0x3fff);
480 		dib0070_write_reg(state, 0x07,
481 				  (state->current_tune_table_index->switch_trim << 11) | (7 << 8) | (state->lna_match->lna_band << 3) | (3 << 0));
482 		dib0070_write_reg(state, 0x08, (state->lna_match->lna_band << 10) | (3 << 7) | (127));
483 		dib0070_write_reg(state, 0x0d, 0x0d80);
484 
485 
486 		dib0070_write_reg(state, 0x18,   0x07ff);
487 		dib0070_write_reg(state, 0x17, 0x0033);
488 
489 
490 		*tune_state = CT_TUNER_STEP_5;
491 	} else if (*tune_state == CT_TUNER_STEP_5) {
492 		dib0070_set_bandwidth(fe);
493 		*tune_state = CT_TUNER_STOP;
494 	} else {
495 		ret = FE_CALLBACK_TIME_NEVER; /* tuner finished, time to call again infinite */
496 	}
497 	return ret;
498 }
499 
500 
501 static int dib0070_tune(struct dvb_frontend *fe)
502 {
503 	struct dib0070_state *state = fe->tuner_priv;
504 	uint32_t ret;
505 
506 	state->tune_state = CT_TUNER_START;
507 
508 	do {
509 		ret = dib0070_tune_digital(fe);
510 		if (ret != FE_CALLBACK_TIME_NEVER)
511 			msleep(ret/10);
512 		else
513 		break;
514 	} while (state->tune_state != CT_TUNER_STOP);
515 
516 	return 0;
517 }
518 
519 static int dib0070_wakeup(struct dvb_frontend *fe)
520 {
521 	struct dib0070_state *state = fe->tuner_priv;
522 	if (state->cfg->sleep)
523 		state->cfg->sleep(fe, 0);
524 	return 0;
525 }
526 
527 static int dib0070_sleep(struct dvb_frontend *fe)
528 {
529 	struct dib0070_state *state = fe->tuner_priv;
530 	if (state->cfg->sleep)
531 		state->cfg->sleep(fe, 1);
532 	return 0;
533 }
534 
535 u8 dib0070_get_rf_output(struct dvb_frontend *fe)
536 {
537 	struct dib0070_state *state = fe->tuner_priv;
538 	return (dib0070_read_reg(state, 0x07) >> 11) & 0x3;
539 }
540 EXPORT_SYMBOL(dib0070_get_rf_output);
541 
542 int dib0070_set_rf_output(struct dvb_frontend *fe, u8 no)
543 {
544 	struct dib0070_state *state = fe->tuner_priv;
545 	u16 rxrf2 = dib0070_read_reg(state, 0x07) & 0xfe7ff;
546 	if (no > 3)
547 		no = 3;
548 	if (no < 1)
549 		no = 1;
550 	return dib0070_write_reg(state, 0x07, rxrf2 | (no << 11));
551 }
552 EXPORT_SYMBOL(dib0070_set_rf_output);
553 
554 static const u16 dib0070_p1f_defaults[] =
555 
556 {
557 	7, 0x02,
558 		0x0008,
559 		0x0000,
560 		0x0000,
561 		0x0000,
562 		0x0000,
563 		0x0002,
564 		0x0100,
565 
566 	3, 0x0d,
567 		0x0d80,
568 		0x0001,
569 		0x0000,
570 
571 	4, 0x11,
572 		0x0000,
573 		0x0103,
574 		0x0000,
575 		0x0000,
576 
577 	3, 0x16,
578 		0x0004 | 0x0040,
579 		0x0030,
580 		0x07ff,
581 
582 	6, 0x1b,
583 		0x4112,
584 		0xff00,
585 		0xc07f,
586 		0x0000,
587 		0x0180,
588 		0x4000 | 0x0800 | 0x0040 | 0x0020 | 0x0010 | 0x0008 | 0x0002 | 0x0001,
589 
590 	0,
591 };
592 
593 static u16 dib0070_read_wbd_offset(struct dib0070_state *state, u8 gain)
594 {
595 	u16 tuner_en = dib0070_read_reg(state, 0x20);
596 	u16 offset;
597 
598 	dib0070_write_reg(state, 0x18, 0x07ff);
599 	dib0070_write_reg(state, 0x20, 0x0800 | 0x4000 | 0x0040 | 0x0020 | 0x0010 | 0x0008 | 0x0002 | 0x0001);
600 	dib0070_write_reg(state, 0x0f, (1 << 14) | (2 << 12) | (gain << 9) | (1 << 8) | (1 << 7) | (0 << 0));
601 	msleep(9);
602 	offset = dib0070_read_reg(state, 0x19);
603 	dib0070_write_reg(state, 0x20, tuner_en);
604 	return offset;
605 }
606 
607 static void dib0070_wbd_offset_calibration(struct dib0070_state *state)
608 {
609 	u8 gain;
610 	for (gain = 6; gain < 8; gain++) {
611 		state->wbd_offset_3_3[gain - 6] = ((dib0070_read_wbd_offset(state, gain) * 8 * 18 / 33 + 1) / 2);
612 		dprintk("Gain: %d, WBDOffset (3.3V) = %hd\n", gain, state->wbd_offset_3_3[gain-6]);
613 	}
614 }
615 
616 u16 dib0070_wbd_offset(struct dvb_frontend *fe)
617 {
618 	struct dib0070_state *state = fe->tuner_priv;
619 	const struct dib0070_wbd_gain_cfg *tmp = state->cfg->wbd_gain;
620 	u32 freq = fe->dtv_property_cache.frequency/1000;
621 
622 	if (tmp != NULL) {
623 		while (freq/1000 > tmp->freq) /* find the right one */
624 			tmp++;
625 		state->wbd_gain_current = tmp->wbd_gain_val;
626 	} else
627 		state->wbd_gain_current = 6;
628 
629 	return state->wbd_offset_3_3[state->wbd_gain_current - 6];
630 }
631 EXPORT_SYMBOL(dib0070_wbd_offset);
632 
633 #define pgm_read_word(w) (*w)
634 static int dib0070_reset(struct dvb_frontend *fe)
635 {
636 	struct dib0070_state *state = fe->tuner_priv;
637 	u16 l, r, *n;
638 
639 	HARD_RESET(state);
640 
641 
642 #ifndef FORCE_SBAND_TUNER
643 	if ((dib0070_read_reg(state, 0x22) >> 9) & 0x1)
644 		state->revision = (dib0070_read_reg(state, 0x1f) >> 8) & 0xff;
645 	else
646 #else
647 #warning forcing SBAND
648 #endif
649 	state->revision = DIB0070S_P1A;
650 
651 	/* P1F or not */
652 	dprintk("Revision: %x\n", state->revision);
653 
654 	if (state->revision == DIB0070_P1D) {
655 		dprintk("Error: this driver is not to be used meant for P1D or earlier\n");
656 		return -EINVAL;
657 	}
658 
659 	n = (u16 *) dib0070_p1f_defaults;
660 	l = pgm_read_word(n++);
661 	while (l) {
662 		r = pgm_read_word(n++);
663 		do {
664 			dib0070_write_reg(state, (u8)r, pgm_read_word(n++));
665 			r++;
666 		} while (--l);
667 		l = pgm_read_word(n++);
668 	}
669 
670 	if (state->cfg->force_crystal_mode != 0)
671 		r = state->cfg->force_crystal_mode;
672 	else if (state->cfg->clock_khz >= 24000)
673 		r = 1;
674 	else
675 		r = 2;
676 
677 
678 	r |= state->cfg->osc_buffer_state << 3;
679 
680 	dib0070_write_reg(state, 0x10, r);
681 	dib0070_write_reg(state, 0x1f, (1 << 8) | ((state->cfg->clock_pad_drive & 0xf) << 5));
682 
683 	if (state->cfg->invert_iq) {
684 		r = dib0070_read_reg(state, 0x02) & 0xffdf;
685 		dib0070_write_reg(state, 0x02, r | (1 << 5));
686 	}
687 
688 	if (state->revision == DIB0070S_P1A)
689 		dib0070_set_ctrl_lo5(fe, 2, 4, 3, 0);
690 	else
691 		dib0070_set_ctrl_lo5(fe, 5, 4, state->cfg->charge_pump,
692 				     state->cfg->enable_third_order_filter);
693 
694 	dib0070_write_reg(state, 0x01, (54 << 9) | 0xc8);
695 
696 	dib0070_wbd_offset_calibration(state);
697 
698 	return 0;
699 }
700 
701 static int dib0070_get_frequency(struct dvb_frontend *fe, u32 *frequency)
702 {
703 	struct dib0070_state *state = fe->tuner_priv;
704 
705 	*frequency = 1000 * state->current_rf;
706 	return 0;
707 }
708 
709 static void dib0070_release(struct dvb_frontend *fe)
710 {
711 	kfree(fe->tuner_priv);
712 	fe->tuner_priv = NULL;
713 }
714 
715 static const struct dvb_tuner_ops dib0070_ops = {
716 	.info = {
717 		.name              = "DiBcom DiB0070",
718 		.frequency_min_hz  =  45 * MHz,
719 		.frequency_max_hz  = 860 * MHz,
720 		.frequency_step_hz =   1 * kHz,
721 	},
722 	.release       = dib0070_release,
723 
724 	.init          = dib0070_wakeup,
725 	.sleep         = dib0070_sleep,
726 	.set_params    = dib0070_tune,
727 
728 	.get_frequency = dib0070_get_frequency,
729 //      .get_bandwidth = dib0070_get_bandwidth
730 };
731 
732 struct dvb_frontend *dib0070_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct dib0070_config *cfg)
733 {
734 	struct dib0070_state *state = kzalloc(sizeof(struct dib0070_state), GFP_KERNEL);
735 	if (state == NULL)
736 		return NULL;
737 
738 	state->cfg = cfg;
739 	state->i2c = i2c;
740 	state->fe  = fe;
741 	mutex_init(&state->i2c_buffer_lock);
742 	fe->tuner_priv = state;
743 
744 	if (dib0070_reset(fe) != 0)
745 		goto free_mem;
746 
747 	pr_info("DiB0070: successfully identified\n");
748 	memcpy(&fe->ops.tuner_ops, &dib0070_ops, sizeof(struct dvb_tuner_ops));
749 
750 	fe->tuner_priv = state;
751 	return fe;
752 
753 free_mem:
754 	kfree(state);
755 	fe->tuner_priv = NULL;
756 	return NULL;
757 }
758 EXPORT_SYMBOL(dib0070_attach);
759 
760 MODULE_AUTHOR("Patrick Boettcher <patrick.boettcher@posteo.de>");
761 MODULE_DESCRIPTION("Driver for the DiBcom 0070 base-band RF Tuner");
762 MODULE_LICENSE("GPL");
763