blob: 750ae61a20f4ba7555581f15710f187d584692f6 [file] [log] [blame]
Patrick Boettchera75763f2006-10-18 08:34:16 -03001/*
2 * Linux-DVB Driver for DiBcom's second generation DiB7000P (PC).
3 *
Patrick Boettcherb6884a12007-07-27 10:08:51 -03004 * Copyright (C) 2005-7 DiBcom (http://www.dibcom.fr/)
Patrick Boettchera75763f2006-10-18 08:34:16 -03005 *
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
Olivier Grenieef801962009-09-15 06:46:52 -030013#include "dvb_math.h"
Patrick Boettchera75763f2006-10-18 08:34:16 -030014#include "dvb_frontend.h"
15
16#include "dib7000p.h"
17
18static int debug;
19module_param(debug, int, 0644);
20MODULE_PARM_DESC(debug, "turn on debugging (default: 0)");
21
Matt Doran8f6956c2007-07-31 07:09:30 -030022static int buggy_sfn_workaround;
23module_param(buggy_sfn_workaround, int, 0644);
Patrick Boettcher8d999962007-07-31 10:36:06 -030024MODULE_PARM_DESC(buggy_sfn_workaround, "Enable work-around for buggy SFNs (default: 0)");
Matt Doran8f6956c2007-07-31 07:09:30 -030025
Patrick Boettcherb6884a12007-07-27 10:08:51 -030026#define dprintk(args...) do { if (debug) { printk(KERN_DEBUG "DiB7000P: "); printk(args); printk("\n"); } } while (0)
Patrick Boettchera75763f2006-10-18 08:34:16 -030027
28struct dib7000p_state {
29 struct dvb_frontend demod;
30 struct dib7000p_config cfg;
31
32 u8 i2c_addr;
33 struct i2c_adapter *i2c_adap;
34
35 struct dibx000_i2c_master i2c_master;
36
37 u16 wbd_ref;
38
Patrick Boettcher904a82e2008-01-25 07:31:58 -030039 u8 current_band;
40 u32 current_bandwidth;
Patrick Boettchera75763f2006-10-18 08:34:16 -030041 struct dibx000_agc_config *current_agc;
42 u32 timf;
43
Patrick Boettcher01373a52007-07-30 12:49:04 -030044 u8 div_force_off : 1;
45 u8 div_state : 1;
46 u16 div_sync_wait;
Patrick Boettcherb6884a12007-07-27 10:08:51 -030047
48 u8 agc_state;
49
Patrick Boettchera75763f2006-10-18 08:34:16 -030050 u16 gpio_dir;
51 u16 gpio_val;
Matt Doran8f6956c2007-07-31 07:09:30 -030052
53 u8 sfn_workaround_active :1;
Patrick Boettchera75763f2006-10-18 08:34:16 -030054};
55
56enum dib7000p_power_mode {
57 DIB7000P_POWER_ALL = 0,
Patrick Boettcherb6884a12007-07-27 10:08:51 -030058 DIB7000P_POWER_ANALOG_ADC,
Patrick Boettchera75763f2006-10-18 08:34:16 -030059 DIB7000P_POWER_INTERFACE_ONLY,
60};
61
62static u16 dib7000p_read_word(struct dib7000p_state *state, u16 reg)
63{
64 u8 wb[2] = { reg >> 8, reg & 0xff };
65 u8 rb[2];
66 struct i2c_msg msg[2] = {
67 { .addr = state->i2c_addr >> 1, .flags = 0, .buf = wb, .len = 2 },
68 { .addr = state->i2c_addr >> 1, .flags = I2C_M_RD, .buf = rb, .len = 2 },
69 };
70
71 if (i2c_transfer(state->i2c_adap, msg, 2) != 2)
Patrick Boettcherb6884a12007-07-27 10:08:51 -030072 dprintk("i2c read error on %d",reg);
Patrick Boettchera75763f2006-10-18 08:34:16 -030073
74 return (rb[0] << 8) | rb[1];
75}
76
77static int dib7000p_write_word(struct dib7000p_state *state, u16 reg, u16 val)
78{
79 u8 b[4] = {
80 (reg >> 8) & 0xff, reg & 0xff,
81 (val >> 8) & 0xff, val & 0xff,
82 };
83 struct i2c_msg msg = {
84 .addr = state->i2c_addr >> 1, .flags = 0, .buf = b, .len = 4
85 };
86 return i2c_transfer(state->i2c_adap, &msg, 1) != 1 ? -EREMOTEIO : 0;
87}
Patrick Boettcherb6884a12007-07-27 10:08:51 -030088static void dib7000p_write_tab(struct dib7000p_state *state, u16 *buf)
89{
90 u16 l = 0, r, *n;
91 n = buf;
92 l = *n++;
93 while (l) {
94 r = *n++;
95
96 do {
97 dib7000p_write_word(state, r, *n++);
98 r++;
99 } while (--l);
100 l = *n++;
101 }
102}
103
Patrick Boettchera75763f2006-10-18 08:34:16 -0300104static int dib7000p_set_output_mode(struct dib7000p_state *state, int mode)
105{
106 int ret = 0;
107 u16 outreg, fifo_threshold, smo_mode;
108
109 outreg = 0;
110 fifo_threshold = 1792;
Olivier Grenieeac1fe12009-09-23 13:41:27 -0300111 smo_mode = (dib7000p_read_word(state, 235) & 0x0050) | (1 << 1);
Patrick Boettchera75763f2006-10-18 08:34:16 -0300112
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300113 dprintk( "setting output mode for demod %p to %d",
Patrick Boettchera75763f2006-10-18 08:34:16 -0300114 &state->demod, mode);
115
116 switch (mode) {
117 case OUTMODE_MPEG2_PAR_GATED_CLK: // STBs with parallel gated clock
118 outreg = (1 << 10); /* 0x0400 */
119 break;
120 case OUTMODE_MPEG2_PAR_CONT_CLK: // STBs with parallel continues clock
121 outreg = (1 << 10) | (1 << 6); /* 0x0440 */
122 break;
123 case OUTMODE_MPEG2_SERIAL: // STBs with serial input
124 outreg = (1 << 10) | (2 << 6) | (0 << 1); /* 0x0480 */
125 break;
126 case OUTMODE_DIVERSITY:
127 if (state->cfg.hostbus_diversity)
128 outreg = (1 << 10) | (4 << 6); /* 0x0500 */
129 else
130 outreg = (1 << 11);
131 break;
132 case OUTMODE_MPEG2_FIFO: // e.g. USB feeding
133 smo_mode |= (3 << 1);
134 fifo_threshold = 512;
135 outreg = (1 << 10) | (5 << 6);
136 break;
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300137 case OUTMODE_ANALOG_ADC:
138 outreg = (1 << 10) | (3 << 6);
139 break;
Patrick Boettchera75763f2006-10-18 08:34:16 -0300140 case OUTMODE_HIGH_Z: // disable
141 outreg = 0;
142 break;
143 default:
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300144 dprintk( "Unhandled output_mode passed to be set for demod %p",&state->demod);
Patrick Boettchera75763f2006-10-18 08:34:16 -0300145 break;
146 }
147
148 if (state->cfg.output_mpeg2_in_188_bytes)
149 smo_mode |= (1 << 5) ;
150
151 ret |= dib7000p_write_word(state, 235, smo_mode);
152 ret |= dib7000p_write_word(state, 236, fifo_threshold); /* synchronous fread */
153 ret |= dib7000p_write_word(state, 1286, outreg); /* P_Div_active */
154
155 return ret;
156}
157
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300158static int dib7000p_set_diversity_in(struct dvb_frontend *demod, int onoff)
159{
160 struct dib7000p_state *state = demod->demodulator_priv;
161
162 if (state->div_force_off) {
163 dprintk( "diversity combination deactivated - forced by COFDM parameters");
164 onoff = 0;
Olivier Grenieeac1fe12009-09-23 13:41:27 -0300165 dib7000p_write_word(state, 207, 0);
166 } else
167 dib7000p_write_word(state, 207, (state->div_sync_wait << 4) | (1 << 2) | (2 << 0));
168
Patrick Boettcher01373a52007-07-30 12:49:04 -0300169 state->div_state = (u8)onoff;
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300170
171 if (onoff) {
172 dib7000p_write_word(state, 204, 6);
173 dib7000p_write_word(state, 205, 16);
174 /* P_dvsy_sync_mode = 0, P_dvsy_sync_enable=1, P_dvcb_comb_mode=2 */
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300175 } else {
176 dib7000p_write_word(state, 204, 1);
177 dib7000p_write_word(state, 205, 0);
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300178 }
179
180 return 0;
181}
182
Patrick Boettchera75763f2006-10-18 08:34:16 -0300183static int dib7000p_set_power_mode(struct dib7000p_state *state, enum dib7000p_power_mode mode)
184{
185 /* by default everything is powered off */
186 u16 reg_774 = 0xffff, reg_775 = 0xffff, reg_776 = 0x0007, reg_899 = 0x0003,
187 reg_1280 = (0xfe00) | (dib7000p_read_word(state, 1280) & 0x01ff);
188
189 /* now, depending on the requested mode, we power on */
190 switch (mode) {
191 /* power up everything in the demod */
192 case DIB7000P_POWER_ALL:
193 reg_774 = 0x0000; reg_775 = 0x0000; reg_776 = 0x0; reg_899 = 0x0; reg_1280 &= 0x01ff;
194 break;
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300195
196 case DIB7000P_POWER_ANALOG_ADC:
197 /* dem, cfg, iqc, sad, agc */
198 reg_774 &= ~((1 << 15) | (1 << 14) | (1 << 11) | (1 << 10) | (1 << 9));
199 /* nud */
200 reg_776 &= ~((1 << 0));
201 /* Dout */
202 reg_1280 &= ~((1 << 11));
203 /* fall through wanted to enable the interfaces */
204
Patrick Boettchera75763f2006-10-18 08:34:16 -0300205 /* just leave power on the control-interfaces: GPIO and (I2C or SDIO) */
206 case DIB7000P_POWER_INTERFACE_ONLY: /* TODO power up either SDIO or I2C */
207 reg_1280 &= ~((1 << 14) | (1 << 13) | (1 << 12) | (1 << 10));
208 break;
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300209
Patrick Boettchera75763f2006-10-18 08:34:16 -0300210/* TODO following stuff is just converted from the dib7000-driver - check when is used what */
211 }
212
213 dib7000p_write_word(state, 774, reg_774);
214 dib7000p_write_word(state, 775, reg_775);
215 dib7000p_write_word(state, 776, reg_776);
216 dib7000p_write_word(state, 899, reg_899);
217 dib7000p_write_word(state, 1280, reg_1280);
218
219 return 0;
220}
221
222static void dib7000p_set_adc_state(struct dib7000p_state *state, enum dibx000_adc_states no)
223{
224 u16 reg_908 = dib7000p_read_word(state, 908),
225 reg_909 = dib7000p_read_word(state, 909);
226
227 switch (no) {
228 case DIBX000_SLOW_ADC_ON:
229 reg_909 |= (1 << 1) | (1 << 0);
230 dib7000p_write_word(state, 909, reg_909);
231 reg_909 &= ~(1 << 1);
232 break;
233
234 case DIBX000_SLOW_ADC_OFF:
235 reg_909 |= (1 << 1) | (1 << 0);
236 break;
237
238 case DIBX000_ADC_ON:
239 reg_908 &= 0x0fff;
240 reg_909 &= 0x0003;
241 break;
242
243 case DIBX000_ADC_OFF: // leave the VBG voltage on
244 reg_908 |= (1 << 14) | (1 << 13) | (1 << 12);
245 reg_909 |= (1 << 5) | (1 << 4) | (1 << 3) | (1 << 2);
246 break;
247
248 case DIBX000_VBG_ENABLE:
249 reg_908 &= ~(1 << 15);
250 break;
251
252 case DIBX000_VBG_DISABLE:
253 reg_908 |= (1 << 15);
254 break;
255
256 default:
257 break;
258 }
259
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300260// dprintk( "908: %x, 909: %x\n", reg_908, reg_909);
Patrick Boettchera75763f2006-10-18 08:34:16 -0300261
262 dib7000p_write_word(state, 908, reg_908);
263 dib7000p_write_word(state, 909, reg_909);
264}
265
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300266static int dib7000p_set_bandwidth(struct dib7000p_state *state, u32 bw)
Patrick Boettchera75763f2006-10-18 08:34:16 -0300267{
Patrick Boettchera75763f2006-10-18 08:34:16 -0300268 u32 timf;
269
270 // store the current bandwidth for later use
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300271 state->current_bandwidth = bw;
Patrick Boettchera75763f2006-10-18 08:34:16 -0300272
273 if (state->timf == 0) {
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300274 dprintk( "using default timf");
Patrick Boettchera75763f2006-10-18 08:34:16 -0300275 timf = state->cfg.bw->timf;
276 } else {
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300277 dprintk( "using updated timf");
Patrick Boettchera75763f2006-10-18 08:34:16 -0300278 timf = state->timf;
279 }
280
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300281 timf = timf * (bw / 50) / 160;
Patrick Boettchera75763f2006-10-18 08:34:16 -0300282
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300283 dib7000p_write_word(state, 23, (u16) ((timf >> 16) & 0xffff));
284 dib7000p_write_word(state, 24, (u16) ((timf ) & 0xffff));
Patrick Boettchera75763f2006-10-18 08:34:16 -0300285
286 return 0;
287}
288
289static int dib7000p_sad_calib(struct dib7000p_state *state)
290{
291/* internal */
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300292// dib7000p_write_word(state, 72, (3 << 14) | (1 << 12) | (524 << 0)); // sampling clock of the SAD is writting in set_bandwidth
Patrick Boettchera75763f2006-10-18 08:34:16 -0300293 dib7000p_write_word(state, 73, (0 << 1) | (0 << 0));
294 dib7000p_write_word(state, 74, 776); // 0.625*3.3 / 4096
295
296 /* do the calibration */
297 dib7000p_write_word(state, 73, (1 << 0));
298 dib7000p_write_word(state, 73, (0 << 0));
299
300 msleep(1);
301
302 return 0;
303}
304
Patrick Boettcher01373a52007-07-30 12:49:04 -0300305int dib7000p_set_wbd_ref(struct dvb_frontend *demod, u16 value)
306{
307 struct dib7000p_state *state = demod->demodulator_priv;
308 if (value > 4095)
309 value = 4095;
310 state->wbd_ref = value;
311 return dib7000p_write_word(state, 105, (dib7000p_read_word(state, 105) & 0xf000) | value);
312}
313
314EXPORT_SYMBOL(dib7000p_set_wbd_ref);
Patrick Boettchera75763f2006-10-18 08:34:16 -0300315static void dib7000p_reset_pll(struct dib7000p_state *state)
316{
317 struct dibx000_bandwidth_config *bw = &state->cfg.bw[0];
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300318 u16 clk_cfg0;
Patrick Boettchera75763f2006-10-18 08:34:16 -0300319
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300320 /* force PLL bypass */
321 clk_cfg0 = (1 << 15) | ((bw->pll_ratio & 0x3f) << 9) |
322 (bw->modulo << 7) | (bw->ADClkSrc << 6) | (bw->IO_CLK_en_core << 5) |
323 (bw->bypclk_div << 2) | (bw->enable_refdiv << 1) | (0 << 0);
324
325 dib7000p_write_word(state, 900, clk_cfg0);
326
327 /* P_pll_cfg */
Patrick Boettchera75763f2006-10-18 08:34:16 -0300328 dib7000p_write_word(state, 903, (bw->pll_prediv << 5) | (((bw->pll_ratio >> 6) & 0x3) << 3) | (bw->pll_range << 1) | bw->pll_reset);
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300329 clk_cfg0 = (bw->pll_bypass << 15) | (clk_cfg0 & 0x7fff);
330 dib7000p_write_word(state, 900, clk_cfg0);
Patrick Boettchera75763f2006-10-18 08:34:16 -0300331
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300332 dib7000p_write_word(state, 18, (u16) (((bw->internal*1000) >> 16) & 0xffff));
333 dib7000p_write_word(state, 19, (u16) ( (bw->internal*1000 ) & 0xffff));
334 dib7000p_write_word(state, 21, (u16) ( (bw->ifreq >> 16) & 0xffff));
335 dib7000p_write_word(state, 22, (u16) ( (bw->ifreq ) & 0xffff));
Patrick Boettchera75763f2006-10-18 08:34:16 -0300336
337 dib7000p_write_word(state, 72, bw->sad_cfg);
338}
339
340static int dib7000p_reset_gpio(struct dib7000p_state *st)
341{
342 /* reset the GPIOs */
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300343 dprintk( "gpio dir: %x: val: %x, pwm_pos: %x",st->gpio_dir, st->gpio_val,st->cfg.gpio_pwm_pos);
Patrick Boettchera75763f2006-10-18 08:34:16 -0300344
345 dib7000p_write_word(st, 1029, st->gpio_dir);
346 dib7000p_write_word(st, 1030, st->gpio_val);
347
348 /* TODO 1031 is P_gpio_od */
349
350 dib7000p_write_word(st, 1032, st->cfg.gpio_pwm_pos);
351
352 dib7000p_write_word(st, 1037, st->cfg.pwm_freq_div);
353 return 0;
354}
355
Patrick Boettcher01373a52007-07-30 12:49:04 -0300356static int dib7000p_cfg_gpio(struct dib7000p_state *st, u8 num, u8 dir, u8 val)
357{
358 st->gpio_dir = dib7000p_read_word(st, 1029);
359 st->gpio_dir &= ~(1 << num); /* reset the direction bit */
360 st->gpio_dir |= (dir & 0x1) << num; /* set the new direction */
361 dib7000p_write_word(st, 1029, st->gpio_dir);
362
363 st->gpio_val = dib7000p_read_word(st, 1030);
364 st->gpio_val &= ~(1 << num); /* reset the direction bit */
365 st->gpio_val |= (val & 0x01) << num; /* set the new value */
366 dib7000p_write_word(st, 1030, st->gpio_val);
367
368 return 0;
369}
370
371int dib7000p_set_gpio(struct dvb_frontend *demod, u8 num, u8 dir, u8 val)
372{
373 struct dib7000p_state *state = demod->demodulator_priv;
374 return dib7000p_cfg_gpio(state, num, dir, val);
375}
376
377EXPORT_SYMBOL(dib7000p_set_gpio);
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300378static u16 dib7000p_defaults[] =
379
380{
381 // auto search configuration
382 3, 2,
383 0x0004,
384 0x1000,
385 0x0814, /* Equal Lock */
386
387 12, 6,
388 0x001b,
389 0x7740,
390 0x005b,
391 0x8d80,
392 0x01c9,
393 0xc380,
394 0x0000,
395 0x0080,
396 0x0000,
397 0x0090,
398 0x0001,
399 0xd4c0,
400
401 1, 26,
402 0x6680, // P_timf_alpha=6, P_corm_alpha=6, P_corm_thres=128 default: 6,4,26
403
404 /* set ADC level to -16 */
405 11, 79,
406 (1 << 13) - 825 - 117,
407 (1 << 13) - 837 - 117,
408 (1 << 13) - 811 - 117,
409 (1 << 13) - 766 - 117,
410 (1 << 13) - 737 - 117,
411 (1 << 13) - 693 - 117,
412 (1 << 13) - 648 - 117,
413 (1 << 13) - 619 - 117,
414 (1 << 13) - 575 - 117,
415 (1 << 13) - 531 - 117,
416 (1 << 13) - 501 - 117,
417
418 1, 142,
419 0x0410, // P_palf_filter_on=1, P_palf_filter_freeze=0, P_palf_alpha_regul=16
420
421 /* disable power smoothing */
422 8, 145,
423 0,
424 0,
425 0,
426 0,
427 0,
428 0,
429 0,
430 0,
431
432 1, 154,
433 1 << 13, // P_fft_freq_dir=1, P_fft_nb_to_cut=0
434
435 1, 168,
436 0x0ccd, // P_pha3_thres, default 0x3000
437
438// 1, 169,
439// 0x0010, // P_cti_use_cpe=0, P_cti_use_prog=0, P_cti_win_len=16, default: 0x0010
440
441 1, 183,
442 0x200f, // P_cspu_regul=512, P_cspu_win_cut=15, default: 0x2005
443
444 5, 187,
445 0x023d, // P_adp_regul_cnt=573, default: 410
446 0x00a4, // P_adp_noise_cnt=
447 0x00a4, // P_adp_regul_ext
448 0x7ff0, // P_adp_noise_ext
449 0x3ccc, // P_adp_fil
450
451 1, 198,
452 0x800, // P_equal_thres_wgn
453
454 1, 222,
455 0x0010, // P_fec_ber_rs_len=2
456
457 1, 235,
458 0x0062, // P_smo_mode, P_smo_rs_discard, P_smo_fifo_flush, P_smo_pid_parse, P_smo_error_discard
459
460 2, 901,
461 0x0006, // P_clk_cfg1
462 (3 << 10) | (1 << 6), // P_divclksel=3 P_divbitsel=1
463
464 1, 905,
465 0x2c8e, // Tuner IO bank: max drive (14mA) + divout pads max drive
466
467 0,
468};
469
Patrick Boettchera75763f2006-10-18 08:34:16 -0300470static int dib7000p_demod_reset(struct dib7000p_state *state)
471{
472 dib7000p_set_power_mode(state, DIB7000P_POWER_ALL);
473
474 dib7000p_set_adc_state(state, DIBX000_VBG_ENABLE);
475
476 /* restart all parts */
477 dib7000p_write_word(state, 770, 0xffff);
478 dib7000p_write_word(state, 771, 0xffff);
479 dib7000p_write_word(state, 772, 0x001f);
480 dib7000p_write_word(state, 898, 0x0003);
481 /* except i2c, sdio, gpio - control interfaces */
482 dib7000p_write_word(state, 1280, 0x01fc - ((1 << 7) | (1 << 6) | (1 << 5)) );
483
484 dib7000p_write_word(state, 770, 0);
485 dib7000p_write_word(state, 771, 0);
486 dib7000p_write_word(state, 772, 0);
487 dib7000p_write_word(state, 898, 0);
488 dib7000p_write_word(state, 1280, 0);
489
490 /* default */
491 dib7000p_reset_pll(state);
492
493 if (dib7000p_reset_gpio(state) != 0)
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300494 dprintk( "GPIO reset was not successful.");
Patrick Boettchera75763f2006-10-18 08:34:16 -0300495
496 if (dib7000p_set_output_mode(state, OUTMODE_HIGH_Z) != 0)
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300497 dprintk( "OUTPUT_MODE could not be reset.");
Patrick Boettchera75763f2006-10-18 08:34:16 -0300498
499 /* unforce divstr regardless whether i2c enumeration was done or not */
500 dib7000p_write_word(state, 1285, dib7000p_read_word(state, 1285) & ~(1 << 1) );
501
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300502 dib7000p_set_bandwidth(state, 8000);
503
504 dib7000p_set_adc_state(state, DIBX000_SLOW_ADC_ON);
505 dib7000p_sad_calib(state);
506 dib7000p_set_adc_state(state, DIBX000_SLOW_ADC_OFF);
507
508 // P_iqc_alpha_pha, P_iqc_alpha_amp_dcc_alpha, ...
509 if(state->cfg.tuner_is_baseband)
510 dib7000p_write_word(state, 36,0x0755);
511 else
512 dib7000p_write_word(state, 36,0x1f55);
513
514 dib7000p_write_tab(state, dib7000p_defaults);
515
Patrick Boettchera75763f2006-10-18 08:34:16 -0300516 dib7000p_set_power_mode(state, DIB7000P_POWER_INTERFACE_ONLY);
517
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300518
Patrick Boettchera75763f2006-10-18 08:34:16 -0300519 return 0;
520}
521
Patrick Boettchera75763f2006-10-18 08:34:16 -0300522static void dib7000p_pll_clk_cfg(struct dib7000p_state *state)
523{
524 u16 tmp = 0;
525 tmp = dib7000p_read_word(state, 903);
526 dib7000p_write_word(state, 903, (tmp | 0x1)); //pwr-up pll
527 tmp = dib7000p_read_word(state, 900);
528 dib7000p_write_word(state, 900, (tmp & 0x7fff) | (1 << 6)); //use High freq clock
529}
530
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300531static void dib7000p_restart_agc(struct dib7000p_state *state)
Patrick Boettchera75763f2006-10-18 08:34:16 -0300532{
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300533 // P_restart_iqc & P_restart_agc
534 dib7000p_write_word(state, 770, (1 << 11) | (1 << 9));
535 dib7000p_write_word(state, 770, 0x0000);
Patrick Boettchera75763f2006-10-18 08:34:16 -0300536}
537
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300538static int dib7000p_update_lna(struct dib7000p_state *state)
Patrick Boettchera75763f2006-10-18 08:34:16 -0300539{
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300540 u16 dyn_gain;
541
542 // when there is no LNA to program return immediatly
543 if (state->cfg.update_lna) {
Patrick Boettcher01373a52007-07-30 12:49:04 -0300544 // read dyn_gain here (because it is demod-dependent and not fe)
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300545 dyn_gain = dib7000p_read_word(state, 394);
546 if (state->cfg.update_lna(&state->demod,dyn_gain)) { // LNA has changed
547 dib7000p_restart_agc(state);
548 return 1;
549 }
550 }
551
552 return 0;
553}
554
555static int dib7000p_set_agc_config(struct dib7000p_state *state, u8 band)
556{
557 struct dibx000_agc_config *agc = NULL;
558 int i;
559 if (state->current_band == band && state->current_agc != NULL)
560 return 0;
561 state->current_band = band;
562
563 for (i = 0; i < state->cfg.agc_config_count; i++)
564 if (state->cfg.agc[i].band_caps & band) {
565 agc = &state->cfg.agc[i];
566 break;
567 }
568
569 if (agc == NULL) {
570 dprintk( "no valid AGC configuration found for band 0x%02x",band);
571 return -EINVAL;
572 }
573
574 state->current_agc = agc;
575
576 /* AGC */
577 dib7000p_write_word(state, 75 , agc->setup );
578 dib7000p_write_word(state, 76 , agc->inv_gain );
579 dib7000p_write_word(state, 77 , agc->time_stabiliz );
580 dib7000p_write_word(state, 100, (agc->alpha_level << 12) | agc->thlock);
581
582 // Demod AGC loop configuration
583 dib7000p_write_word(state, 101, (agc->alpha_mant << 5) | agc->alpha_exp);
584 dib7000p_write_word(state, 102, (agc->beta_mant << 6) | agc->beta_exp);
585
586 /* AGC continued */
587 dprintk( "WBD: ref: %d, sel: %d, active: %d, alpha: %d",
588 state->wbd_ref != 0 ? state->wbd_ref : agc->wbd_ref, agc->wbd_sel, !agc->perform_agc_softsplit, agc->wbd_sel);
589
590 if (state->wbd_ref != 0)
591 dib7000p_write_word(state, 105, (agc->wbd_inv << 12) | state->wbd_ref);
592 else
593 dib7000p_write_word(state, 105, (agc->wbd_inv << 12) | agc->wbd_ref);
594
595 dib7000p_write_word(state, 106, (agc->wbd_sel << 13) | (agc->wbd_alpha << 9) | (agc->perform_agc_softsplit << 8));
596
597 dib7000p_write_word(state, 107, agc->agc1_max);
598 dib7000p_write_word(state, 108, agc->agc1_min);
599 dib7000p_write_word(state, 109, agc->agc2_max);
600 dib7000p_write_word(state, 110, agc->agc2_min);
601 dib7000p_write_word(state, 111, (agc->agc1_pt1 << 8) | agc->agc1_pt2);
602 dib7000p_write_word(state, 112, agc->agc1_pt3);
603 dib7000p_write_word(state, 113, (agc->agc1_slope1 << 8) | agc->agc1_slope2);
604 dib7000p_write_word(state, 114, (agc->agc2_pt1 << 8) | agc->agc2_pt2);
605 dib7000p_write_word(state, 115, (agc->agc2_slope1 << 8) | agc->agc2_slope2);
606 return 0;
607}
608
609static int dib7000p_agc_startup(struct dvb_frontend *demod, struct dvb_frontend_parameters *ch)
610{
611 struct dib7000p_state *state = demod->demodulator_priv;
612 int ret = -1;
613 u8 *agc_state = &state->agc_state;
614 u8 agc_split;
615
616 switch (state->agc_state) {
617 case 0:
618 // set power-up level: interf+analog+AGC
619 dib7000p_set_power_mode(state, DIB7000P_POWER_ALL);
620 dib7000p_set_adc_state(state, DIBX000_ADC_ON);
621 dib7000p_pll_clk_cfg(state);
622
623 if (dib7000p_set_agc_config(state, BAND_OF_FREQUENCY(ch->frequency/1000)) != 0)
624 return -1;
625
626 ret = 7;
627 (*agc_state)++;
628 break;
629
630 case 1:
631 // AGC initialization
632 if (state->cfg.agc_control)
633 state->cfg.agc_control(&state->demod, 1);
634
635 dib7000p_write_word(state, 78, 32768);
636 if (!state->current_agc->perform_agc_softsplit) {
637 /* we are using the wbd - so slow AGC startup */
638 /* force 0 split on WBD and restart AGC */
639 dib7000p_write_word(state, 106, (state->current_agc->wbd_sel << 13) | (state->current_agc->wbd_alpha << 9) | (1 << 8));
640 (*agc_state)++;
641 ret = 5;
642 } else {
643 /* default AGC startup */
644 (*agc_state) = 4;
645 /* wait AGC rough lock time */
646 ret = 7;
647 }
648
649 dib7000p_restart_agc(state);
650 break;
651
652 case 2: /* fast split search path after 5sec */
653 dib7000p_write_word(state, 75, state->current_agc->setup | (1 << 4)); /* freeze AGC loop */
654 dib7000p_write_word(state, 106, (state->current_agc->wbd_sel << 13) | (2 << 9) | (0 << 8)); /* fast split search 0.25kHz */
655 (*agc_state)++;
656 ret = 14;
657 break;
658
659 case 3: /* split search ended */
Patrick Boettcher01373a52007-07-30 12:49:04 -0300660 agc_split = (u8)dib7000p_read_word(state, 396); /* store the split value for the next time */
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300661 dib7000p_write_word(state, 78, dib7000p_read_word(state, 394)); /* set AGC gain start value */
662
663 dib7000p_write_word(state, 75, state->current_agc->setup); /* std AGC loop */
664 dib7000p_write_word(state, 106, (state->current_agc->wbd_sel << 13) | (state->current_agc->wbd_alpha << 9) | agc_split); /* standard split search */
665
666 dib7000p_restart_agc(state);
667
668 dprintk( "SPLIT %p: %hd", demod, agc_split);
669
670 (*agc_state)++;
671 ret = 5;
672 break;
673
674 case 4: /* LNA startup */
675 // wait AGC accurate lock time
676 ret = 7;
677
678 if (dib7000p_update_lna(state))
679 // wait only AGC rough lock time
680 ret = 5;
681 else // nothing was done, go to the next state
682 (*agc_state)++;
683 break;
684
685 case 5:
686 if (state->cfg.agc_control)
687 state->cfg.agc_control(&state->demod, 0);
688 (*agc_state)++;
689 break;
690 default:
691 break;
692 }
693 return ret;
694}
695
696static void dib7000p_update_timf(struct dib7000p_state *state)
697{
698 u32 timf = (dib7000p_read_word(state, 427) << 16) | dib7000p_read_word(state, 428);
699 state->timf = timf * 160 / (state->current_bandwidth / 50);
700 dib7000p_write_word(state, 23, (u16) (timf >> 16));
701 dib7000p_write_word(state, 24, (u16) (timf & 0xffff));
702 dprintk( "updated timf_frequency: %d (default: %d)",state->timf, state->cfg.bw->timf);
703
704}
705
706static void dib7000p_set_channel(struct dib7000p_state *state, struct dvb_frontend_parameters *ch, u8 seq)
707{
708 u16 value, est[4];
709
710 dib7000p_set_bandwidth(state, BANDWIDTH_TO_KHZ(ch->u.ofdm.bandwidth));
Patrick Boettchera75763f2006-10-18 08:34:16 -0300711
712 /* nfft, guard, qam, alpha */
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300713 value = 0;
714 switch (ch->u.ofdm.transmission_mode) {
715 case TRANSMISSION_MODE_2K: value |= (0 << 7); break;
716 case /* 4K MODE */ 255: value |= (2 << 7); break;
717 default:
718 case TRANSMISSION_MODE_8K: value |= (1 << 7); break;
719 }
720 switch (ch->u.ofdm.guard_interval) {
721 case GUARD_INTERVAL_1_32: value |= (0 << 5); break;
722 case GUARD_INTERVAL_1_16: value |= (1 << 5); break;
723 case GUARD_INTERVAL_1_4: value |= (3 << 5); break;
724 default:
725 case GUARD_INTERVAL_1_8: value |= (2 << 5); break;
726 }
727 switch (ch->u.ofdm.constellation) {
728 case QPSK: value |= (0 << 3); break;
729 case QAM_16: value |= (1 << 3); break;
730 default:
731 case QAM_64: value |= (2 << 3); break;
732 }
733 switch (HIERARCHY_1) {
734 case HIERARCHY_2: value |= 2; break;
735 case HIERARCHY_4: value |= 4; break;
736 default:
737 case HIERARCHY_1: value |= 1; break;
738 }
739 dib7000p_write_word(state, 0, value);
Patrick Boettchera75763f2006-10-18 08:34:16 -0300740 dib7000p_write_word(state, 5, (seq << 4) | 1); /* do not force tps, search list 0 */
741
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300742 /* P_dintl_native, P_dintlv_inv, P_hrch, P_code_rate, P_select_hp */
743 value = 0;
744 if (1 != 0)
745 value |= (1 << 6);
746 if (ch->u.ofdm.hierarchy_information == 1)
747 value |= (1 << 4);
748 if (1 == 1)
749 value |= 1;
750 switch ((ch->u.ofdm.hierarchy_information == 0 || 1 == 1) ? ch->u.ofdm.code_rate_HP : ch->u.ofdm.code_rate_LP) {
751 case FEC_2_3: value |= (2 << 1); break;
752 case FEC_3_4: value |= (3 << 1); break;
753 case FEC_5_6: value |= (5 << 1); break;
754 case FEC_7_8: value |= (7 << 1); break;
755 default:
756 case FEC_1_2: value |= (1 << 1); break;
757 }
758 dib7000p_write_word(state, 208, value);
759
760 /* offset loop parameters */
761 dib7000p_write_word(state, 26, 0x6680); // timf(6xxx)
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300762 dib7000p_write_word(state, 32, 0x0003); // pha_off_max(xxx3)
Matt Doran8f6956c2007-07-31 07:09:30 -0300763 dib7000p_write_word(state, 29, 0x1273); // isi
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300764 dib7000p_write_word(state, 33, 0x0005); // sfreq(xxx5)
Patrick Boettchera75763f2006-10-18 08:34:16 -0300765
766 /* P_dvsy_sync_wait */
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300767 switch (ch->u.ofdm.transmission_mode) {
768 case TRANSMISSION_MODE_8K: value = 256; break;
769 case /* 4K MODE */ 255: value = 128; break;
770 case TRANSMISSION_MODE_2K:
771 default: value = 64; break;
Patrick Boettchera75763f2006-10-18 08:34:16 -0300772 }
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300773 switch (ch->u.ofdm.guard_interval) {
774 case GUARD_INTERVAL_1_16: value *= 2; break;
775 case GUARD_INTERVAL_1_8: value *= 4; break;
776 case GUARD_INTERVAL_1_4: value *= 8; break;
777 default:
778 case GUARD_INTERVAL_1_32: value *= 1; break;
779 }
780 state->div_sync_wait = (value * 3) / 2 + 32; // add 50% SFN margin + compensate for one DVSY-fifo TODO
Patrick Boettchera75763f2006-10-18 08:34:16 -0300781
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300782 /* deactive the possibility of diversity reception if extended interleaver */
783 state->div_force_off = !1 && ch->u.ofdm.transmission_mode != TRANSMISSION_MODE_8K;
784 dib7000p_set_diversity_in(&state->demod, state->div_state);
Patrick Boettchera75763f2006-10-18 08:34:16 -0300785
786 /* channel estimation fine configuration */
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300787 switch (ch->u.ofdm.constellation) {
788 case QAM_64:
Patrick Boettchera75763f2006-10-18 08:34:16 -0300789 est[0] = 0x0148; /* P_adp_regul_cnt 0.04 */
790 est[1] = 0xfff0; /* P_adp_noise_cnt -0.002 */
791 est[2] = 0x00a4; /* P_adp_regul_ext 0.02 */
792 est[3] = 0xfff8; /* P_adp_noise_ext -0.001 */
793 break;
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300794 case QAM_16:
Patrick Boettchera75763f2006-10-18 08:34:16 -0300795 est[0] = 0x023d; /* P_adp_regul_cnt 0.07 */
796 est[1] = 0xffdf; /* P_adp_noise_cnt -0.004 */
797 est[2] = 0x00a4; /* P_adp_regul_ext 0.02 */
798 est[3] = 0xfff0; /* P_adp_noise_ext -0.002 */
799 break;
800 default:
801 est[0] = 0x099a; /* P_adp_regul_cnt 0.3 */
802 est[1] = 0xffae; /* P_adp_noise_cnt -0.01 */
803 est[2] = 0x0333; /* P_adp_regul_ext 0.1 */
804 est[3] = 0xfff8; /* P_adp_noise_ext -0.002 */
805 break;
806 }
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300807 for (value = 0; value < 4; value++)
808 dib7000p_write_word(state, 187 + value, est[value]);
Patrick Boettchera75763f2006-10-18 08:34:16 -0300809}
810
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300811static int dib7000p_autosearch_start(struct dvb_frontend *demod, struct dvb_frontend_parameters *ch)
Patrick Boettchera75763f2006-10-18 08:34:16 -0300812{
813 struct dib7000p_state *state = demod->demodulator_priv;
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300814 struct dvb_frontend_parameters schan;
815 u32 value, factor;
Patrick Boettchera75763f2006-10-18 08:34:16 -0300816
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300817 schan = *ch;
818 schan.u.ofdm.constellation = QAM_64;
819 schan.u.ofdm.guard_interval = GUARD_INTERVAL_1_32;
820 schan.u.ofdm.transmission_mode = TRANSMISSION_MODE_8K;
821 schan.u.ofdm.code_rate_HP = FEC_2_3;
822 schan.u.ofdm.code_rate_LP = FEC_3_4;
823 schan.u.ofdm.hierarchy_information = 0;
Patrick Boettchera75763f2006-10-18 08:34:16 -0300824
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300825 dib7000p_set_channel(state, &schan, 7);
826
827 factor = BANDWIDTH_TO_KHZ(ch->u.ofdm.bandwidth);
828 if (factor >= 5000)
829 factor = 1;
830 else
831 factor = 6;
Patrick Boettchera75763f2006-10-18 08:34:16 -0300832
833 // always use the setting for 8MHz here lock_time for 7,6 MHz are longer
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300834 value = 30 * state->cfg.bw->internal * factor;
Patrick Boettchera75763f2006-10-18 08:34:16 -0300835 dib7000p_write_word(state, 6, (u16) ((value >> 16) & 0xffff)); // lock0 wait time
836 dib7000p_write_word(state, 7, (u16) (value & 0xffff)); // lock0 wait time
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300837 value = 100 * state->cfg.bw->internal * factor;
Patrick Boettchera75763f2006-10-18 08:34:16 -0300838 dib7000p_write_word(state, 8, (u16) ((value >> 16) & 0xffff)); // lock1 wait time
839 dib7000p_write_word(state, 9, (u16) (value & 0xffff)); // lock1 wait time
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300840 value = 500 * state->cfg.bw->internal * factor;
Patrick Boettchera75763f2006-10-18 08:34:16 -0300841 dib7000p_write_word(state, 10, (u16) ((value >> 16) & 0xffff)); // lock2 wait time
842 dib7000p_write_word(state, 11, (u16) (value & 0xffff)); // lock2 wait time
843
844 value = dib7000p_read_word(state, 0);
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300845 dib7000p_write_word(state, 0, (u16) ((1 << 9) | value));
Patrick Boettchera75763f2006-10-18 08:34:16 -0300846 dib7000p_read_word(state, 1284);
847 dib7000p_write_word(state, 0, (u16) value);
848
849 return 0;
850}
851
852static int dib7000p_autosearch_is_irq(struct dvb_frontend *demod)
853{
854 struct dib7000p_state *state = demod->demodulator_priv;
855 u16 irq_pending = dib7000p_read_word(state, 1284);
856
857 if (irq_pending & 0x1) // failed
858 return 1;
859
860 if (irq_pending & 0x2) // succeeded
861 return 2;
862
863 return 0; // still pending
864}
865
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300866static void dib7000p_spur_protect(struct dib7000p_state *state, u32 rf_khz, u32 bw)
867{
868 static s16 notch[]={16143, 14402, 12238, 9713, 6902, 3888, 759, -2392};
869 static u8 sine [] ={0, 2, 3, 5, 6, 8, 9, 11, 13, 14, 16, 17, 19, 20, 22,
870 24, 25, 27, 28, 30, 31, 33, 34, 36, 38, 39, 41, 42, 44, 45, 47, 48, 50, 51,
871 53, 55, 56, 58, 59, 61, 62, 64, 65, 67, 68, 70, 71, 73, 74, 76, 77, 79, 80,
872 82, 83, 85, 86, 88, 89, 91, 92, 94, 95, 97, 98, 99, 101, 102, 104, 105,
873 107, 108, 109, 111, 112, 114, 115, 117, 118, 119, 121, 122, 123, 125, 126,
874 128, 129, 130, 132, 133, 134, 136, 137, 138, 140, 141, 142, 144, 145, 146,
875 147, 149, 150, 151, 152, 154, 155, 156, 157, 159, 160, 161, 162, 164, 165,
876 166, 167, 168, 170, 171, 172, 173, 174, 175, 177, 178, 179, 180, 181, 182,
877 183, 184, 185, 186, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198,
878 199, 200, 201, 202, 203, 204, 205, 206, 207, 207, 208, 209, 210, 211, 212,
879 213, 214, 215, 215, 216, 217, 218, 219, 220, 220, 221, 222, 223, 224, 224,
880 225, 226, 227, 227, 228, 229, 229, 230, 231, 231, 232, 233, 233, 234, 235,
881 235, 236, 237, 237, 238, 238, 239, 239, 240, 241, 241, 242, 242, 243, 243,
882 244, 244, 245, 245, 245, 246, 246, 247, 247, 248, 248, 248, 249, 249, 249,
883 250, 250, 250, 251, 251, 251, 252, 252, 252, 252, 253, 253, 253, 253, 254,
884 254, 254, 254, 254, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
885 255, 255, 255, 255, 255, 255};
886
887 u32 xtal = state->cfg.bw->xtal_hz / 1000;
Julia Lawall75b697f2009-08-01 16:48:41 -0300888 int f_rel = DIV_ROUND_CLOSEST(rf_khz, xtal) * xtal - rf_khz;
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300889 int k;
890 int coef_re[8],coef_im[8];
891 int bw_khz = bw;
892 u32 pha;
893
894 dprintk( "relative position of the Spur: %dk (RF: %dk, XTAL: %dk)", f_rel, rf_khz, xtal);
895
896
897 if (f_rel < -bw_khz/2 || f_rel > bw_khz/2)
898 return;
899
900 bw_khz /= 100;
901
902 dib7000p_write_word(state, 142 ,0x0610);
903
904 for (k = 0; k < 8; k++) {
905 pha = ((f_rel * (k+1) * 112 * 80/bw_khz) /1000) & 0x3ff;
906
907 if (pha==0) {
908 coef_re[k] = 256;
909 coef_im[k] = 0;
910 } else if(pha < 256) {
911 coef_re[k] = sine[256-(pha&0xff)];
912 coef_im[k] = sine[pha&0xff];
913 } else if (pha == 256) {
914 coef_re[k] = 0;
915 coef_im[k] = 256;
916 } else if (pha < 512) {
917 coef_re[k] = -sine[pha&0xff];
918 coef_im[k] = sine[256 - (pha&0xff)];
919 } else if (pha == 512) {
920 coef_re[k] = -256;
921 coef_im[k] = 0;
922 } else if (pha < 768) {
923 coef_re[k] = -sine[256-(pha&0xff)];
924 coef_im[k] = -sine[pha&0xff];
925 } else if (pha == 768) {
926 coef_re[k] = 0;
927 coef_im[k] = -256;
928 } else {
929 coef_re[k] = sine[pha&0xff];
930 coef_im[k] = -sine[256 - (pha&0xff)];
931 }
932
933 coef_re[k] *= notch[k];
934 coef_re[k] += (1<<14);
935 if (coef_re[k] >= (1<<24))
936 coef_re[k] = (1<<24) - 1;
937 coef_re[k] /= (1<<15);
938
939 coef_im[k] *= notch[k];
940 coef_im[k] += (1<<14);
941 if (coef_im[k] >= (1<<24))
942 coef_im[k] = (1<<24)-1;
943 coef_im[k] /= (1<<15);
944
945 dprintk( "PALF COEF: %d re: %d im: %d", k, coef_re[k], coef_im[k]);
946
947 dib7000p_write_word(state, 143, (0 << 14) | (k << 10) | (coef_re[k] & 0x3ff));
948 dib7000p_write_word(state, 144, coef_im[k] & 0x3ff);
949 dib7000p_write_word(state, 143, (1 << 14) | (k << 10) | (coef_re[k] & 0x3ff));
950 }
951 dib7000p_write_word(state,143 ,0);
952}
953
954static int dib7000p_tune(struct dvb_frontend *demod, struct dvb_frontend_parameters *ch)
Patrick Boettchera75763f2006-10-18 08:34:16 -0300955{
956 struct dib7000p_state *state = demod->demodulator_priv;
957 u16 tmp = 0;
958
959 if (ch != NULL)
960 dib7000p_set_channel(state, ch, 0);
961 else
962 return -EINVAL;
963
964 // restart demod
965 dib7000p_write_word(state, 770, 0x4000);
966 dib7000p_write_word(state, 770, 0x0000);
967 msleep(45);
968
969 /* P_ctrl_inh_cor=0, P_ctrl_alpha_cor=4, P_ctrl_inh_isi=0, P_ctrl_alpha_isi=3, P_ctrl_inh_cor4=1, P_ctrl_alpha_cor4=3 */
Matt Doran8f6956c2007-07-31 07:09:30 -0300970 tmp = (0 << 14) | (4 << 10) | (0 << 9) | (3 << 5) | (1 << 4) | (0x3);
971 if (state->sfn_workaround_active) {
972 dprintk( "SFN workaround is active");
973 tmp |= (1 << 9);
974 dib7000p_write_word(state, 166, 0x4000); // P_pha3_force_pha_shift
975 } else {
976 dib7000p_write_word(state, 166, 0x0000); // P_pha3_force_pha_shift
977 }
978 dib7000p_write_word(state, 29, tmp);
Patrick Boettchera75763f2006-10-18 08:34:16 -0300979
980 // never achieved a lock with that bandwidth so far - wait for osc-freq to update
981 if (state->timf == 0)
982 msleep(200);
983
984 /* offset loop parameters */
985
986 /* P_timf_alpha, P_corm_alpha=6, P_corm_thres=0x80 */
987 tmp = (6 << 8) | 0x80;
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300988 switch (ch->u.ofdm.transmission_mode) {
989 case TRANSMISSION_MODE_2K: tmp |= (7 << 12); break;
990 case /* 4K MODE */ 255: tmp |= (8 << 12); break;
991 default:
992 case TRANSMISSION_MODE_8K: tmp |= (9 << 12); break;
Patrick Boettchera75763f2006-10-18 08:34:16 -0300993 }
994 dib7000p_write_word(state, 26, tmp); /* timf_a(6xxx) */
995
996 /* P_ctrl_freeze_pha_shift=0, P_ctrl_pha_off_max */
997 tmp = (0 << 4);
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300998 switch (ch->u.ofdm.transmission_mode) {
999 case TRANSMISSION_MODE_2K: tmp |= 0x6; break;
1000 case /* 4K MODE */ 255: tmp |= 0x7; break;
1001 default:
1002 case TRANSMISSION_MODE_8K: tmp |= 0x8; break;
Patrick Boettchera75763f2006-10-18 08:34:16 -03001003 }
1004 dib7000p_write_word(state, 32, tmp);
1005
1006 /* P_ctrl_sfreq_inh=0, P_ctrl_sfreq_step */
1007 tmp = (0 << 4);
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001008 switch (ch->u.ofdm.transmission_mode) {
1009 case TRANSMISSION_MODE_2K: tmp |= 0x6; break;
1010 case /* 4K MODE */ 255: tmp |= 0x7; break;
1011 default:
1012 case TRANSMISSION_MODE_8K: tmp |= 0x8; break;
Patrick Boettchera75763f2006-10-18 08:34:16 -03001013 }
1014 dib7000p_write_word(state, 33, tmp);
1015
1016 tmp = dib7000p_read_word(state,509);
1017 if (!((tmp >> 6) & 0x1)) {
1018 /* restart the fec */
1019 tmp = dib7000p_read_word(state,771);
1020 dib7000p_write_word(state, 771, tmp | (1 << 1));
1021 dib7000p_write_word(state, 771, tmp);
1022 msleep(10);
1023 tmp = dib7000p_read_word(state,509);
1024 }
1025
1026 // we achieved a lock - it's time to update the osc freq
1027 if ((tmp >> 6) & 0x1)
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001028 dib7000p_update_timf(state);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001029
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001030 if (state->cfg.spur_protect)
1031 dib7000p_spur_protect(state, ch->frequency/1000, BANDWIDTH_TO_KHZ(ch->u.ofdm.bandwidth));
1032
1033 dib7000p_set_bandwidth(state, BANDWIDTH_TO_KHZ(ch->u.ofdm.bandwidth));
Patrick Boettchera75763f2006-10-18 08:34:16 -03001034 return 0;
1035}
1036
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001037static int dib7000p_wakeup(struct dvb_frontend *demod)
Patrick Boettchera75763f2006-10-18 08:34:16 -03001038{
Patrick Boettchera75763f2006-10-18 08:34:16 -03001039 struct dib7000p_state *state = demod->demodulator_priv;
Patrick Boettchera75763f2006-10-18 08:34:16 -03001040 dib7000p_set_power_mode(state, DIB7000P_POWER_ALL);
1041 dib7000p_set_adc_state(state, DIBX000_SLOW_ADC_ON);
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001042 return 0;
Patrick Boettchera75763f2006-10-18 08:34:16 -03001043}
1044
1045static int dib7000p_sleep(struct dvb_frontend *demod)
1046{
1047 struct dib7000p_state *state = demod->demodulator_priv;
1048 return dib7000p_set_output_mode(state, OUTMODE_HIGH_Z) | dib7000p_set_power_mode(state, DIB7000P_POWER_INTERFACE_ONLY);
1049}
1050
1051static int dib7000p_identify(struct dib7000p_state *st)
1052{
1053 u16 value;
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001054 dprintk( "checking demod on I2C address: %d (%x)",
Patrick Boettchera75763f2006-10-18 08:34:16 -03001055 st->i2c_addr, st->i2c_addr);
1056
1057 if ((value = dib7000p_read_word(st, 768)) != 0x01b3) {
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001058 dprintk( "wrong Vendor ID (read=0x%x)",value);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001059 return -EREMOTEIO;
1060 }
1061
1062 if ((value = dib7000p_read_word(st, 769)) != 0x4000) {
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001063 dprintk( "wrong Device ID (%x)",value);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001064 return -EREMOTEIO;
1065 }
1066
1067 return 0;
1068}
1069
1070
1071static int dib7000p_get_frontend(struct dvb_frontend* fe,
1072 struct dvb_frontend_parameters *fep)
1073{
1074 struct dib7000p_state *state = fe->demodulator_priv;
1075 u16 tps = dib7000p_read_word(state,463);
1076
1077 fep->inversion = INVERSION_AUTO;
1078
Patrick Boettcher904a82e2008-01-25 07:31:58 -03001079 fep->u.ofdm.bandwidth = BANDWIDTH_TO_INDEX(state->current_bandwidth);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001080
1081 switch ((tps >> 8) & 0x3) {
1082 case 0: fep->u.ofdm.transmission_mode = TRANSMISSION_MODE_2K; break;
1083 case 1: fep->u.ofdm.transmission_mode = TRANSMISSION_MODE_8K; break;
1084 /* case 2: fep->u.ofdm.transmission_mode = TRANSMISSION_MODE_4K; break; */
1085 }
1086
1087 switch (tps & 0x3) {
1088 case 0: fep->u.ofdm.guard_interval = GUARD_INTERVAL_1_32; break;
1089 case 1: fep->u.ofdm.guard_interval = GUARD_INTERVAL_1_16; break;
1090 case 2: fep->u.ofdm.guard_interval = GUARD_INTERVAL_1_8; break;
1091 case 3: fep->u.ofdm.guard_interval = GUARD_INTERVAL_1_4; break;
1092 }
1093
1094 switch ((tps >> 14) & 0x3) {
1095 case 0: fep->u.ofdm.constellation = QPSK; break;
1096 case 1: fep->u.ofdm.constellation = QAM_16; break;
1097 case 2:
1098 default: fep->u.ofdm.constellation = QAM_64; break;
1099 }
1100
1101 /* as long as the frontend_param structure is fixed for hierarchical transmission I refuse to use it */
1102 /* (tps >> 13) & 0x1 == hrch is used, (tps >> 10) & 0x7 == alpha */
1103
1104 fep->u.ofdm.hierarchy_information = HIERARCHY_NONE;
1105 switch ((tps >> 5) & 0x7) {
1106 case 1: fep->u.ofdm.code_rate_HP = FEC_1_2; break;
1107 case 2: fep->u.ofdm.code_rate_HP = FEC_2_3; break;
1108 case 3: fep->u.ofdm.code_rate_HP = FEC_3_4; break;
1109 case 5: fep->u.ofdm.code_rate_HP = FEC_5_6; break;
1110 case 7:
1111 default: fep->u.ofdm.code_rate_HP = FEC_7_8; break;
1112
1113 }
1114
1115 switch ((tps >> 2) & 0x7) {
1116 case 1: fep->u.ofdm.code_rate_LP = FEC_1_2; break;
1117 case 2: fep->u.ofdm.code_rate_LP = FEC_2_3; break;
1118 case 3: fep->u.ofdm.code_rate_LP = FEC_3_4; break;
1119 case 5: fep->u.ofdm.code_rate_LP = FEC_5_6; break;
1120 case 7:
1121 default: fep->u.ofdm.code_rate_LP = FEC_7_8; break;
1122 }
1123
1124 /* native interleaver: (dib7000p_read_word(state, 464) >> 5) & 0x1 */
1125
1126 return 0;
1127}
1128
1129static int dib7000p_set_frontend(struct dvb_frontend* fe,
1130 struct dvb_frontend_parameters *fep)
1131{
1132 struct dib7000p_state *state = fe->demodulator_priv;
Soeren Moch853ea132008-01-25 06:27:06 -03001133 int time, ret;
Patrick Boettchera75763f2006-10-18 08:34:16 -03001134
Soeren Moch853ea132008-01-25 06:27:06 -03001135 dib7000p_set_output_mode(state, OUTMODE_HIGH_Z);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001136
Patrick Boettcher904a82e2008-01-25 07:31:58 -03001137 /* maybe the parameter has been changed */
Matt Doran8f6956c2007-07-31 07:09:30 -03001138 state->sfn_workaround_active = buggy_sfn_workaround;
1139
Patrick Boettchera75763f2006-10-18 08:34:16 -03001140 if (fe->ops.tuner_ops.set_params)
1141 fe->ops.tuner_ops.set_params(fe, fep);
1142
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001143 /* start up the AGC */
1144 state->agc_state = 0;
1145 do {
1146 time = dib7000p_agc_startup(fe, fep);
1147 if (time != -1)
1148 msleep(time);
1149 } while (time != -1);
1150
Patrick Boettchera75763f2006-10-18 08:34:16 -03001151 if (fep->u.ofdm.transmission_mode == TRANSMISSION_MODE_AUTO ||
1152 fep->u.ofdm.guard_interval == GUARD_INTERVAL_AUTO ||
1153 fep->u.ofdm.constellation == QAM_AUTO ||
1154 fep->u.ofdm.code_rate_HP == FEC_AUTO) {
1155 int i = 800, found;
1156
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001157 dib7000p_autosearch_start(fe, fep);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001158 do {
1159 msleep(1);
1160 found = dib7000p_autosearch_is_irq(fe);
1161 } while (found == 0 && i--);
1162
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001163 dprintk("autosearch returns: %d",found);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001164 if (found == 0 || found == 1)
1165 return 0; // no channel found
1166
1167 dib7000p_get_frontend(fe, fep);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001168 }
1169
Soeren Moch853ea132008-01-25 06:27:06 -03001170 ret = dib7000p_tune(fe, fep);
1171
Patrick Boettchera75763f2006-10-18 08:34:16 -03001172 /* make this a config parameter */
Steven Totha38d6e32008-04-22 15:37:01 -03001173 dib7000p_set_output_mode(state, state->cfg.output_mode);
Soeren Moch853ea132008-01-25 06:27:06 -03001174 return ret;
Patrick Boettchera75763f2006-10-18 08:34:16 -03001175}
1176
1177static int dib7000p_read_status(struct dvb_frontend *fe, fe_status_t *stat)
1178{
1179 struct dib7000p_state *state = fe->demodulator_priv;
1180 u16 lock = dib7000p_read_word(state, 509);
1181
1182 *stat = 0;
1183
1184 if (lock & 0x8000)
1185 *stat |= FE_HAS_SIGNAL;
1186 if (lock & 0x3000)
1187 *stat |= FE_HAS_CARRIER;
1188 if (lock & 0x0100)
1189 *stat |= FE_HAS_VITERBI;
1190 if (lock & 0x0010)
1191 *stat |= FE_HAS_SYNC;
Olivier Grenieeac1fe12009-09-23 13:41:27 -03001192 if ((lock & 0x0038) == 0x38)
Patrick Boettchera75763f2006-10-18 08:34:16 -03001193 *stat |= FE_HAS_LOCK;
1194
1195 return 0;
1196}
1197
1198static int dib7000p_read_ber(struct dvb_frontend *fe, u32 *ber)
1199{
1200 struct dib7000p_state *state = fe->demodulator_priv;
1201 *ber = (dib7000p_read_word(state, 500) << 16) | dib7000p_read_word(state, 501);
1202 return 0;
1203}
1204
1205static int dib7000p_read_unc_blocks(struct dvb_frontend *fe, u32 *unc)
1206{
1207 struct dib7000p_state *state = fe->demodulator_priv;
1208 *unc = dib7000p_read_word(state, 506);
1209 return 0;
1210}
1211
1212static int dib7000p_read_signal_strength(struct dvb_frontend *fe, u16 *strength)
1213{
1214 struct dib7000p_state *state = fe->demodulator_priv;
1215 u16 val = dib7000p_read_word(state, 394);
1216 *strength = 65535 - val;
1217 return 0;
1218}
1219
1220static int dib7000p_read_snr(struct dvb_frontend* fe, u16 *snr)
1221{
Olivier Grenieef801962009-09-15 06:46:52 -03001222 struct dib7000p_state *state = fe->demodulator_priv;
1223 u16 val;
1224 s32 signal_mant, signal_exp, noise_mant, noise_exp;
1225 u32 result = 0;
1226
1227 val = dib7000p_read_word(state, 479);
1228 noise_mant = (val >> 4) & 0xff;
1229 noise_exp = ((val & 0xf) << 2);
1230 val = dib7000p_read_word(state, 480);
1231 noise_exp += ((val >> 14) & 0x3);
1232 if ((noise_exp & 0x20) != 0)
1233 noise_exp -= 0x40;
1234
1235 signal_mant = (val >> 6) & 0xFF;
1236 signal_exp = (val & 0x3F);
1237 if ((signal_exp & 0x20) != 0)
1238 signal_exp -= 0x40;
1239
1240 if (signal_mant != 0)
1241 result = intlog10(2) * 10 * signal_exp + 10 *
1242 intlog10(signal_mant);
1243 else
1244 result = intlog10(2) * 10 * signal_exp - 100;
1245
1246 if (noise_mant != 0)
1247 result -= intlog10(2) * 10 * noise_exp + 10 *
1248 intlog10(noise_mant);
1249 else
1250 result -= intlog10(2) * 10 * noise_exp - 100;
1251
1252 *snr = result / ((1 << 24) / 10);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001253 return 0;
1254}
1255
1256static int dib7000p_fe_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings *tune)
1257{
1258 tune->min_delay_ms = 1000;
1259 return 0;
1260}
1261
1262static void dib7000p_release(struct dvb_frontend *demod)
1263{
1264 struct dib7000p_state *st = demod->demodulator_priv;
1265 dibx000_exit_i2c_master(&st->i2c_master);
1266 kfree(st);
1267}
1268
1269int dib7000pc_detection(struct i2c_adapter *i2c_adap)
1270{
1271 u8 tx[2], rx[2];
1272 struct i2c_msg msg[2] = {
1273 { .addr = 18 >> 1, .flags = 0, .buf = tx, .len = 2 },
1274 { .addr = 18 >> 1, .flags = I2C_M_RD, .buf = rx, .len = 2 },
1275 };
1276
1277 tx[0] = 0x03;
1278 tx[1] = 0x00;
1279
1280 if (i2c_transfer(i2c_adap, msg, 2) == 2)
1281 if (rx[0] == 0x01 && rx[1] == 0xb3) {
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001282 dprintk("-D- DiB7000PC detected");
Patrick Boettchera75763f2006-10-18 08:34:16 -03001283 return 1;
1284 }
1285
1286 msg[0].addr = msg[1].addr = 0x40;
1287
1288 if (i2c_transfer(i2c_adap, msg, 2) == 2)
1289 if (rx[0] == 0x01 && rx[1] == 0xb3) {
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001290 dprintk("-D- DiB7000PC detected");
Patrick Boettchera75763f2006-10-18 08:34:16 -03001291 return 1;
1292 }
1293
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001294 dprintk("-D- DiB7000PC not detected");
Patrick Boettchera75763f2006-10-18 08:34:16 -03001295 return 0;
1296}
1297EXPORT_SYMBOL(dib7000pc_detection);
1298
1299struct i2c_adapter * dib7000p_get_i2c_master(struct dvb_frontend *demod, enum dibx000_i2c_interface intf, int gating)
1300{
1301 struct dib7000p_state *st = demod->demodulator_priv;
1302 return dibx000_get_i2c_adapter(&st->i2c_master, intf, gating);
1303}
1304EXPORT_SYMBOL(dib7000p_get_i2c_master);
1305
Olivier Grenief8731f42009-09-18 04:08:43 -03001306int dib7000p_pid_filter_ctrl(struct dvb_frontend *fe, u8 onoff)
1307{
1308 struct dib7000p_state *state = fe->demodulator_priv;
1309 u16 val = dib7000p_read_word(state, 235) & 0xffef;
1310 val |= (onoff & 0x1) << 4;
1311 dprintk("PID filter enabled %d", onoff);
1312 return dib7000p_write_word(state, 235, val);
1313}
1314EXPORT_SYMBOL(dib7000p_pid_filter_ctrl);
1315
1316int dib7000p_pid_filter(struct dvb_frontend *fe, u8 id, u16 pid, u8 onoff)
1317{
1318 struct dib7000p_state *state = fe->demodulator_priv;
1319 dprintk("PID filter: index %x, PID %d, OnOff %d", id, pid, onoff);
1320 return dib7000p_write_word(state, 241 + id, onoff ? (1 << 13) | pid : 0);
1321}
1322EXPORT_SYMBOL(dib7000p_pid_filter);
1323
Patrick Boettchera75763f2006-10-18 08:34:16 -03001324int dib7000p_i2c_enumeration(struct i2c_adapter *i2c, int no_of_demods, u8 default_addr, struct dib7000p_config cfg[])
1325{
1326 struct dib7000p_state st = { .i2c_adap = i2c };
1327 int k = 0;
1328 u8 new_addr = 0;
1329
1330 for (k = no_of_demods-1; k >= 0; k--) {
1331 st.cfg = cfg[k];
1332
1333 /* designated i2c address */
1334 new_addr = (0x40 + k) << 1;
1335 st.i2c_addr = new_addr;
Olivier Grenieeac1fe12009-09-23 13:41:27 -03001336 dib7000p_write_word(&st, 1287, 0x0003); /* sram lead in, rdy */
Patrick Boettchera75763f2006-10-18 08:34:16 -03001337 if (dib7000p_identify(&st) != 0) {
1338 st.i2c_addr = default_addr;
Olivier Grenieeac1fe12009-09-23 13:41:27 -03001339 dib7000p_write_word(&st, 1287, 0x0003); /* sram lead in, rdy */
Patrick Boettchera75763f2006-10-18 08:34:16 -03001340 if (dib7000p_identify(&st) != 0) {
1341 dprintk("DiB7000P #%d: not identified\n", k);
1342 return -EIO;
1343 }
1344 }
1345
1346 /* start diversity to pull_down div_str - just for i2c-enumeration */
1347 dib7000p_set_output_mode(&st, OUTMODE_DIVERSITY);
1348
1349 /* set new i2c address and force divstart */
1350 dib7000p_write_word(&st, 1285, (new_addr << 2) | 0x2);
1351
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001352 dprintk("IC %d initialized (to i2c_address 0x%x)", k, new_addr);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001353 }
1354
1355 for (k = 0; k < no_of_demods; k++) {
1356 st.cfg = cfg[k];
1357 st.i2c_addr = (0x40 + k) << 1;
1358
1359 // unforce divstr
1360 dib7000p_write_word(&st, 1285, st.i2c_addr << 2);
1361
1362 /* deactivate div - it was just for i2c-enumeration */
1363 dib7000p_set_output_mode(&st, OUTMODE_HIGH_Z);
1364 }
1365
1366 return 0;
1367}
1368EXPORT_SYMBOL(dib7000p_i2c_enumeration);
1369
1370static struct dvb_frontend_ops dib7000p_ops;
1371struct dvb_frontend * dib7000p_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr, struct dib7000p_config *cfg)
1372{
1373 struct dvb_frontend *demod;
1374 struct dib7000p_state *st;
1375 st = kzalloc(sizeof(struct dib7000p_state), GFP_KERNEL);
1376 if (st == NULL)
1377 return NULL;
1378
1379 memcpy(&st->cfg, cfg, sizeof(struct dib7000p_config));
1380 st->i2c_adap = i2c_adap;
1381 st->i2c_addr = i2c_addr;
1382 st->gpio_val = cfg->gpio_val;
1383 st->gpio_dir = cfg->gpio_dir;
1384
Steven Totha38d6e32008-04-22 15:37:01 -03001385 /* Ensure the output mode remains at the previous default if it's
1386 * not specifically set by the caller.
1387 */
Anton Blanchard8d798982008-08-09 12:23:15 -03001388 if ((st->cfg.output_mode != OUTMODE_MPEG2_SERIAL) &&
1389 (st->cfg.output_mode != OUTMODE_MPEG2_PAR_GATED_CLK))
Steven Totha38d6e32008-04-22 15:37:01 -03001390 st->cfg.output_mode = OUTMODE_MPEG2_FIFO;
1391
Patrick Boettchera75763f2006-10-18 08:34:16 -03001392 demod = &st->demod;
1393 demod->demodulator_priv = st;
1394 memcpy(&st->demod.ops, &dib7000p_ops, sizeof(struct dvb_frontend_ops));
1395
Olivier Grenieeac1fe12009-09-23 13:41:27 -03001396 dib7000p_write_word(st, 1287, 0x0003); /* sram lead in, rdy */
1397
Patrick Boettchera75763f2006-10-18 08:34:16 -03001398 if (dib7000p_identify(st) != 0)
1399 goto error;
1400
Martin Samek7646b9d2009-09-30 22:59:09 -03001401 /* FIXME: make sure the dev.parent field is initialized, or else
1402 request_firmware() will hit an OOPS (this should be moved somewhere
1403 more common) */
1404 st->i2c_master.gated_tuner_i2c_adap.dev.parent = i2c_adap->dev.parent;
1405
Patrick Boettchera75763f2006-10-18 08:34:16 -03001406 dibx000_init_i2c_master(&st->i2c_master, DIB7000P, st->i2c_adap, st->i2c_addr);
1407
1408 dib7000p_demod_reset(st);
1409
1410 return demod;
1411
1412error:
1413 kfree(st);
1414 return NULL;
1415}
1416EXPORT_SYMBOL(dib7000p_attach);
1417
1418static struct dvb_frontend_ops dib7000p_ops = {
1419 .info = {
1420 .name = "DiBcom 7000PC",
1421 .type = FE_OFDM,
1422 .frequency_min = 44250000,
1423 .frequency_max = 867250000,
1424 .frequency_stepsize = 62500,
1425 .caps = FE_CAN_INVERSION_AUTO |
1426 FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
1427 FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
1428 FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO |
1429 FE_CAN_TRANSMISSION_MODE_AUTO |
1430 FE_CAN_GUARD_INTERVAL_AUTO |
1431 FE_CAN_RECOVER |
1432 FE_CAN_HIERARCHY_AUTO,
1433 },
1434
1435 .release = dib7000p_release,
1436
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001437 .init = dib7000p_wakeup,
Patrick Boettchera75763f2006-10-18 08:34:16 -03001438 .sleep = dib7000p_sleep,
1439
1440 .set_frontend = dib7000p_set_frontend,
1441 .get_tune_settings = dib7000p_fe_get_tune_settings,
1442 .get_frontend = dib7000p_get_frontend,
1443
1444 .read_status = dib7000p_read_status,
1445 .read_ber = dib7000p_read_ber,
1446 .read_signal_strength = dib7000p_read_signal_strength,
1447 .read_snr = dib7000p_read_snr,
1448 .read_ucblocks = dib7000p_read_unc_blocks,
1449};
1450
1451MODULE_AUTHOR("Patrick Boettcher <pboettcher@dibcom.fr>");
1452MODULE_DESCRIPTION("Driver for the DiBcom 7000PC COFDM demodulator");
1453MODULE_LICENSE("GPL");