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