diff options
Diffstat (limited to 'drivers/media/dvb/frontends/dib0070.c')
-rw-r--r-- | drivers/media/dvb/frontends/dib0070.c | 580 |
1 files changed, 580 insertions, 0 deletions
diff --git a/drivers/media/dvb/frontends/dib0070.c b/drivers/media/dvb/frontends/dib0070.c new file mode 100644 index 000000000000..481eaa684157 --- /dev/null +++ b/drivers/media/dvb/frontends/dib0070.c | |||
@@ -0,0 +1,580 @@ | |||
1 | /* | ||
2 | * Linux-DVB Driver for DiBcom's DiB0070 base-band RF Tuner. | ||
3 | * | ||
4 | * Copyright (C) 2005-7 DiBcom (http://www.dibcom.fr/) | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or | ||
7 | * modify it under the terms of the GNU General Public License as | ||
8 | * published by the Free Software Foundation, version 2. | ||
9 | */ | ||
10 | #include <linux/kernel.h> | ||
11 | #include <linux/i2c.h> | ||
12 | |||
13 | #include "dvb_frontend.h" | ||
14 | |||
15 | #include "dib0070.h" | ||
16 | #include "dibx000_common.h" | ||
17 | |||
18 | static int debug; | ||
19 | module_param(debug, int, 0644); | ||
20 | MODULE_PARM_DESC(debug, "turn on debugging (default: 0)"); | ||
21 | |||
22 | #define dprintk(args...) do { if (debug) { printk(KERN_DEBUG "DiB0070: "); printk(args); printk("\n"); } } while (0) | ||
23 | |||
24 | #define DIB0070_P1D 0x00 | ||
25 | #define DIB0070_P1F 0x01 | ||
26 | #define DIB0070_P1G 0x03 | ||
27 | #define DIB0070S_P1A 0x02 | ||
28 | |||
29 | struct dib0070_state { | ||
30 | struct i2c_adapter *i2c; | ||
31 | struct dvb_frontend *fe; | ||
32 | const struct dib0070_config *cfg; | ||
33 | u16 wbd_ff_offset; | ||
34 | u8 revision; | ||
35 | }; | ||
36 | |||
37 | static uint16_t dib0070_read_reg(struct dib0070_state *state, u8 reg) | ||
38 | { | ||
39 | u8 b[2]; | ||
40 | struct i2c_msg msg[2] = { | ||
41 | { .addr = state->cfg->i2c_address, .flags = 0, .buf = ®, .len = 1 }, | ||
42 | { .addr = state->cfg->i2c_address, .flags = I2C_M_RD, .buf = b, .len = 2 }, | ||
43 | }; | ||
44 | if (i2c_transfer(state->i2c, msg, 2) != 2) { | ||
45 | printk(KERN_WARNING "DiB0070 I2C read failed\n"); | ||
46 | return 0; | ||
47 | } | ||
48 | return (b[0] << 8) | b[1]; | ||
49 | } | ||
50 | |||
51 | static int dib0070_write_reg(struct dib0070_state *state, u8 reg, u16 val) | ||
52 | { | ||
53 | u8 b[3] = { reg, val >> 8, val & 0xff }; | ||
54 | struct i2c_msg msg = { .addr = state->cfg->i2c_address, .flags = 0, .buf = b, .len = 3 }; | ||
55 | if (i2c_transfer(state->i2c, &msg, 1) != 1) { | ||
56 | printk(KERN_WARNING "DiB0070 I2C write failed\n"); | ||
57 | return -EREMOTEIO; | ||
58 | } | ||
59 | return 0; | ||
60 | } | ||
61 | |||
62 | #define HARD_RESET(state) do { if (state->cfg->reset) { state->cfg->reset(state->fe,1); msleep(10); state->cfg->reset(state->fe,0); msleep(10); } } while (0) | ||
63 | |||
64 | static int dib0070_set_bandwidth(struct dvb_frontend *fe, struct dvb_frontend_parameters *ch) | ||
65 | { | ||
66 | struct dib0070_state *st = fe->tuner_priv; | ||
67 | u16 tmp = 0; | ||
68 | tmp = dib0070_read_reg(st, 0x02) & 0x3fff; | ||
69 | |||
70 | switch(BANDWIDTH_TO_KHZ(ch->u.ofdm.bandwidth)) { | ||
71 | case 8000: | ||
72 | tmp |= (0 << 14); | ||
73 | break; | ||
74 | case 7000: | ||
75 | tmp |= (1 << 14); | ||
76 | break; | ||
77 | case 6000: | ||
78 | tmp |= (2 << 14); | ||
79 | break; | ||
80 | case 5000: | ||
81 | default: | ||
82 | tmp |= (3 << 14); | ||
83 | break; | ||
84 | } | ||
85 | dib0070_write_reg(st, 0x02, tmp); | ||
86 | return 0; | ||
87 | } | ||
88 | |||
89 | static void dib0070_captrim(struct dib0070_state *st, u16 LO4) | ||
90 | { | ||
91 | int8_t captrim, fcaptrim, step_sign, step; | ||
92 | u16 adc, adc_diff = 3000; | ||
93 | |||
94 | |||
95 | |||
96 | dib0070_write_reg(st, 0x0f, 0xed10); | ||
97 | dib0070_write_reg(st, 0x17, 0x0034); | ||
98 | |||
99 | dib0070_write_reg(st, 0x18, 0x0032); | ||
100 | msleep(2); | ||
101 | |||
102 | step = captrim = fcaptrim = 64; | ||
103 | |||
104 | do { | ||
105 | step /= 2; | ||
106 | dib0070_write_reg(st, 0x14, LO4 | captrim); | ||
107 | msleep(1); | ||
108 | adc = dib0070_read_reg(st, 0x19); | ||
109 | |||
110 | dprintk( "CAPTRIM=%hd; ADC = %hd (ADC) & %dmV", captrim, adc, (u32) adc*(u32)1800/(u32)1024); | ||
111 | |||
112 | if (adc >= 400) { | ||
113 | adc -= 400; | ||
114 | step_sign = -1; | ||
115 | } else { | ||
116 | adc = 400 - adc; | ||
117 | step_sign = 1; | ||
118 | } | ||
119 | |||
120 | if (adc < adc_diff) { | ||
121 | dprintk( "CAPTRIM=%hd is closer to target (%hd/%hd)", captrim, adc, adc_diff); | ||
122 | adc_diff = adc; | ||
123 | fcaptrim = captrim; | ||
124 | |||
125 | |||
126 | |||
127 | } | ||
128 | captrim += (step_sign * step); | ||
129 | } while (step >= 1); | ||
130 | |||
131 | dib0070_write_reg(st, 0x14, LO4 | fcaptrim); | ||
132 | dib0070_write_reg(st, 0x18, 0x07ff); | ||
133 | } | ||
134 | |||
135 | #define LPF 100 // define for the loop filter 100kHz by default 16-07-06 | ||
136 | #define LO4_SET_VCO_HFDIV(l, v, h) l |= ((v) << 11) | ((h) << 7) | ||
137 | #define LO4_SET_SD(l, s) l |= ((s) << 14) | ((s) << 12) | ||
138 | #define LO4_SET_CTRIM(l, c) l |= (c) << 10 | ||
139 | static int dib0070_tune_digital(struct dvb_frontend *fe, struct dvb_frontend_parameters *ch) | ||
140 | { | ||
141 | struct dib0070_state *st = fe->tuner_priv; | ||
142 | u32 freq = ch->frequency/1000 + (BAND_OF_FREQUENCY(ch->frequency/1000) == BAND_VHF ? st->cfg->freq_offset_khz_vhf : st->cfg->freq_offset_khz_uhf); | ||
143 | |||
144 | u8 band = BAND_OF_FREQUENCY(freq), c; | ||
145 | |||
146 | /*******************VCO***********************************/ | ||
147 | u16 lo4 = 0; | ||
148 | |||
149 | u8 REFDIV, PRESC = 2; | ||
150 | u32 FBDiv, Rest, FREF, VCOF_kHz; | ||
151 | u16 Num, Den; | ||
152 | /*******************FrontEnd******************************/ | ||
153 | u16 value = 0; | ||
154 | |||
155 | dprintk( "Tuning for Band: %hd (%d kHz)", band, freq); | ||
156 | |||
157 | |||
158 | dib0070_write_reg(st, 0x17, 0x30); | ||
159 | |||
160 | dib0070_set_bandwidth(fe, ch); /* c is used as HF */ | ||
161 | switch (st->revision) { | ||
162 | case DIB0070S_P1A: | ||
163 | switch (band) { | ||
164 | case BAND_LBAND: | ||
165 | LO4_SET_VCO_HFDIV(lo4, 1, 1); | ||
166 | c = 2; | ||
167 | break; | ||
168 | case BAND_SBAND: | ||
169 | LO4_SET_VCO_HFDIV(lo4, 0, 0); | ||
170 | LO4_SET_CTRIM(lo4, 1);; | ||
171 | c = 1; | ||
172 | break; | ||
173 | case BAND_UHF: | ||
174 | default: | ||
175 | if (freq < 570000) { | ||
176 | LO4_SET_VCO_HFDIV(lo4, 1, 3); | ||
177 | PRESC = 6; c = 6; | ||
178 | } else if (freq < 680000) { | ||
179 | LO4_SET_VCO_HFDIV(lo4, 0, 2); | ||
180 | c = 4; | ||
181 | } else { | ||
182 | LO4_SET_VCO_HFDIV(lo4, 1, 2); | ||
183 | c = 4; | ||
184 | } | ||
185 | break; | ||
186 | } break; | ||
187 | |||
188 | case DIB0070_P1G: | ||
189 | case DIB0070_P1F: | ||
190 | default: | ||
191 | switch (band) { | ||
192 | case BAND_FM: | ||
193 | LO4_SET_VCO_HFDIV(lo4, 0, 7); | ||
194 | c = 24; | ||
195 | break; | ||
196 | case BAND_LBAND: | ||
197 | LO4_SET_VCO_HFDIV(lo4, 1, 0); | ||
198 | c = 2; | ||
199 | break; | ||
200 | case BAND_VHF: | ||
201 | if (freq < 180000) { | ||
202 | LO4_SET_VCO_HFDIV(lo4, 0, 3); | ||
203 | c = 16; | ||
204 | } else if (freq < 190000) { | ||
205 | LO4_SET_VCO_HFDIV(lo4, 1, 3); | ||
206 | c = 16; | ||
207 | } else { | ||
208 | LO4_SET_VCO_HFDIV(lo4, 0, 6); | ||
209 | c = 12; | ||
210 | } | ||
211 | break; | ||
212 | |||
213 | case BAND_UHF: | ||
214 | default: | ||
215 | if (freq < 570000) { | ||
216 | LO4_SET_VCO_HFDIV(lo4, 1, 5); | ||
217 | c = 6; | ||
218 | } else if (freq < 700000) { | ||
219 | LO4_SET_VCO_HFDIV(lo4, 0, 1); | ||
220 | c = 4; | ||
221 | } else { | ||
222 | LO4_SET_VCO_HFDIV(lo4, 1, 1); | ||
223 | c = 4; | ||
224 | } | ||
225 | break; | ||
226 | } | ||
227 | break; | ||
228 | } | ||
229 | |||
230 | dprintk( "HFDIV code: %hd", (lo4 >> 7) & 0xf); | ||
231 | dprintk( "VCO = %hd", (lo4 >> 11) & 0x3); | ||
232 | |||
233 | |||
234 | VCOF_kHz = (c * freq) * 2; | ||
235 | dprintk( "VCOF in kHz: %d ((%hd*%d) << 1))",VCOF_kHz, c, freq); | ||
236 | |||
237 | switch (band) { | ||
238 | case BAND_VHF: | ||
239 | REFDIV = (u8) ((st->cfg->clock_khz + 9999) / 10000); | ||
240 | break; | ||
241 | case BAND_FM: | ||
242 | REFDIV = (u8) ((st->cfg->clock_khz) / 1000); | ||
243 | break; | ||
244 | default: | ||
245 | REFDIV = (u8) ( st->cfg->clock_khz / 10000); | ||
246 | break; | ||
247 | } | ||
248 | FREF = st->cfg->clock_khz / REFDIV; | ||
249 | |||
250 | dprintk( "REFDIV: %hd, FREF: %d", REFDIV, FREF); | ||
251 | |||
252 | |||
253 | |||
254 | switch (st->revision) { | ||
255 | case DIB0070S_P1A: | ||
256 | FBDiv = (VCOF_kHz / PRESC / FREF); | ||
257 | Rest = (VCOF_kHz / PRESC) - FBDiv * FREF; | ||
258 | break; | ||
259 | |||
260 | case DIB0070_P1G: | ||
261 | case DIB0070_P1F: | ||
262 | default: | ||
263 | FBDiv = (freq / (FREF / 2)); | ||
264 | Rest = 2 * freq - FBDiv * FREF; | ||
265 | break; | ||
266 | } | ||
267 | |||
268 | |||
269 | if (Rest < LPF) Rest = 0; | ||
270 | else if (Rest < 2 * LPF) Rest = 2 * LPF; | ||
271 | else if (Rest > (FREF - LPF)) { Rest = 0 ; FBDiv += 1; } | ||
272 | else if (Rest > (FREF - 2 * LPF)) Rest = FREF - 2 * LPF; | ||
273 | Rest = (Rest * 6528) / (FREF / 10); | ||
274 | dprintk( "FBDIV: %d, Rest: %d", FBDiv, Rest); | ||
275 | |||
276 | Num = 0; | ||
277 | Den = 1; | ||
278 | |||
279 | if (Rest > 0) { | ||
280 | LO4_SET_SD(lo4, 1); | ||
281 | Den = 255; | ||
282 | Num = (u16)Rest; | ||
283 | } | ||
284 | dprintk( "Num: %hd, Den: %hd, SD: %hd",Num, Den, (lo4 >> 12) & 0x1); | ||
285 | |||
286 | |||
287 | |||
288 | dib0070_write_reg(st, 0x11, (u16)FBDiv); | ||
289 | |||
290 | |||
291 | dib0070_write_reg(st, 0x12, (Den << 8) | REFDIV); | ||
292 | |||
293 | |||
294 | dib0070_write_reg(st, 0x13, Num); | ||
295 | |||
296 | |||
297 | value = 0x0040 | 0x0020 | 0x0010 | 0x0008 | 0x0002 | 0x0001; | ||
298 | |||
299 | switch (band) { | ||
300 | case BAND_UHF: value |= 0x4000 | 0x0800; break; | ||
301 | case BAND_LBAND: value |= 0x2000 | 0x0400; break; | ||
302 | default: value |= 0x8000 | 0x1000; break; | ||
303 | } | ||
304 | dib0070_write_reg(st, 0x20, value); | ||
305 | |||
306 | dib0070_captrim(st, lo4); | ||
307 | if (st->revision == DIB0070S_P1A) { | ||
308 | if (band == BAND_SBAND) | ||
309 | dib0070_write_reg(st, 0x15, 0x16e2); | ||
310 | else | ||
311 | dib0070_write_reg(st, 0x15, 0x56e5); | ||
312 | } | ||
313 | |||
314 | |||
315 | |||
316 | switch (band) { | ||
317 | case BAND_UHF: value = 0x7c82; break; | ||
318 | case BAND_LBAND: value = 0x7c84; break; | ||
319 | default: value = 0x7c81; break; | ||
320 | } | ||
321 | dib0070_write_reg(st, 0x0f, value); | ||
322 | dib0070_write_reg(st, 0x06, 0x3fff); | ||
323 | |||
324 | /* Front End */ | ||
325 | /* c == TUNE, value = SWITCH */ | ||
326 | c = 0; | ||
327 | value = 0; | ||
328 | switch (band) { | ||
329 | case BAND_FM: | ||
330 | c = 0; value = 1; | ||
331 | break; | ||
332 | |||
333 | case BAND_VHF: | ||
334 | if (freq <= 180000) c = 0; | ||
335 | else if (freq <= 188200) c = 1; | ||
336 | else if (freq <= 196400) c = 2; | ||
337 | else c = 3; | ||
338 | value = 1; | ||
339 | break; | ||
340 | |||
341 | case BAND_LBAND: | ||
342 | if (freq <= 1500000) c = 0; | ||
343 | else if (freq <= 1600000) c = 1; | ||
344 | else c = 3; | ||
345 | break; | ||
346 | |||
347 | case BAND_SBAND: | ||
348 | c = 7; | ||
349 | dib0070_write_reg(st, 0x1d,0xFFFF); | ||
350 | break; | ||
351 | |||
352 | case BAND_UHF: | ||
353 | default: | ||
354 | if (st->cfg->flip_chip) { | ||
355 | if (freq <= 550000) c = 0; | ||
356 | else if (freq <= 590000) c = 1; | ||
357 | else if (freq <= 666000) c = 3; | ||
358 | else c = 5; | ||
359 | } else { | ||
360 | if (freq <= 550000) c = 2; | ||
361 | else if (freq <= 650000) c = 3; | ||
362 | else if (freq <= 750000) c = 5; | ||
363 | else if (freq <= 850000) c = 6; | ||
364 | else c = 7; | ||
365 | } | ||
366 | value = 2; | ||
367 | break; | ||
368 | } | ||
369 | |||
370 | /* default: LNA_MATCH=7, BIAS=3 */ | ||
371 | dib0070_write_reg(st, 0x07, (value << 11) | (7 << 8) | (c << 3) | (3 << 0)); | ||
372 | dib0070_write_reg(st, 0x08, (c << 10) | (3 << 7) | (127)); | ||
373 | dib0070_write_reg(st, 0x0d, 0x0d80); | ||
374 | |||
375 | |||
376 | dib0070_write_reg(st, 0x18, 0x07ff); | ||
377 | dib0070_write_reg(st, 0x17, 0x0033); | ||
378 | |||
379 | return 0; | ||
380 | } | ||
381 | |||
382 | static int dib0070_wakeup(struct dvb_frontend *fe) | ||
383 | { | ||
384 | struct dib0070_state *st = fe->tuner_priv; | ||
385 | if (st->cfg->sleep) | ||
386 | st->cfg->sleep(fe, 0); | ||
387 | return 0; | ||
388 | } | ||
389 | |||
390 | static int dib0070_sleep(struct dvb_frontend *fe) | ||
391 | { | ||
392 | struct dib0070_state *st = fe->tuner_priv; | ||
393 | if (st->cfg->sleep) | ||
394 | st->cfg->sleep(fe, 1); | ||
395 | return 0; | ||
396 | } | ||
397 | |||
398 | static u16 dib0070_p1f_defaults[] = | ||
399 | |||
400 | { | ||
401 | 7, 0x02, | ||
402 | 0x0008, | ||
403 | 0x0000, | ||
404 | 0x0000, | ||
405 | 0x0000, | ||
406 | 0x0000, | ||
407 | 0x0002, | ||
408 | 0x0100, | ||
409 | |||
410 | 3, 0x0d, | ||
411 | 0x0d80, | ||
412 | 0x0001, | ||
413 | 0x0000, | ||
414 | |||
415 | 4, 0x11, | ||
416 | 0x0000, | ||
417 | 0x0103, | ||
418 | 0x0000, | ||
419 | 0x0000, | ||
420 | |||
421 | 3, 0x16, | ||
422 | 0x0004 | 0x0040, | ||
423 | 0x0030, | ||
424 | 0x07ff, | ||
425 | |||
426 | 6, 0x1b, | ||
427 | 0x4112, | ||
428 | 0xff00, | ||
429 | 0xc07f, | ||
430 | 0x0000, | ||
431 | 0x0180, | ||
432 | 0x4000 | 0x0800 | 0x0040 | 0x0020 | 0x0010 | 0x0008 | 0x0002 | 0x0001, | ||
433 | |||
434 | 0, | ||
435 | }; | ||
436 | |||
437 | static void dib0070_wbd_calibration(struct dib0070_state *state) | ||
438 | { | ||
439 | u16 wbd_offs; | ||
440 | dib0070_write_reg(state, 0x0f, 0x6d81); | ||
441 | dib0070_write_reg(state, 0x20, 0x0040 | 0x0020 | 0x0010 | 0x0008 | 0x0002 | 0x0001); | ||
442 | msleep(9); | ||
443 | wbd_offs = dib0070_read_reg(state, 0x19); | ||
444 | dib0070_write_reg(state, 0x20, 0); | ||
445 | state->wbd_ff_offset = ((wbd_offs * 8 * 18 / 33 + 1) / 2); | ||
446 | dprintk( "WBDStart = %d (Vargen) - FF = %hd", (u32) wbd_offs * 1800/1024, state->wbd_ff_offset); | ||
447 | } | ||
448 | |||
449 | u16 dib0070_wbd_offset(struct dvb_frontend *fe) | ||
450 | { | ||
451 | struct dib0070_state *st = fe->tuner_priv; | ||
452 | return st->wbd_ff_offset; | ||
453 | } | ||
454 | |||
455 | EXPORT_SYMBOL(dib0070_wbd_offset); | ||
456 | static int dib0070_set_ctrl_lo5(struct dvb_frontend *fe, u8 vco_bias_trim, u8 hf_div_trim, u8 cp_current, u8 third_order_filt) | ||
457 | { | ||
458 | struct dib0070_state *state = fe->tuner_priv; | ||
459 | u16 lo5 = (third_order_filt << 14) | (0 << 13) | (1 << 12) | (3 << 9) | (cp_current << 6) | (hf_div_trim << 3) | (vco_bias_trim << 0); | ||
460 | dprintk( "CTRL_LO5: 0x%x", lo5); | ||
461 | return dib0070_write_reg(state, 0x15, lo5); | ||
462 | } | ||
463 | |||
464 | #define pgm_read_word(w) (*w) | ||
465 | static int dib0070_reset(struct dib0070_state *state) | ||
466 | { | ||
467 | u16 l, r, *n; | ||
468 | |||
469 | HARD_RESET(state); | ||
470 | |||
471 | |||
472 | #ifndef FORCE_SBAND_TUNER | ||
473 | if ((dib0070_read_reg(state, 0x22) >> 9) & 0x1) | ||
474 | state->revision = (dib0070_read_reg(state, 0x1f) >> 8) & 0xff; | ||
475 | else | ||
476 | #endif | ||
477 | state->revision = DIB0070S_P1A; | ||
478 | |||
479 | /* P1F or not */ | ||
480 | dprintk( "Revision: %x", state->revision); | ||
481 | |||
482 | if (state->revision == DIB0070_P1D) { | ||
483 | dprintk( "Error: this driver is not to be used meant for P1D or earlier"); | ||
484 | return -EINVAL; | ||
485 | } | ||
486 | |||
487 | n = (u16 *) dib0070_p1f_defaults; | ||
488 | l = pgm_read_word(n++); | ||
489 | while (l) { | ||
490 | r = pgm_read_word(n++); | ||
491 | do { | ||
492 | dib0070_write_reg(state, (u8)r, pgm_read_word(n++)); | ||
493 | r++; | ||
494 | } while (--l); | ||
495 | l = pgm_read_word(n++); | ||
496 | } | ||
497 | |||
498 | if (state->cfg->force_crystal_mode != 0) | ||
499 | r = state->cfg->force_crystal_mode; | ||
500 | else if (state->cfg->clock_khz >= 24000) | ||
501 | r = 1; | ||
502 | else | ||
503 | r = 2; | ||
504 | |||
505 | r |= state->cfg->osc_buffer_state << 3; | ||
506 | |||
507 | dib0070_write_reg(state, 0x10, r); | ||
508 | dib0070_write_reg(state, 0x1f, (1 << 8) | ((state->cfg->clock_pad_drive & 0xf) << 4)); | ||
509 | |||
510 | if (state->cfg->invert_iq) { | ||
511 | r = dib0070_read_reg(state, 0x02) & 0xffdf; | ||
512 | dib0070_write_reg(state, 0x02, r | (1 << 5)); | ||
513 | } | ||
514 | |||
515 | |||
516 | if (state->revision == DIB0070S_P1A) | ||
517 | dib0070_set_ctrl_lo5(state->fe, 4, 7, 3, 1); | ||
518 | else | ||
519 | dib0070_set_ctrl_lo5(state->fe, 4, 4, 2, 0); | ||
520 | |||
521 | dib0070_write_reg(state, 0x01, (54 << 9) | 0xc8); | ||
522 | return 0; | ||
523 | } | ||
524 | |||
525 | |||
526 | static int dib0070_release(struct dvb_frontend *fe) | ||
527 | { | ||
528 | kfree(fe->tuner_priv); | ||
529 | fe->tuner_priv = NULL; | ||
530 | return 0; | ||
531 | } | ||
532 | |||
533 | static struct dvb_tuner_ops dib0070_ops = { | ||
534 | .info = { | ||
535 | .name = "DiBcom DiB0070", | ||
536 | .frequency_min = 45000000, | ||
537 | .frequency_max = 860000000, | ||
538 | .frequency_step = 1000, | ||
539 | }, | ||
540 | .release = dib0070_release, | ||
541 | |||
542 | .init = dib0070_wakeup, | ||
543 | .sleep = dib0070_sleep, | ||
544 | .set_params = dib0070_tune_digital, | ||
545 | // .get_frequency = dib0070_get_frequency, | ||
546 | // .get_bandwidth = dib0070_get_bandwidth | ||
547 | }; | ||
548 | |||
549 | struct dvb_frontend * dib0070_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct dib0070_config *cfg) | ||
550 | { | ||
551 | struct dib0070_state *state = kzalloc(sizeof(struct dib0070_state), GFP_KERNEL); | ||
552 | if (state == NULL) | ||
553 | return NULL; | ||
554 | |||
555 | state->cfg = cfg; | ||
556 | state->i2c = i2c; | ||
557 | state->fe = fe; | ||
558 | fe->tuner_priv = state; | ||
559 | |||
560 | if (dib0070_reset(state) != 0) | ||
561 | goto free_mem; | ||
562 | |||
563 | dib0070_wbd_calibration(state); | ||
564 | |||
565 | printk(KERN_INFO "DiB0070: successfully identified\n"); | ||
566 | memcpy(&fe->ops.tuner_ops, &dib0070_ops, sizeof(struct dvb_tuner_ops)); | ||
567 | |||
568 | fe->tuner_priv = state; | ||
569 | return fe; | ||
570 | |||
571 | free_mem: | ||
572 | kfree(state); | ||
573 | fe->tuner_priv = NULL; | ||
574 | return NULL; | ||
575 | } | ||
576 | EXPORT_SYMBOL(dib0070_attach); | ||
577 | |||
578 | MODULE_AUTHOR("Patrick Boettcher <pboettcher@dibcom.fr>"); | ||
579 | MODULE_DESCRIPTION("Driver for the DiBcom 0070 base-band RF Tuner"); | ||
580 | MODULE_LICENSE("GPL"); | ||