blob: 2eb9bdb4dbb3c1e39ce0880740ce03094b5fe102 [file] [log] [blame]
Patrick Boettcher01373a52007-07-30 12:49:04 -03001/*
2 * Linux-DVB Driver for DiBcom's DiB0070 base-band RF Tuner.
3 *
Patrick Boettcher7e5ce652009-08-03 13:43:40 -03004 * Copyright (C) 2005-9 DiBcom (http://www.dibcom.fr/)
Patrick Boettcher01373a52007-07-30 12:49:04 -03005 *
6 * This program is free software; you can redistribute it and/or
Patrick Boettcher7e5ce652009-08-03 13:43:40 -03007 * 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 *
Patrick Boettcher01373a52007-07-30 12:49:04 -030025 */
Patrick Boettcher7e5ce652009-08-03 13:43:40 -030026
Patrick Boettcher01373a52007-07-30 12:49:04 -030027#include <linux/kernel.h>
28#include <linux/i2c.h>
29
30#include "dvb_frontend.h"
31
32#include "dib0070.h"
33#include "dibx000_common.h"
34
35static int debug;
36module_param(debug, int, 0644);
37MODULE_PARM_DESC(debug, "turn on debugging (default: 0)");
38
Patrick Boettcher7e5ce652009-08-03 13:43:40 -030039#define dprintk(args...) do { \
40 if (debug) { \
41 printk(KERN_DEBUG "DiB0070: "); \
42 printk(args); \
43 printk("\n"); \
44 } \
45} while (0)
Patrick Boettcher01373a52007-07-30 12:49:04 -030046
47#define DIB0070_P1D 0x00
48#define DIB0070_P1F 0x01
49#define DIB0070_P1G 0x03
50#define DIB0070S_P1A 0x02
51
Patrick Boettcher7e5ce652009-08-03 13:43:40 -030052enum frontend_tune_state {
53 CT_TUNER_START = 10,
54 CT_TUNER_STEP_0,
55 CT_TUNER_STEP_1,
56 CT_TUNER_STEP_2,
57 CT_TUNER_STEP_3,
58 CT_TUNER_STEP_4,
59 CT_TUNER_STEP_5,
60 CT_TUNER_STEP_6,
61 CT_TUNER_STEP_7,
62 CT_TUNER_STOP,
63};
64
65#define FE_CALLBACK_TIME_NEVER 0xffffffff
66
Patrick Boettcher01373a52007-07-30 12:49:04 -030067struct dib0070_state {
68 struct i2c_adapter *i2c;
69 struct dvb_frontend *fe;
70 const struct dib0070_config *cfg;
71 u16 wbd_ff_offset;
72 u8 revision;
Patrick Boettcher7e5ce652009-08-03 13:43:40 -030073
74 enum frontend_tune_state tune_state;
75 u32 current_rf;
76
77 /* for the captrim binary search */
78 s8 step;
79 u16 adc_diff;
80
81 s8 captrim;
82 s8 fcaptrim;
83 u16 lo4;
84
85 const struct dib0070_tuning *current_tune_table_index;
86 const struct dib0070_lna_match *lna_match;
87
88 u8 wbd_gain_current;
89 u16 wbd_offset_3_3[2];
Patrick Boettcher01373a52007-07-30 12:49:04 -030090};
91
92static uint16_t dib0070_read_reg(struct dib0070_state *state, u8 reg)
93{
94 u8 b[2];
95 struct i2c_msg msg[2] = {
96 { .addr = state->cfg->i2c_address, .flags = 0, .buf = &reg, .len = 1 },
97 { .addr = state->cfg->i2c_address, .flags = I2C_M_RD, .buf = b, .len = 2 },
98 };
99 if (i2c_transfer(state->i2c, msg, 2) != 2) {
100 printk(KERN_WARNING "DiB0070 I2C read failed\n");
101 return 0;
102 }
103 return (b[0] << 8) | b[1];
104}
105
106static int dib0070_write_reg(struct dib0070_state *state, u8 reg, u16 val)
107{
108 u8 b[3] = { reg, val >> 8, val & 0xff };
109 struct i2c_msg msg = { .addr = state->cfg->i2c_address, .flags = 0, .buf = b, .len = 3 };
110 if (i2c_transfer(state->i2c, &msg, 1) != 1) {
111 printk(KERN_WARNING "DiB0070 I2C write failed\n");
112 return -EREMOTEIO;
113 }
114 return 0;
115}
116
Patrick Boettcher7e5ce652009-08-03 13:43:40 -0300117#define HARD_RESET(state) do { \
118 state->cfg->sleep(state->fe, 0); \
119 if (state->cfg->reset) { \
120 state->cfg->reset(state->fe,1); msleep(10); \
121 state->cfg->reset(state->fe,0); msleep(10); \
122 } \
123} while (0)
Patrick Boettcher01373a52007-07-30 12:49:04 -0300124
125static int dib0070_set_bandwidth(struct dvb_frontend *fe, struct dvb_frontend_parameters *ch)
126{
Patrick Boettcher7e5ce652009-08-03 13:43:40 -0300127 struct dib0070_state *st = fe->tuner_priv;
128 u16 tmp = dib0070_read_reg(st, 0x02) & 0x3fff;
Patrick Boettcher01373a52007-07-30 12:49:04 -0300129
Patrick Boettcher7e5ce652009-08-03 13:43:40 -0300130 if (fe->dtv_property_cache.bandwidth_hz/1000 > 7000)
131 tmp |= (0 << 14);
132 else if (fe->dtv_property_cache.bandwidth_hz/1000 > 6000)
133 tmp |= (1 << 14);
134 else if (fe->dtv_property_cache.bandwidth_hz/1000 > 5000)
135 tmp |= (2 << 14);
136 else
137 tmp |= (3 << 14);
138
139 dib0070_write_reg(st, 0x02, tmp);
140
141 /* sharpen the BB filter in ISDB-T to have higher immunity to adjacent channels */
142 if (fe->dtv_property_cache.delivery_system == SYS_ISDBT) {
143 u16 value = dib0070_read_reg(st, 0x17);
144
145 dib0070_write_reg(st, 0x17, value & 0xfffc);
146 tmp = dib0070_read_reg(st, 0x01) & 0x01ff;
147 dib0070_write_reg(st, 0x01, tmp | (60 << 9));
148
149 dib0070_write_reg(st, 0x17, value);
150 }
Patrick Boettcher01373a52007-07-30 12:49:04 -0300151 return 0;
152}
153
Patrick Boettcher7e5ce652009-08-03 13:43:40 -0300154static int dib0070_captrim(struct dib0070_state *st, enum frontend_tune_state *tune_state)
Patrick Boettcher01373a52007-07-30 12:49:04 -0300155{
Patrick Boettcher7e5ce652009-08-03 13:43:40 -0300156 int8_t step_sign;
157 u16 adc;
158 int ret = 0;
Patrick Boettcher01373a52007-07-30 12:49:04 -0300159
Patrick Boettcher7e5ce652009-08-03 13:43:40 -0300160 if (*tune_state == CT_TUNER_STEP_0) {
Patrick Boettcher01373a52007-07-30 12:49:04 -0300161
Patrick Boettcher7e5ce652009-08-03 13:43:40 -0300162 dib0070_write_reg(st, 0x0f, 0xed10);
163 dib0070_write_reg(st, 0x17, 0x0034);
Patrick Boettcher01373a52007-07-30 12:49:04 -0300164
Patrick Boettcher7e5ce652009-08-03 13:43:40 -0300165 dib0070_write_reg(st, 0x18, 0x0032);
166 st->step = st->captrim = st->fcaptrim = 64;
167 st->adc_diff = 3000;
168 ret = 20;
Patrick Boettcher01373a52007-07-30 12:49:04 -0300169
Patrick Boettcher7e5ce652009-08-03 13:43:40 -0300170 *tune_state = CT_TUNER_STEP_1;
171 } else if (*tune_state == CT_TUNER_STEP_1) {
172 st->step /= 2;
173 dib0070_write_reg(st, 0x14, st->lo4 | st->captrim);
174 ret = 15;
Patrick Boettcher01373a52007-07-30 12:49:04 -0300175
Patrick Boettcher7e5ce652009-08-03 13:43:40 -0300176 *tune_state = CT_TUNER_STEP_2;
177 } else if (*tune_state == CT_TUNER_STEP_2) {
Patrick Boettcher01373a52007-07-30 12:49:04 -0300178
Patrick Boettcher01373a52007-07-30 12:49:04 -0300179 adc = dib0070_read_reg(st, 0x19);
180
Patrick Boettcher7e5ce652009-08-03 13:43:40 -0300181 dprintk( "CAPTRIM=%hd; ADC = %hd (ADC) & %dmV", st->captrim, adc, (u32) adc*(u32)1800/(u32)1024);
Patrick Boettcher01373a52007-07-30 12:49:04 -0300182
183 if (adc >= 400) {
184 adc -= 400;
185 step_sign = -1;
186 } else {
187 adc = 400 - adc;
188 step_sign = 1;
189 }
190
Patrick Boettcher7e5ce652009-08-03 13:43:40 -0300191 if (adc < st->adc_diff) {
192 dprintk( "CAPTRIM=%hd is closer to target (%hd/%hd)", st->captrim, adc, st->adc_diff);
193 st->adc_diff = adc;
194 st->fcaptrim = st->captrim;
Patrick Boettcher01373a52007-07-30 12:49:04 -0300195
196
197
198 }
Patrick Boettcher7e5ce652009-08-03 13:43:40 -0300199 st->captrim += (step_sign * st->step);
Patrick Boettcher01373a52007-07-30 12:49:04 -0300200
Patrick Boettcher7e5ce652009-08-03 13:43:40 -0300201 if (st->step >= 1)
202 *tune_state = CT_TUNER_STEP_1;
203 else
204 *tune_state = CT_TUNER_STEP_3;
205
206 } else if (*tune_state == CT_TUNER_STEP_3) {
207 dib0070_write_reg(st, 0x14, st->lo4 | st->fcaptrim);
208 dib0070_write_reg(st, 0x18, 0x07ff);
209 *tune_state = CT_TUNER_STEP_4;
210 }
211
212 return ret;
Patrick Boettcher01373a52007-07-30 12:49:04 -0300213}
214
Patrick Boettcher7e5ce652009-08-03 13:43:40 -0300215static int dib0070_set_ctrl_lo5(struct dvb_frontend *fe, u8 vco_bias_trim, u8 hf_div_trim, u8 cp_current, u8 third_order_filt)
216{
217 struct dib0070_state *state = fe->tuner_priv;
218 u16 lo5 = (third_order_filt << 14) | (0 << 13) | (1 << 12) | (3 << 9) | (cp_current << 6) | (hf_div_trim << 3) | (vco_bias_trim << 0);
219 dprintk( "CTRL_LO5: 0x%x", lo5);
220 return dib0070_write_reg(state, 0x15, lo5);
221}
222
223struct dib0070_tuning
224{
225 u32 max_freq; /* for every frequency less than or equal to that field: this information is correct */
226 u8 switch_trim;
227 u8 vco_band;
228 u8 hfdiv;
229 u8 vco_multi;
230 u8 presc;
231 u8 wbdmux;
232 u16 tuner_enable;
233};
234
235struct dib0070_lna_match
236{
237 u32 max_freq; /* for every frequency less than or equal to that field: this information is correct */
238 u8 lna_band;
239};
240
241static const struct dib0070_tuning dib0070s_tuning_table[] =
242
243{
244 { 570000, 2, 1, 3, 6, 6, 2, 0x4000 | 0x0800 }, /* UHF */
245 { 700000, 2, 0, 2, 4, 2, 2, 0x4000 | 0x0800 },
246 { 863999, 2, 1, 2, 4, 2, 2, 0x4000 | 0x0800 },
247 { 1500000, 0, 1, 1, 2, 2, 4, 0x2000 | 0x0400 }, /* LBAND */
248 { 1600000, 0, 1, 1, 2, 2, 4, 0x2000 | 0x0400 },
249 { 2000000, 0, 1, 1, 2, 2, 4, 0x2000 | 0x0400 },
250 { 0xffffffff, 0, 0, 8, 1, 2, 1, 0x8000 | 0x1000 }, /* SBAND */
251};
252
253static const struct dib0070_tuning dib0070_tuning_table[] =
254
255{
256 { 115000, 1, 0, 7, 24, 2, 1, 0x8000 | 0x1000 }, /* FM below 92MHz cannot be tuned */
257 { 179500, 1, 0, 3, 16, 2, 1, 0x8000 | 0x1000 }, /* VHF */
258 { 189999, 1, 1, 3, 16, 2, 1, 0x8000 | 0x1000 },
259 { 250000, 1, 0, 6, 12, 2, 1, 0x8000 | 0x1000 },
260 { 569999, 2, 1, 5, 6, 2, 2, 0x4000 | 0x0800 }, /* UHF */
261 { 699999, 2, 0 ,1, 4, 2, 2, 0x4000 | 0x0800 },
262 { 863999, 2, 1, 1, 4, 2, 2, 0x4000 | 0x0800 },
263 { 0xffffffff, 0, 1, 0, 2, 2, 4, 0x2000 | 0x0400 }, /* LBAND or everything higher than UHF */
264};
265
266static const struct dib0070_lna_match dib0070_lna_flip_chip[] =
267
268{
269 { 180000, 0 }, /* VHF */
270 { 188000, 1 },
271 { 196400, 2 },
272 { 250000, 3 },
273 { 550000, 0 }, /* UHF */
274 { 590000, 1 },
275 { 666000, 3 },
276 { 864000, 5 },
277 { 1500000, 0 }, /* LBAND or everything higher than UHF */
278 { 1600000, 1 },
279 { 2000000, 3 },
280 { 0xffffffff, 7 },
281};
282
283static const struct dib0070_lna_match dib0070_lna[] =
284
285{
286 { 180000, 0 }, /* VHF */
287 { 188000, 1 },
288 { 196400, 2 },
289 { 250000, 3 },
290 { 550000, 2 }, /* UHF */
291 { 650000, 3 },
292 { 750000, 5 },
293 { 850000, 6 },
294 { 864000, 7 },
295 { 1500000, 0 }, /* LBAND or everything higher than UHF */
296 { 1600000, 1 },
297 { 2000000, 3 },
298 { 0xffffffff, 7 },
299};
300
Patrick Boettcher01373a52007-07-30 12:49:04 -0300301#define LPF 100 // define for the loop filter 100kHz by default 16-07-06
Patrick Boettcher01373a52007-07-30 12:49:04 -0300302static int dib0070_tune_digital(struct dvb_frontend *fe, struct dvb_frontend_parameters *ch)
303{
Patrick Boettcher7e5ce652009-08-03 13:43:40 -0300304 struct dib0070_state *st = fe->tuner_priv;
Patrick Boettcher01373a52007-07-30 12:49:04 -0300305
Patrick Boettcher7e5ce652009-08-03 13:43:40 -0300306 const struct dib0070_tuning *tune;
307 const struct dib0070_lna_match *lna_match;
Patrick Boettcher01373a52007-07-30 12:49:04 -0300308
Patrick Boettcher7e5ce652009-08-03 13:43:40 -0300309 enum frontend_tune_state *tune_state = &st->tune_state;
310 int ret = 10; /* 1ms is the default delay most of the time */
Patrick Boettcher01373a52007-07-30 12:49:04 -0300311
Patrick Boettcher7e5ce652009-08-03 13:43:40 -0300312 u8 band = (u8)BAND_OF_FREQUENCY(ch->frequency/1000);
313 u32 freq = ch->frequency/1000 + (band == BAND_VHF ? st->cfg->freq_offset_khz_vhf : st->cfg->freq_offset_khz_uhf);
Patrick Boettcher01373a52007-07-30 12:49:04 -0300314
Patrick Boettcher7e5ce652009-08-03 13:43:40 -0300315
316
317
318
319#ifdef CONFIG_STANDARD_ISDBT
320 if (fe->dtv_property_cache.delivery_system == SYS_ISDBT && ch->u.isdbt.sb_mode == 1)
321 if ( ( (ch->u.isdbt.sb_conn_total_seg % 2) && (ch->u.isdbt.sb_wanted_seg == ((ch->u.isdbt.sb_conn_total_seg/2) + 1) ) ) ||
322 ( ( (ch->u.isdbt.sb_conn_total_seg % 2) == 0) && (ch->u.isdbt.sb_wanted_seg == (ch->u.isdbt.sb_conn_total_seg/2) ) ) ||
323 ( ( (ch->u.isdbt.sb_conn_total_seg % 2) == 0) && (ch->u.isdbt.sb_wanted_seg == ((ch->u.isdbt.sb_conn_total_seg/2)+1))) )
324 freq += 850;
325#endif
326 if (st->current_rf != freq) {
327
328 switch (st->revision) {
329 case DIB0070S_P1A:
330 tune = dib0070s_tuning_table;
331 lna_match = dib0070_lna;
332 break;
333 default:
334 tune = dib0070_tuning_table;
335 if (st->cfg->flip_chip)
336 lna_match = dib0070_lna_flip_chip;
337 else
338 lna_match = dib0070_lna;
339 break;
340 }
341 while (freq > tune->max_freq) /* find the right one */
342 tune++;
343 while (freq > lna_match->max_freq) /* find the right one */
344 lna_match++;
345
346 st->current_tune_table_index = tune;
347 st->lna_match = lna_match;
348 }
349
350 if (*tune_state == CT_TUNER_START) {
Patrick Boettcher01373a52007-07-30 12:49:04 -0300351 dprintk( "Tuning for Band: %hd (%d kHz)", band, freq);
Patrick Boettcher7e5ce652009-08-03 13:43:40 -0300352 if (st->current_rf != freq) {
353 u8 REFDIV;
354 u32 FBDiv, Rest, FREF, VCOF_kHz;
355 u8 Den;
356
357 st->current_rf = freq;
358 st->lo4 = (st->current_tune_table_index->vco_band << 11) | (st->current_tune_table_index->hfdiv << 7);
Patrick Boettcher01373a52007-07-30 12:49:04 -0300359
360
Patrick Boettcher7e5ce652009-08-03 13:43:40 -0300361 dib0070_write_reg(st, 0x17, 0x30);
Patrick Boettcher01373a52007-07-30 12:49:04 -0300362
Patrick Boettcher01373a52007-07-30 12:49:04 -0300363
Patrick Boettcher7e5ce652009-08-03 13:43:40 -0300364 VCOF_kHz = st->current_tune_table_index->vco_multi * freq * 2;
Patrick Boettcher01373a52007-07-30 12:49:04 -0300365
Patrick Boettcher7e5ce652009-08-03 13:43:40 -0300366 switch (band) {
367 case BAND_VHF:
368 REFDIV = (u8) ((st->cfg->clock_khz + 9999) / 10000);
Patrick Boettcher01373a52007-07-30 12:49:04 -0300369 break;
Patrick Boettcher7e5ce652009-08-03 13:43:40 -0300370 case BAND_FM:
371 REFDIV = (u8) ((st->cfg->clock_khz) / 1000);
372 break;
373 default:
374 REFDIV = (u8) ( st->cfg->clock_khz / 10000);
375 break;
376 }
377 FREF = st->cfg->clock_khz / REFDIV;
Patrick Boettcher01373a52007-07-30 12:49:04 -0300378
379
380
Patrick Boettcher7e5ce652009-08-03 13:43:40 -0300381 switch (st->revision) {
382 case DIB0070S_P1A:
383 FBDiv = (VCOF_kHz / st->current_tune_table_index->presc / FREF);
384 Rest = (VCOF_kHz / st->current_tune_table_index->presc) - FBDiv * FREF;
385 break;
Patrick Boettcher01373a52007-07-30 12:49:04 -0300386
Patrick Boettcher7e5ce652009-08-03 13:43:40 -0300387 case DIB0070_P1G:
388 case DIB0070_P1F:
389 default:
390 FBDiv = (freq / (FREF / 2));
391 Rest = 2 * freq - FBDiv * FREF;
392 break;
393 }
Patrick Boettcher01373a52007-07-30 12:49:04 -0300394
395
Patrick Boettcher7e5ce652009-08-03 13:43:40 -0300396 if (Rest < LPF) Rest = 0;
397 else if (Rest < 2 * LPF) Rest = 2 * LPF;
398 else if (Rest > (FREF - LPF)) { Rest = 0 ; FBDiv += 1; }
399 else if (Rest > (FREF - 2 * LPF)) Rest = FREF - 2 * LPF;
400 Rest = (Rest * 6528) / (FREF / 10);
Patrick Boettcher01373a52007-07-30 12:49:04 -0300401
Patrick Boettcher7e5ce652009-08-03 13:43:40 -0300402 Den = 1;
403 if (Rest > 0) {
404 st->lo4 |= (1 << 14) | (1 << 12);
Patrick Boettcher01373a52007-07-30 12:49:04 -0300405 Den = 255;
Patrick Boettcher7e5ce652009-08-03 13:43:40 -0300406 }
407
408
409 dib0070_write_reg(st, 0x11, (u16)FBDiv);
410 dib0070_write_reg(st, 0x12, (Den << 8) | REFDIV);
411 dib0070_write_reg(st, 0x13, (u16) Rest);
412
413 if (st->revision == DIB0070S_P1A) {
414
415 if (band == BAND_SBAND) {
416 dib0070_set_ctrl_lo5(fe, 2, 4, 3, 0);
417 dib0070_write_reg(st, 0x1d,0xFFFF);
418 } else
419 dib0070_set_ctrl_lo5(fe, 5, 4, 3, 1);
420 }
421
422
423 dib0070_write_reg(st, 0x20, 0x0040 | 0x0020 | 0x0010 | 0x0008 | 0x0002 | 0x0001 | st->current_tune_table_index->tuner_enable);
424
425 dprintk( "REFDIV: %hd, FREF: %d", REFDIV, FREF);
426 dprintk( "FBDIV: %d, Rest: %d", FBDiv, Rest);
427 dprintk( "Num: %hd, Den: %hd, SD: %hd",(u16) Rest, Den, (st->lo4 >> 12) & 0x1);
428 dprintk( "HFDIV code: %hd", st->current_tune_table_index->hfdiv);
429 dprintk( "VCO = %hd", st->current_tune_table_index->vco_band);
430 dprintk( "VCOF: ((%hd*%d) << 1))", st->current_tune_table_index->vco_multi, freq);
431
432 *tune_state = CT_TUNER_STEP_0;
433 } else { /* we are already tuned to this frequency - the configuration is correct */
434 ret = 50; /* wakeup time */
435 *tune_state = CT_TUNER_STEP_5;
Patrick Boettcher01373a52007-07-30 12:49:04 -0300436 }
Patrick Boettcher7e5ce652009-08-03 13:43:40 -0300437 } else if ((*tune_state > CT_TUNER_START) && (*tune_state < CT_TUNER_STEP_4)) {
Patrick Boettcher01373a52007-07-30 12:49:04 -0300438
Patrick Boettcher7e5ce652009-08-03 13:43:40 -0300439 ret = dib0070_captrim(st, tune_state);
Patrick Boettcher01373a52007-07-30 12:49:04 -0300440
Patrick Boettcher7e5ce652009-08-03 13:43:40 -0300441 } else if (*tune_state == CT_TUNER_STEP_4) {
442 const struct dib0070_wbd_gain_cfg *tmp = st->cfg->wbd_gain;
443 if (tmp != NULL) {
444 while (freq/1000 > tmp->freq) /* find the right one */
445 tmp++;
446 dib0070_write_reg(st, 0x0f, (0 << 15) | (1 << 14) | (3 << 12) | (tmp->wbd_gain_val << 9) | (0 << 8) | (1 << 7) | (st->current_tune_table_index->wbdmux << 0));
447 st->wbd_gain_current = tmp->wbd_gain_val;
448 } else {
449 dib0070_write_reg(st, 0x0f, (0 << 15) | (1 << 14) | (3 << 12) | (6 << 9) | (0 << 8) | (1 << 7) | (st->current_tune_table_index->wbdmux << 0));
450 st->wbd_gain_current = 6;
Patrick Boettcher01373a52007-07-30 12:49:04 -0300451 }
452
Patrick Boettcher01373a52007-07-30 12:49:04 -0300453 dib0070_write_reg(st, 0x06, 0x3fff);
Patrick Boettcher7e5ce652009-08-03 13:43:40 -0300454 dib0070_write_reg(st, 0x07, (st->current_tune_table_index->switch_trim << 11) | (7 << 8) | (st->lna_match->lna_band << 3) | (3 << 0));
455 dib0070_write_reg(st, 0x08, (st->lna_match->lna_band << 10) | (3 << 7) | (127));
Patrick Boettcher01373a52007-07-30 12:49:04 -0300456 dib0070_write_reg(st, 0x0d, 0x0d80);
457
458
459 dib0070_write_reg(st, 0x18, 0x07ff);
460 dib0070_write_reg(st, 0x17, 0x0033);
461
Patrick Boettcher7e5ce652009-08-03 13:43:40 -0300462
463 *tune_state = CT_TUNER_STEP_5;
464 } else if (*tune_state == CT_TUNER_STEP_5) {
465 dib0070_set_bandwidth(fe, ch);
466 *tune_state = CT_TUNER_STOP;
467 } else {
468 ret = FE_CALLBACK_TIME_NEVER; /* tuner finished, time to call again infinite */
469 }
470 return ret;
471}
472
473
474static int dib0070_tune(struct dvb_frontend *fe, struct dvb_frontend_parameters *p)
475{
476 struct dib0070_state *state = fe->tuner_priv;
477 uint32_t ret;
478
479 state->tune_state = CT_TUNER_START;
480
481 do {
482 ret = dib0070_tune_digital(fe, p);
483 if (ret != FE_CALLBACK_TIME_NEVER)
484 msleep(ret/10);
485 else
486 break;
487 } while (state->tune_state != CT_TUNER_STOP);
488
489 return 0;
Patrick Boettcher01373a52007-07-30 12:49:04 -0300490}
491
492static int dib0070_wakeup(struct dvb_frontend *fe)
493{
494 struct dib0070_state *st = fe->tuner_priv;
495 if (st->cfg->sleep)
496 st->cfg->sleep(fe, 0);
497 return 0;
498}
499
500static int dib0070_sleep(struct dvb_frontend *fe)
501{
502 struct dib0070_state *st = fe->tuner_priv;
503 if (st->cfg->sleep)
504 st->cfg->sleep(fe, 1);
505 return 0;
506}
507
Patrick Boettcher7e5ce652009-08-03 13:43:40 -0300508static const u16 dib0070_p1f_defaults[] =
Patrick Boettcher01373a52007-07-30 12:49:04 -0300509
510{
511 7, 0x02,
512 0x0008,
513 0x0000,
514 0x0000,
515 0x0000,
516 0x0000,
517 0x0002,
518 0x0100,
519
520 3, 0x0d,
521 0x0d80,
522 0x0001,
523 0x0000,
524
525 4, 0x11,
526 0x0000,
527 0x0103,
528 0x0000,
529 0x0000,
530
531 3, 0x16,
532 0x0004 | 0x0040,
533 0x0030,
534 0x07ff,
535
536 6, 0x1b,
537 0x4112,
538 0xff00,
539 0xc07f,
540 0x0000,
541 0x0180,
542 0x4000 | 0x0800 | 0x0040 | 0x0020 | 0x0010 | 0x0008 | 0x0002 | 0x0001,
543
544 0,
545};
546
Patrick Boettcher7e5ce652009-08-03 13:43:40 -0300547static u16 dib0070_read_wbd_offset(struct dib0070_state *state, u8 gain)
Patrick Boettcher01373a52007-07-30 12:49:04 -0300548{
Patrick Boettcher7e5ce652009-08-03 13:43:40 -0300549 u16 tuner_en = dib0070_read_reg(state, 0x20);
550 u16 offset;
Patrick Boettcher3cb2c392008-01-25 07:25:20 -0300551
Patrick Boettcher7e5ce652009-08-03 13:43:40 -0300552 dib0070_write_reg(state, 0x18, 0x07ff);
553 dib0070_write_reg(state, 0x20, 0x0800 | 0x4000 | 0x0040 | 0x0020 | 0x0010 | 0x0008 | 0x0002 | 0x0001);
554 dib0070_write_reg(state, 0x0f, (1 << 14) | (2 << 12) | (gain << 9) | (1 << 8) | (1 << 7) | (0 << 0));
555 msleep(9);
556 offset = dib0070_read_reg(state, 0x19);
557 dib0070_write_reg(state, 0x20, tuner_en);
558 return offset;
559}
Patrick Boettcher3cb2c392008-01-25 07:25:20 -0300560
Patrick Boettcher7e5ce652009-08-03 13:43:40 -0300561static void dib0070_wbd_offset_calibration(struct dib0070_state *state)
562{
563 u8 gain;
564 for (gain = 6; gain < 8; gain++) {
565 state->wbd_offset_3_3[gain - 6] = ((dib0070_read_wbd_offset(state, gain) * 8 * 18 / 33 + 1) / 2);
566 dprintk( "Gain: %d, WBDOffset (3.3V) = %hd", gain, state->wbd_offset_3_3[gain-6]);
567 }
Patrick Boettcher01373a52007-07-30 12:49:04 -0300568}
569
570u16 dib0070_wbd_offset(struct dvb_frontend *fe)
571{
572 struct dib0070_state *st = fe->tuner_priv;
Patrick Boettcher7e5ce652009-08-03 13:43:40 -0300573 return st->wbd_offset_3_3[st->wbd_gain_current - 6];
Patrick Boettcher01373a52007-07-30 12:49:04 -0300574}
575
576EXPORT_SYMBOL(dib0070_wbd_offset);
Patrick Boettcher01373a52007-07-30 12:49:04 -0300577#define pgm_read_word(w) (*w)
Patrick Boettcher7e5ce652009-08-03 13:43:40 -0300578static int dib0070_reset(struct dvb_frontend *fe)
Patrick Boettcher01373a52007-07-30 12:49:04 -0300579{
Patrick Boettcher7e5ce652009-08-03 13:43:40 -0300580 struct dib0070_state *state = fe->tuner_priv;
Patrick Boettcher01373a52007-07-30 12:49:04 -0300581 u16 l, r, *n;
582
583 HARD_RESET(state);
584
585
586#ifndef FORCE_SBAND_TUNER
587 if ((dib0070_read_reg(state, 0x22) >> 9) & 0x1)
588 state->revision = (dib0070_read_reg(state, 0x1f) >> 8) & 0xff;
589 else
Patrick Boettcher7e5ce652009-08-03 13:43:40 -0300590#else
591#warning forcing SBAND
Patrick Boettcher01373a52007-07-30 12:49:04 -0300592#endif
593 state->revision = DIB0070S_P1A;
594
595 /* P1F or not */
596 dprintk( "Revision: %x", state->revision);
597
598 if (state->revision == DIB0070_P1D) {
599 dprintk( "Error: this driver is not to be used meant for P1D or earlier");
600 return -EINVAL;
601 }
602
603 n = (u16 *) dib0070_p1f_defaults;
604 l = pgm_read_word(n++);
605 while (l) {
606 r = pgm_read_word(n++);
607 do {
608 dib0070_write_reg(state, (u8)r, pgm_read_word(n++));
609 r++;
610 } while (--l);
611 l = pgm_read_word(n++);
612 }
613
614 if (state->cfg->force_crystal_mode != 0)
615 r = state->cfg->force_crystal_mode;
616 else if (state->cfg->clock_khz >= 24000)
617 r = 1;
618 else
619 r = 2;
620
Patrick Boettcher7e5ce652009-08-03 13:43:40 -0300621
Patrick Boettcher01373a52007-07-30 12:49:04 -0300622 r |= state->cfg->osc_buffer_state << 3;
623
624 dib0070_write_reg(state, 0x10, r);
Patrick Boettcher7e5ce652009-08-03 13:43:40 -0300625 dib0070_write_reg(state, 0x1f, (1 << 8) | ((state->cfg->clock_pad_drive & 0xf) << 5));
Patrick Boettcher01373a52007-07-30 12:49:04 -0300626
627 if (state->cfg->invert_iq) {
628 r = dib0070_read_reg(state, 0x02) & 0xffdf;
629 dib0070_write_reg(state, 0x02, r | (1 << 5));
630 }
631
Patrick Boettcher7e5ce652009-08-03 13:43:40 -0300632 if (state->revision == DIB0070S_P1A)
633 dib0070_set_ctrl_lo5(fe, 2, 4, 3, 0);
634 else
635 dib0070_set_ctrl_lo5(fe, 5, 4, state->cfg->charge_pump, state->cfg->enable_third_order_filter);
Patrick Boettcher01373a52007-07-30 12:49:04 -0300636
637 dib0070_write_reg(state, 0x01, (54 << 9) | 0xc8);
Patrick Boettcher7e5ce652009-08-03 13:43:40 -0300638
639 dib0070_wbd_offset_calibration(state);
640
641 return 0;
Patrick Boettcher01373a52007-07-30 12:49:04 -0300642}
643
644
645static int dib0070_release(struct dvb_frontend *fe)
646{
647 kfree(fe->tuner_priv);
648 fe->tuner_priv = NULL;
649 return 0;
650}
651
Patrick Boettcher7e5ce652009-08-03 13:43:40 -0300652static const struct dvb_tuner_ops dib0070_ops = {
Patrick Boettcher01373a52007-07-30 12:49:04 -0300653 .info = {
654 .name = "DiBcom DiB0070",
655 .frequency_min = 45000000,
656 .frequency_max = 860000000,
657 .frequency_step = 1000,
658 },
659 .release = dib0070_release,
660
661 .init = dib0070_wakeup,
662 .sleep = dib0070_sleep,
Patrick Boettcher7e5ce652009-08-03 13:43:40 -0300663 .set_params = dib0070_tune,
664
Patrick Boettcher01373a52007-07-30 12:49:04 -0300665// .get_frequency = dib0070_get_frequency,
666// .get_bandwidth = dib0070_get_bandwidth
667};
668
669struct dvb_frontend * dib0070_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct dib0070_config *cfg)
670{
671 struct dib0070_state *state = kzalloc(sizeof(struct dib0070_state), GFP_KERNEL);
672 if (state == NULL)
673 return NULL;
674
675 state->cfg = cfg;
676 state->i2c = i2c;
677 state->fe = fe;
678 fe->tuner_priv = state;
679
Patrick Boettcher7e5ce652009-08-03 13:43:40 -0300680 if (dib0070_reset(fe) != 0)
Patrick Boettcher01373a52007-07-30 12:49:04 -0300681 goto free_mem;
682
Patrick Boettcher01373a52007-07-30 12:49:04 -0300683 printk(KERN_INFO "DiB0070: successfully identified\n");
684 memcpy(&fe->ops.tuner_ops, &dib0070_ops, sizeof(struct dvb_tuner_ops));
685
686 fe->tuner_priv = state;
687 return fe;
688
689free_mem:
690 kfree(state);
691 fe->tuner_priv = NULL;
692 return NULL;
693}
694EXPORT_SYMBOL(dib0070_attach);
695
696MODULE_AUTHOR("Patrick Boettcher <pboettcher@dibcom.fr>");
697MODULE_DESCRIPTION("Driver for the DiBcom 0070 base-band RF Tuner");
698MODULE_LICENSE("GPL");