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(adap: state->i2c, msgs: state->msg, num: 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(lock: &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(adap: state->i2c, msgs: state->msg, num: 1) != 1) {
120 pr_warn("DiB0070 I2C write failed\n");
121 ret = -EREMOTEIO;
122 } else
123 ret = 0;
124
125 mutex_unlock(lock: &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, reg: 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, reg: 0x02, val: 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, reg: 0x17);
156
157 dib0070_write_reg(state, reg: 0x17, val: value & 0xfffc);
158 tmp = dib0070_read_reg(state, reg: 0x01) & 0x01ff;
159 dib0070_write_reg(state, reg: 0x01, val: tmp | (60 << 9));
160
161 dib0070_write_reg(state, reg: 0x17, val: 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, reg: 0x0f, val: 0xed10);
174 dib0070_write_reg(state, reg: 0x17, val: 0x0034);
175
176 dib0070_write_reg(state, reg: 0x18, val: 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, reg: 0x14, val: 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, reg: 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, reg: 0x14, val: state->lo4 | state->fcaptrim);
218 dib0070_write_reg(state, reg: 0x18, val: 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, reg: 0x15, val: 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, reg: 0x1b, val: 0xff00);
240 dib0070_write_reg(state, reg: 0x1a, val: 0x0000);
241 } else {
242 dib0070_write_reg(state, reg: 0x1b, val: 0x4112);
243 if (state->cfg->vga_filter != 0) {
244 dib0070_write_reg(state, reg: 0x1a, val: 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, reg: 0x1a, val: 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, reg: 0x17, val: 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, reg: 0x11, val: (u16)FBDiv);
432 dib0070_write_reg(state, reg: 0x12, val: (Den << 8) | REFDIV);
433 dib0070_write_reg(state, reg: 0x13, val: (u16) Rest);
434
435 if (state->revision == DIB0070S_P1A) {
436
437 if (band == BAND_SBAND) {
438 dib0070_set_ctrl_lo5(fe, vco_bias_trim: 2, hf_div_trim: 4, cp_current: 3, third_order_filt: 0);
439 dib0070_write_reg(state, reg: 0x1d, val: 0xFFFF);
440 } else
441 dib0070_set_ctrl_lo5(fe, vco_bias_trim: 5, hf_div_trim: 4, cp_current: 3, third_order_filt: 1);
442 }
443
444 dib0070_write_reg(state, reg: 0x20,
445 val: 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, reg: 0x0f,
474 val: (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, reg: 0x0f,
480 val: (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, reg: 0x06, val: 0x3fff);
487 dib0070_write_reg(state, reg: 0x07,
488 val: (state->current_tune_table_index->switch_trim << 11) | (7 << 8) | (state->lna_match->lna_band << 3) | (3 << 0));
489 dib0070_write_reg(state, reg: 0x08, val: (state->lna_match->lna_band << 10) | (3 << 7) | (127));
490 dib0070_write_reg(state, reg: 0x0d, val: 0x0d80);
491
492
493 dib0070_write_reg(state, reg: 0x18, val: 0x07ff);
494 dib0070_write_reg(state, reg: 0x17, val: 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(msecs: 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, reg: 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, reg: 0x07) & 0xfe7ff;
553 if (no > 3)
554 no = 3;
555 if (no < 1)
556 no = 1;
557 return dib0070_write_reg(state, reg: 0x07, val: 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, reg: 0x20);
603 u16 offset;
604
605 dib0070_write_reg(state, reg: 0x18, val: 0x07ff);
606 dib0070_write_reg(state, reg: 0x20, val: 0x0800 | 0x4000 | 0x0040 | 0x0020 | 0x0010 | 0x0008 | 0x0002 | 0x0001);
607 dib0070_write_reg(state, reg: 0x0f, val: (1 << 14) | (2 << 12) | (gain << 9) | (1 << 8) | (1 << 7) | (0 << 0));
608 msleep(msecs: 9);
609 offset = dib0070_read_reg(state, reg: 0x19);
610 dib0070_write_reg(state, reg: 0x20, val: 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, reg: 0x22) >> 9) & 0x1)
651 state->revision = (dib0070_read_reg(state, reg: 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, reg: (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, reg: 0x10, val: r);
688 dib0070_write_reg(state, reg: 0x1f, val: (1 << 8) | ((state->cfg->clock_pad_drive & 0xf) << 5));
689
690 if (state->cfg->invert_iq) {
691 r = dib0070_read_reg(state, reg: 0x02) & 0xffdf;
692 dib0070_write_reg(state, reg: 0x02, val: r | (1 << 5));
693 }
694
695 if (state->revision == DIB0070S_P1A)
696 dib0070_set_ctrl_lo5(fe, vco_bias_trim: 2, hf_div_trim: 4, cp_current: 3, third_order_filt: 0);
697 else
698 dib0070_set_ctrl_lo5(fe, vco_bias_trim: 5, hf_div_trim: 4, cp_current: state->cfg->charge_pump,
699 third_order_filt: state->cfg->enable_third_order_filter);
700
701 dib0070_write_reg(state, reg: 0x01, val: (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(objp: 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(size: 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(objp: 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

source code of linux/drivers/media/dvb-frontends/dib0070.c