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