blob: 2be17b93e0bd7dcf2419b263316971304f30072f [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 {
Patrick Boettcher2a6a30e2009-08-17 05:13:28 -030053 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,
Patrick Boettcher7e5ce652009-08-03 13:43:40 -030063};
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
Patrick Boettcher2a6a30e2009-08-17 05:13:28 -030074 enum frontend_tune_state tune_state;
75 u32 current_rf;
Patrick Boettcher7e5ce652009-08-03 13:43:40 -030076
Patrick Boettcher2a6a30e2009-08-17 05:13:28 -030077 /* for the captrim binary search */
Patrick Boettcher7e5ce652009-08-03 13:43:40 -030078 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
Patrick Boettcher2a6a30e2009-08-17 05:13:28 -030088 u8 wbd_gain_current;
Patrick Boettcher7e5ce652009-08-03 13:43:40 -030089 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] = {
Patrick Boettcher2a6a30e2009-08-17 05:13:28 -030096 {.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},
Patrick Boettcher01373a52007-07-30 12:49:04 -030098 };
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 };
Patrick Boettcher2a6a30e2009-08-17 05:13:28 -0300109 struct i2c_msg msg = {.addr = state->cfg->i2c_address,.flags = 0,.buf = b,.len = 3 };
Patrick Boettcher01373a52007-07-30 12:49:04 -0300110 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 Boettcher2a6a30e2009-08-17 05:13:28 -0300127 struct dib0070_state *state = fe->tuner_priv;
128 u16 tmp = dib0070_read_reg(state, 0x02) & 0x3fff;
Patrick Boettcher01373a52007-07-30 12:49:04 -0300129
Patrick Boettcher2a6a30e2009-08-17 05:13:28 -0300130 if (state->fe->dtv_property_cache.bandwidth_hz / 1000 > 7000)
131 tmp |= (0 << 14);
132 else if (state->fe->dtv_property_cache.bandwidth_hz / 1000 > 6000)
133 tmp |= (1 << 14);
134 else if (state->fe->dtv_property_cache.bandwidth_hz / 1000 > 5000)
135 tmp |= (2 << 14);
136 else
137 tmp |= (3 << 14);
Patrick Boettcher7e5ce652009-08-03 13:43:40 -0300138
Patrick Boettcher2a6a30e2009-08-17 05:13:28 -0300139 dib0070_write_reg(state, 0x02, tmp);
Patrick Boettcher7e5ce652009-08-03 13:43:40 -0300140
Patrick Boettcher2a6a30e2009-08-17 05:13:28 -0300141 /* sharpen the BB filter in ISDB-T to have higher immunity to adjacent channels */
142 if (state->fe->dtv_property_cache.delivery_system == SYS_ISDBT) {
143 u16 value = dib0070_read_reg(state, 0x17);
Patrick Boettcher7e5ce652009-08-03 13:43:40 -0300144
Patrick Boettcher2a6a30e2009-08-17 05:13:28 -0300145 dib0070_write_reg(state, 0x17, value & 0xfffc);
146 tmp = dib0070_read_reg(state, 0x01) & 0x01ff;
147 dib0070_write_reg(state, 0x01, tmp | (60 << 9));
Patrick Boettcher7e5ce652009-08-03 13:43:40 -0300148
Patrick Boettcher2a6a30e2009-08-17 05:13:28 -0300149 dib0070_write_reg(state, 0x17, value);
150 }
Patrick Boettcher01373a52007-07-30 12:49:04 -0300151 return 0;
152}
153
Patrick Boettcher2a6a30e2009-08-17 05:13:28 -0300154static int dib0070_captrim(struct dib0070_state *state, 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 Boettcher2a6a30e2009-08-17 05:13:28 -0300162 dib0070_write_reg(state, 0x0f, 0xed10);
163 dib0070_write_reg(state, 0x17, 0x0034);
Patrick Boettcher01373a52007-07-30 12:49:04 -0300164
Patrick Boettcher2a6a30e2009-08-17 05:13:28 -0300165 dib0070_write_reg(state, 0x18, 0x0032);
166 state->step = state->captrim = state->fcaptrim = 64;
167 state->adc_diff = 3000;
Patrick Boettcher7e5ce652009-08-03 13:43:40 -0300168 ret = 20;
Patrick Boettcher01373a52007-07-30 12:49:04 -0300169
Patrick Boettcher2a6a30e2009-08-17 05:13:28 -0300170 *tune_state = CT_TUNER_STEP_1;
Patrick Boettcher7e5ce652009-08-03 13:43:40 -0300171 } else if (*tune_state == CT_TUNER_STEP_1) {
Patrick Boettcher2a6a30e2009-08-17 05:13:28 -0300172 state->step /= 2;
173 dib0070_write_reg(state, 0x14, state->lo4 | state->captrim);
Patrick Boettcher7e5ce652009-08-03 13:43:40 -0300174 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 Boettcher2a6a30e2009-08-17 05:13:28 -0300179 adc = dib0070_read_reg(state, 0x19);
Patrick Boettcher01373a52007-07-30 12:49:04 -0300180
Patrick Boettcher2a6a30e2009-08-17 05:13:28 -0300181 dprintk("CAPTRIM=%hd; ADC = %hd (ADC) & %dmV", state->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 Boettcher2a6a30e2009-08-17 05:13:28 -0300191 if (adc < state->adc_diff) {
192 dprintk("CAPTRIM=%hd is closer to target (%hd/%hd)", state->captrim, adc, state->adc_diff);
193 state->adc_diff = adc;
194 state->fcaptrim = state->captrim;
Patrick Boettcher01373a52007-07-30 12:49:04 -0300195
196 }
Patrick Boettcher2a6a30e2009-08-17 05:13:28 -0300197 state->captrim += (step_sign * state->step);
Patrick Boettcher01373a52007-07-30 12:49:04 -0300198
Patrick Boettcher2a6a30e2009-08-17 05:13:28 -0300199 if (state->step >= 1)
Patrick Boettcher7e5ce652009-08-03 13:43:40 -0300200 *tune_state = CT_TUNER_STEP_1;
201 else
202 *tune_state = CT_TUNER_STEP_3;
203
204 } else if (*tune_state == CT_TUNER_STEP_3) {
Patrick Boettcher2a6a30e2009-08-17 05:13:28 -0300205 dib0070_write_reg(state, 0x14, state->lo4 | state->fcaptrim);
206 dib0070_write_reg(state, 0x18, 0x07ff);
Patrick Boettcher7e5ce652009-08-03 13:43:40 -0300207 *tune_state = CT_TUNER_STEP_4;
208 }
209
210 return ret;
Patrick Boettcher01373a52007-07-30 12:49:04 -0300211}
212
Patrick Boettcher7e5ce652009-08-03 13:43:40 -0300213static int dib0070_set_ctrl_lo5(struct dvb_frontend *fe, u8 vco_bias_trim, u8 hf_div_trim, u8 cp_current, u8 third_order_filt)
214{
215 struct dib0070_state *state = fe->tuner_priv;
Patrick Boettcher2a6a30e2009-08-17 05:13:28 -0300216 u16 lo5 = (third_order_filt << 14) | (0 << 13) | (1 << 12) | (3 << 9) | (cp_current << 6) | (hf_div_trim << 3) | (vco_bias_trim << 0);
217 dprintk("CTRL_LO5: 0x%x", lo5);
Patrick Boettcher7e5ce652009-08-03 13:43:40 -0300218 return dib0070_write_reg(state, 0x15, lo5);
219}
220
Patrick Boettcher2a6a30e2009-08-17 05:13:28 -0300221void dib0070_ctrl_agc_filter(struct dvb_frontend *fe, u8 open)
Patrick Boettcher7e5ce652009-08-03 13:43:40 -0300222{
Patrick Boettcher2a6a30e2009-08-17 05:13:28 -0300223 struct dib0070_state *state = fe->tuner_priv;
Patrick Boettcher7e5ce652009-08-03 13:43:40 -0300224
Patrick Boettcher2a6a30e2009-08-17 05:13:28 -0300225 if (open) {
226 dib0070_write_reg(state, 0x1b, 0xff00);
227 dib0070_write_reg(state, 0x1a, 0x0000);
Patrick Boettcher7e5ce652009-08-03 13:43:40 -0300228 } else {
Patrick Boettcher2a6a30e2009-08-17 05:13:28 -0300229 dib0070_write_reg(state, 0x1b, 0x4112);
230 if (state->cfg->vga_filter != 0) {
231 dib0070_write_reg(state, 0x1a, state->cfg->vga_filter);
232 dprintk("vga filter register is set to %x", state->cfg->vga_filter);
233 } else
234 dib0070_write_reg(state, 0x1a, 0x0009);
Patrick Boettcher01373a52007-07-30 12:49:04 -0300235 }
Patrick Boettcher7e5ce652009-08-03 13:43:40 -0300236}
237
Patrick Boettcher2a6a30e2009-08-17 05:13:28 -0300238EXPORT_SYMBOL(dib0070_ctrl_agc_filter);
239struct dib0070_tuning {
240 u32 max_freq; /* for every frequency less than or equal to that field: this information is correct */
241 u8 switch_trim;
242 u8 vco_band;
243 u8 hfdiv;
244 u8 vco_multi;
245 u8 presc;
246 u8 wbdmux;
247 u16 tuner_enable;
248};
249
250struct dib0070_lna_match {
251 u32 max_freq; /* for every frequency less than or equal to that field: this information is correct */
252 u8 lna_band;
253};
254
255static const struct dib0070_tuning dib0070s_tuning_table[] = {
256 {570000, 2, 1, 3, 6, 6, 2, 0x4000 | 0x0800}, /* UHF */
257 {700000, 2, 0, 2, 4, 2, 2, 0x4000 | 0x0800},
258 {863999, 2, 1, 2, 4, 2, 2, 0x4000 | 0x0800},
259 {1500000, 0, 1, 1, 2, 2, 4, 0x2000 | 0x0400}, /* LBAND */
260 {1600000, 0, 1, 1, 2, 2, 4, 0x2000 | 0x0400},
261 {2000000, 0, 1, 1, 2, 2, 4, 0x2000 | 0x0400},
262 {0xffffffff, 0, 0, 8, 1, 2, 1, 0x8000 | 0x1000}, /* SBAND */
263};
264
265static const struct dib0070_tuning dib0070_tuning_table[] = {
266 {115000, 1, 0, 7, 24, 2, 1, 0x8000 | 0x1000}, /* FM below 92MHz cannot be tuned */
267 {179500, 1, 0, 3, 16, 2, 1, 0x8000 | 0x1000}, /* VHF */
268 {189999, 1, 1, 3, 16, 2, 1, 0x8000 | 0x1000},
269 {250000, 1, 0, 6, 12, 2, 1, 0x8000 | 0x1000},
270 {569999, 2, 1, 5, 6, 2, 2, 0x4000 | 0x0800}, /* UHF */
271 {699999, 2, 0, 1, 4, 2, 2, 0x4000 | 0x0800},
272 {863999, 2, 1, 1, 4, 2, 2, 0x4000 | 0x0800},
273 {0xffffffff, 0, 1, 0, 2, 2, 4, 0x2000 | 0x0400}, /* LBAND or everything higher than UHF */
274};
275
276static const struct dib0070_lna_match dib0070_lna_flip_chip[] = {
277 {180000, 0}, /* VHF */
278 {188000, 1},
279 {196400, 2},
280 {250000, 3},
281 {550000, 0}, /* UHF */
282 {590000, 1},
283 {666000, 3},
284 {864000, 5},
285 {1500000, 0}, /* LBAND or everything higher than UHF */
286 {1600000, 1},
287 {2000000, 3},
288 {0xffffffff, 7},
289};
290
291static const struct dib0070_lna_match dib0070_lna[] = {
292 {180000, 0}, /* VHF */
293 {188000, 1},
294 {196400, 2},
295 {250000, 3},
296 {550000, 2}, /* UHF */
297 {650000, 3},
298 {750000, 5},
299 {850000, 6},
300 {864000, 7},
301 {1500000, 0}, /* LBAND or everything higher than UHF */
302 {1600000, 1},
303 {2000000, 3},
304 {0xffffffff, 7},
305};
306
307#define LPF 100 // define for the loop filter 100kHz by default 16-07-06
308static int dib0070_tune_digital(struct dvb_frontend *fe, struct dvb_frontend_parameters *ch)
309{
310 struct dib0070_state *state = fe->tuner_priv;
311
312 const struct dib0070_tuning *tune;
313 const struct dib0070_lna_match *lna_match;
314
315 enum frontend_tune_state *tune_state = &state->tune_state;
316 int ret = 10; /* 1ms is the default delay most of the time */
317
318 u8 band = (u8) BAND_OF_FREQUENCY(fe->dtv_property_cache.frequency / 1000);
319 u32 freq = fe->dtv_property_cache.frequency / 1000 + (band == BAND_VHF ? state->cfg->freq_offset_khz_vhf : state->cfg->freq_offset_khz_uhf);
320
321#ifdef CONFIG_SYS_ISDBT
322 if (state->fe->dtv_property_cache.delivery_system == SYS_ISDBT && state->fe->dtv_property_cache.isdbt_sb_mode == 1)
323 if (((state->fe->dtv_property_cache.isdbt_sb_segment_count % 2)
324 && (state->fe->dtv_property_cache.isdbt_sb_segment_idx == ((state->fe->dtv_property_cache.isdbt_sb_segment_count / 2) + 1)))
325 || (((state->fe->dtv_property_cache.isdbt_sb_segment_count % 2) == 0)
326 && (state->fe->dtv_property_cache.isdbt_sb_segment_idx == (state->fe->dtv_property_cache.isdbt_sb_segment_count / 2)))
327 || (((state->fe->dtv_property_cache.isdbt_sb_segment_count % 2) == 0)
328 && (state->fe->dtv_property_cache.isdbt_sb_segment_idx == ((state->fe->dtv_property_cache.isdbt_sb_segment_count / 2) + 1))))
329 freq += 850;
330#endif
331 if (state->current_rf != freq) {
332
333 switch (state->revision) {
334 case DIB0070S_P1A:
335 tune = dib0070s_tuning_table;
336 lna_match = dib0070_lna;
337 break;
338 default:
339 tune = dib0070_tuning_table;
340 if (state->cfg->flip_chip)
341 lna_match = dib0070_lna_flip_chip;
342 else
343 lna_match = dib0070_lna;
344 break;
345 }
346 while (freq > tune->max_freq) /* find the right one */
347 tune++;
348 while (freq > lna_match->max_freq) /* find the right one */
349 lna_match++;
350
351 state->current_tune_table_index = tune;
352 state->lna_match = lna_match;
353 }
354
355 if (*tune_state == CT_TUNER_START) {
356 dprintk("Tuning for Band: %hd (%d kHz)", band, freq);
357 if (state->current_rf != freq) {
358 u8 REFDIV;
359 u32 FBDiv, Rest, FREF, VCOF_kHz;
360 u8 Den;
361
362 state->current_rf = freq;
363 state->lo4 = (state->current_tune_table_index->vco_band << 11) | (state->current_tune_table_index->hfdiv << 7);
364
365 dib0070_write_reg(state, 0x17, 0x30);
366
367 VCOF_kHz = state->current_tune_table_index->vco_multi * freq * 2;
368
369 switch (band) {
370 case BAND_VHF:
371 REFDIV = (u8) ((state->cfg->clock_khz + 9999) / 10000);
372 break;
373 case BAND_FM:
374 REFDIV = (u8) ((state->cfg->clock_khz) / 1000);
375 break;
376 default:
377 REFDIV = (u8) (state->cfg->clock_khz / 10000);
378 break;
379 }
380 FREF = state->cfg->clock_khz / REFDIV;
381
382 switch (state->revision) {
383 case DIB0070S_P1A:
384 FBDiv = (VCOF_kHz / state->current_tune_table_index->presc / FREF);
385 Rest = (VCOF_kHz / state->current_tune_table_index->presc) - FBDiv * FREF;
386 break;
387
388 case DIB0070_P1G:
389 case DIB0070_P1F:
390 default:
391 FBDiv = (freq / (FREF / 2));
392 Rest = 2 * freq - FBDiv * FREF;
393 break;
394 }
395
396 if (Rest < LPF)
397 Rest = 0;
398 else if (Rest < 2 * LPF)
399 Rest = 2 * LPF;
400 else if (Rest > (FREF - LPF)) {
401 Rest = 0;
402 FBDiv += 1;
403 } else if (Rest > (FREF - 2 * LPF))
404 Rest = FREF - 2 * LPF;
405 Rest = (Rest * 6528) / (FREF / 10);
406
407 Den = 1;
408 if (Rest > 0) {
409 state->lo4 |= (1 << 14) | (1 << 12);
410 Den = 255;
411 }
412
413 dib0070_write_reg(state, 0x11, (u16) FBDiv);
414 dib0070_write_reg(state, 0x12, (Den << 8) | REFDIV);
415 dib0070_write_reg(state, 0x13, (u16) Rest);
416
417 if (state->revision == DIB0070S_P1A) {
418
419 if (band == BAND_SBAND) {
420 dib0070_set_ctrl_lo5(fe, 2, 4, 3, 0);
421 dib0070_write_reg(state, 0x1d, 0xFFFF);
422 } else
423 dib0070_set_ctrl_lo5(fe, 5, 4, 3, 1);
424 }
425
426 dib0070_write_reg(state, 0x20,
427 0x0040 | 0x0020 | 0x0010 | 0x0008 | 0x0002 | 0x0001 | state->current_tune_table_index->tuner_enable);
428
429 dprintk("REFDIV: %hd, FREF: %d", REFDIV, FREF);
430 dprintk("FBDIV: %d, Rest: %d", FBDiv, Rest);
431 dprintk("Num: %hd, Den: %hd, SD: %hd", (u16) Rest, Den, (state->lo4 >> 12) & 0x1);
432 dprintk("HFDIV code: %hd", state->current_tune_table_index->hfdiv);
433 dprintk("VCO = %hd", state->current_tune_table_index->vco_band);
434 dprintk("VCOF: ((%hd*%d) << 1))", state->current_tune_table_index->vco_multi, freq);
435
436 *tune_state = CT_TUNER_STEP_0;
437 } else { /* we are already tuned to this frequency - the configuration is correct */
438 ret = 50; /* wakeup time */
439 *tune_state = CT_TUNER_STEP_5;
440 }
441 } else if ((*tune_state > CT_TUNER_START) && (*tune_state < CT_TUNER_STEP_4)) {
442
443 ret = dib0070_captrim(state, tune_state);
444
445 } else if (*tune_state == CT_TUNER_STEP_4) {
446 const struct dib0070_wbd_gain_cfg *tmp = state->cfg->wbd_gain;
447 if (tmp != NULL) {
448 while (freq / 1000 > tmp->freq) /* find the right one */
449 tmp++;
450 dib0070_write_reg(state, 0x0f,
451 (0 << 15) | (1 << 14) | (3 << 12) | (tmp->wbd_gain_val << 9) | (0 << 8) | (1 << 7) | (state->
452 current_tune_table_index->
453 wbdmux << 0));
454 state->wbd_gain_current = tmp->wbd_gain_val;
455 } else {
456 dib0070_write_reg(state, 0x0f,
457 (0 << 15) | (1 << 14) | (3 << 12) | (6 << 9) | (0 << 8) | (1 << 7) | (state->current_tune_table_index->
458 wbdmux << 0));
459 state->wbd_gain_current = 6;
460 }
461
462 dib0070_write_reg(state, 0x06, 0x3fff);
463 dib0070_write_reg(state, 0x07,
464 (state->current_tune_table_index->switch_trim << 11) | (7 << 8) | (state->lna_match->lna_band << 3) | (3 << 0));
465 dib0070_write_reg(state, 0x08, (state->lna_match->lna_band << 10) | (3 << 7) | (127));
466 dib0070_write_reg(state, 0x0d, 0x0d80);
467
468 dib0070_write_reg(state, 0x18, 0x07ff);
469 dib0070_write_reg(state, 0x17, 0x0033);
470
471 *tune_state = CT_TUNER_STEP_5;
472 } else if (*tune_state == CT_TUNER_STEP_5) {
473 dib0070_set_bandwidth(fe, ch);
474 *tune_state = CT_TUNER_STOP;
475 } else {
476 ret = FE_CALLBACK_TIME_NEVER; /* tuner finished, time to call again infinite */
477 }
478 return ret;
479}
Patrick Boettcher7e5ce652009-08-03 13:43:40 -0300480
481static int dib0070_tune(struct dvb_frontend *fe, struct dvb_frontend_parameters *p)
482{
Patrick Boettcher2a6a30e2009-08-17 05:13:28 -0300483 struct dib0070_state *state = fe->tuner_priv;
484 uint32_t ret;
Patrick Boettcher7e5ce652009-08-03 13:43:40 -0300485
Patrick Boettcher2a6a30e2009-08-17 05:13:28 -0300486 state->tune_state = CT_TUNER_START;
Patrick Boettcher7e5ce652009-08-03 13:43:40 -0300487
Patrick Boettcher2a6a30e2009-08-17 05:13:28 -0300488 do {
489 ret = dib0070_tune_digital(fe, p);
490 if (ret != FE_CALLBACK_TIME_NEVER)
491 msleep(ret / 10);
492 else
493 break;
494 } while (state->tune_state != CT_TUNER_STOP);
Patrick Boettcher7e5ce652009-08-03 13:43:40 -0300495
Patrick Boettcher2a6a30e2009-08-17 05:13:28 -0300496 return 0;
Patrick Boettcher01373a52007-07-30 12:49:04 -0300497}
498
499static int dib0070_wakeup(struct dvb_frontend *fe)
500{
Patrick Boettcher2a6a30e2009-08-17 05:13:28 -0300501 struct dib0070_state *state = fe->tuner_priv;
502 if (state->cfg->sleep)
503 state->cfg->sleep(fe, 0);
Patrick Boettcher01373a52007-07-30 12:49:04 -0300504 return 0;
505}
506
507static int dib0070_sleep(struct dvb_frontend *fe)
508{
Patrick Boettcher2a6a30e2009-08-17 05:13:28 -0300509 struct dib0070_state *state = fe->tuner_priv;
510 if (state->cfg->sleep)
511 state->cfg->sleep(fe, 1);
Patrick Boettcher01373a52007-07-30 12:49:04 -0300512 return 0;
513}
514
Patrick Boettcher2a6a30e2009-08-17 05:13:28 -0300515static const u16 dib0070_p1f_defaults[] = {
Patrick Boettcher01373a52007-07-30 12:49:04 -0300516 7, 0x02,
Patrick Boettcher2a6a30e2009-08-17 05:13:28 -0300517 0x0008,
518 0x0000,
519 0x0000,
520 0x0000,
521 0x0000,
522 0x0002,
523 0x0100,
Patrick Boettcher01373a52007-07-30 12:49:04 -0300524
525 3, 0x0d,
Patrick Boettcher2a6a30e2009-08-17 05:13:28 -0300526 0x0d80,
527 0x0001,
528 0x0000,
Patrick Boettcher01373a52007-07-30 12:49:04 -0300529
530 4, 0x11,
Patrick Boettcher2a6a30e2009-08-17 05:13:28 -0300531 0x0000,
532 0x0103,
533 0x0000,
534 0x0000,
Patrick Boettcher01373a52007-07-30 12:49:04 -0300535
536 3, 0x16,
Patrick Boettcher2a6a30e2009-08-17 05:13:28 -0300537 0x0004 | 0x0040,
538 0x0030,
539 0x07ff,
Patrick Boettcher01373a52007-07-30 12:49:04 -0300540
541 6, 0x1b,
Patrick Boettcher2a6a30e2009-08-17 05:13:28 -0300542 0x4112,
543 0xff00,
544 0xc07f,
545 0x0000,
546 0x0180,
547 0x4000 | 0x0800 | 0x0040 | 0x0020 | 0x0010 | 0x0008 | 0x0002 | 0x0001,
Patrick Boettcher01373a52007-07-30 12:49:04 -0300548
549 0,
550};
551
Patrick Boettcher7e5ce652009-08-03 13:43:40 -0300552static u16 dib0070_read_wbd_offset(struct dib0070_state *state, u8 gain)
Patrick Boettcher01373a52007-07-30 12:49:04 -0300553{
Patrick Boettcher2a6a30e2009-08-17 05:13:28 -0300554 u16 tuner_en = dib0070_read_reg(state, 0x20);
555 u16 offset;
Patrick Boettcher3cb2c392008-01-25 07:25:20 -0300556
Patrick Boettcher2a6a30e2009-08-17 05:13:28 -0300557 dib0070_write_reg(state, 0x18, 0x07ff);
558 dib0070_write_reg(state, 0x20, 0x0800 | 0x4000 | 0x0040 | 0x0020 | 0x0010 | 0x0008 | 0x0002 | 0x0001);
559 dib0070_write_reg(state, 0x0f, (1 << 14) | (2 << 12) | (gain << 9) | (1 << 8) | (1 << 7) | (0 << 0));
560 msleep(9);
561 offset = dib0070_read_reg(state, 0x19);
562 dib0070_write_reg(state, 0x20, tuner_en);
563 return offset;
Patrick Boettcher7e5ce652009-08-03 13:43:40 -0300564}
Patrick Boettcher3cb2c392008-01-25 07:25:20 -0300565
Patrick Boettcher7e5ce652009-08-03 13:43:40 -0300566static void dib0070_wbd_offset_calibration(struct dib0070_state *state)
567{
Patrick Boettcher2a6a30e2009-08-17 05:13:28 -0300568 u8 gain;
569 for (gain = 6; gain < 8; gain++) {
570 state->wbd_offset_3_3[gain - 6] = ((dib0070_read_wbd_offset(state, gain) * 8 * 18 / 33 + 1) / 2);
571 dprintk("Gain: %d, WBDOffset (3.3V) = %hd", gain, state->wbd_offset_3_3[gain - 6]);
572 }
Patrick Boettcher01373a52007-07-30 12:49:04 -0300573}
574
575u16 dib0070_wbd_offset(struct dvb_frontend *fe)
576{
Patrick Boettcher2a6a30e2009-08-17 05:13:28 -0300577 struct dib0070_state *state = fe->tuner_priv;
578 const struct dib0070_wbd_gain_cfg *tmp = state->cfg->wbd_gain;
579 u32 freq = fe->dtv_property_cache.frequency / 1000;
580
581 if (tmp != NULL) {
582 while (freq / 1000 > tmp->freq) /* find the right one */
583 tmp++;
584 state->wbd_gain_current = tmp->wbd_gain_val;
585 } else
586 state->wbd_gain_current = 6;
587
588 return state->wbd_offset_3_3[state->wbd_gain_current - 6];
Patrick Boettcher01373a52007-07-30 12:49:04 -0300589}
590
591EXPORT_SYMBOL(dib0070_wbd_offset);
Patrick Boettcher2a6a30e2009-08-17 05:13:28 -0300592
Patrick Boettcher01373a52007-07-30 12:49:04 -0300593#define pgm_read_word(w) (*w)
Patrick Boettcher7e5ce652009-08-03 13:43:40 -0300594static int dib0070_reset(struct dvb_frontend *fe)
Patrick Boettcher01373a52007-07-30 12:49:04 -0300595{
Patrick Boettcher2a6a30e2009-08-17 05:13:28 -0300596 struct dib0070_state *state = fe->tuner_priv;
Patrick Boettcher01373a52007-07-30 12:49:04 -0300597 u16 l, r, *n;
598
599 HARD_RESET(state);
600
Patrick Boettcher01373a52007-07-30 12:49:04 -0300601#ifndef FORCE_SBAND_TUNER
602 if ((dib0070_read_reg(state, 0x22) >> 9) & 0x1)
603 state->revision = (dib0070_read_reg(state, 0x1f) >> 8) & 0xff;
604 else
Patrick Boettcher7e5ce652009-08-03 13:43:40 -0300605#else
606#warning forcing SBAND
Patrick Boettcher01373a52007-07-30 12:49:04 -0300607#endif
Patrick Boettcher2a6a30e2009-08-17 05:13:28 -0300608 state->revision = DIB0070S_P1A;
Patrick Boettcher01373a52007-07-30 12:49:04 -0300609
610 /* P1F or not */
Patrick Boettcher2a6a30e2009-08-17 05:13:28 -0300611 dprintk("Revision: %x", state->revision);
Patrick Boettcher01373a52007-07-30 12:49:04 -0300612
613 if (state->revision == DIB0070_P1D) {
Patrick Boettcher2a6a30e2009-08-17 05:13:28 -0300614 dprintk("Error: this driver is not to be used meant for P1D or earlier");
Patrick Boettcher01373a52007-07-30 12:49:04 -0300615 return -EINVAL;
616 }
617
618 n = (u16 *) dib0070_p1f_defaults;
619 l = pgm_read_word(n++);
620 while (l) {
621 r = pgm_read_word(n++);
622 do {
Patrick Boettcher2a6a30e2009-08-17 05:13:28 -0300623 dib0070_write_reg(state, (u8) r, pgm_read_word(n++));
Patrick Boettcher01373a52007-07-30 12:49:04 -0300624 r++;
625 } while (--l);
626 l = pgm_read_word(n++);
627 }
628
629 if (state->cfg->force_crystal_mode != 0)
630 r = state->cfg->force_crystal_mode;
631 else if (state->cfg->clock_khz >= 24000)
632 r = 1;
633 else
634 r = 2;
635
636 r |= state->cfg->osc_buffer_state << 3;
637
638 dib0070_write_reg(state, 0x10, r);
Patrick Boettcher7e5ce652009-08-03 13:43:40 -0300639 dib0070_write_reg(state, 0x1f, (1 << 8) | ((state->cfg->clock_pad_drive & 0xf) << 5));
Patrick Boettcher01373a52007-07-30 12:49:04 -0300640
641 if (state->cfg->invert_iq) {
642 r = dib0070_read_reg(state, 0x02) & 0xffdf;
643 dib0070_write_reg(state, 0x02, r | (1 << 5));
644 }
645
Patrick Boettcher2a6a30e2009-08-17 05:13:28 -0300646 if (state->revision == DIB0070S_P1A)
647 dib0070_set_ctrl_lo5(fe, 2, 4, 3, 0);
648 else
Patrick Boettcher7e5ce652009-08-03 13:43:40 -0300649 dib0070_set_ctrl_lo5(fe, 5, 4, state->cfg->charge_pump, state->cfg->enable_third_order_filter);
Patrick Boettcher01373a52007-07-30 12:49:04 -0300650
651 dib0070_write_reg(state, 0x01, (54 << 9) | 0xc8);
Patrick Boettcher7e5ce652009-08-03 13:43:40 -0300652
Patrick Boettcher2a6a30e2009-08-17 05:13:28 -0300653 dib0070_wbd_offset_calibration(state);
Patrick Boettcher7e5ce652009-08-03 13:43:40 -0300654
Patrick Boettcher2a6a30e2009-08-17 05:13:28 -0300655 return 0;
Patrick Boettcher01373a52007-07-30 12:49:04 -0300656}
657
Patrick Boettcher01373a52007-07-30 12:49:04 -0300658static int dib0070_release(struct dvb_frontend *fe)
659{
660 kfree(fe->tuner_priv);
661 fe->tuner_priv = NULL;
662 return 0;
663}
664
Patrick Boettcher7e5ce652009-08-03 13:43:40 -0300665static const struct dvb_tuner_ops dib0070_ops = {
Patrick Boettcher01373a52007-07-30 12:49:04 -0300666 .info = {
Patrick Boettcher2a6a30e2009-08-17 05:13:28 -0300667 .name = "DiBcom DiB0070",
668 .frequency_min = 45000000,
669 .frequency_max = 860000000,
670 .frequency_step = 1000,
671 },
672 .release = dib0070_release,
Patrick Boettcher01373a52007-07-30 12:49:04 -0300673
Patrick Boettcher2a6a30e2009-08-17 05:13:28 -0300674 .init = dib0070_wakeup,
675 .sleep = dib0070_sleep,
676 .set_params = dib0070_tune,
Patrick Boettcher7e5ce652009-08-03 13:43:40 -0300677
Patrick Boettcher2a6a30e2009-08-17 05:13:28 -0300678// .get_frequency = dib0070_get_frequency,
679// .get_bandwidth = dib0070_get_bandwidth
Patrick Boettcher01373a52007-07-30 12:49:04 -0300680};
681
Patrick Boettcher2a6a30e2009-08-17 05:13:28 -0300682struct dvb_frontend *dib0070_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct dib0070_config *cfg)
Patrick Boettcher01373a52007-07-30 12:49:04 -0300683{
684 struct dib0070_state *state = kzalloc(sizeof(struct dib0070_state), GFP_KERNEL);
685 if (state == NULL)
686 return NULL;
687
688 state->cfg = cfg;
689 state->i2c = i2c;
Patrick Boettcher2a6a30e2009-08-17 05:13:28 -0300690 state->fe = fe;
Patrick Boettcher01373a52007-07-30 12:49:04 -0300691 fe->tuner_priv = state;
692
Patrick Boettcher7e5ce652009-08-03 13:43:40 -0300693 if (dib0070_reset(fe) != 0)
Patrick Boettcher01373a52007-07-30 12:49:04 -0300694 goto free_mem;
695
Patrick Boettcher01373a52007-07-30 12:49:04 -0300696 printk(KERN_INFO "DiB0070: successfully identified\n");
697 memcpy(&fe->ops.tuner_ops, &dib0070_ops, sizeof(struct dvb_tuner_ops));
698
699 fe->tuner_priv = state;
700 return fe;
701
Patrick Boettcher2a6a30e2009-08-17 05:13:28 -0300702 free_mem:
Patrick Boettcher01373a52007-07-30 12:49:04 -0300703 kfree(state);
704 fe->tuner_priv = NULL;
705 return NULL;
706}
Patrick Boettcher2a6a30e2009-08-17 05:13:28 -0300707
Patrick Boettcher01373a52007-07-30 12:49:04 -0300708EXPORT_SYMBOL(dib0070_attach);
709
710MODULE_AUTHOR("Patrick Boettcher <pboettcher@dibcom.fr>");
711MODULE_DESCRIPTION("Driver for the DiBcom 0070 base-band RF Tuner");
712MODULE_LICENSE("GPL");