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