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