blob: 55ef6eeb0769f9b8f9aa352962be6418e2f8f827 [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;
111 smo_mode = (dib7000p_read_word(state, 235) & 0x0010) | (1 << 1);
112
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;
165 }
Patrick Boettcher01373a52007-07-30 12:49:04 -0300166 state->div_state = (u8)onoff;
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300167
168 if (onoff) {
169 dib7000p_write_word(state, 204, 6);
170 dib7000p_write_word(state, 205, 16);
171 /* P_dvsy_sync_mode = 0, P_dvsy_sync_enable=1, P_dvcb_comb_mode=2 */
172 dib7000p_write_word(state, 207, (state->div_sync_wait << 4) | (1 << 2) | (2 << 0));
173 } else {
174 dib7000p_write_word(state, 204, 1);
175 dib7000p_write_word(state, 205, 0);
176 dib7000p_write_word(state, 207, 0);
177 }
178
179 return 0;
180}
181
Patrick Boettchera75763f2006-10-18 08:34:16 -0300182static int dib7000p_set_power_mode(struct dib7000p_state *state, enum dib7000p_power_mode mode)
183{
184 /* by default everything is powered off */
185 u16 reg_774 = 0xffff, reg_775 = 0xffff, reg_776 = 0x0007, reg_899 = 0x0003,
186 reg_1280 = (0xfe00) | (dib7000p_read_word(state, 1280) & 0x01ff);
187
188 /* now, depending on the requested mode, we power on */
189 switch (mode) {
190 /* power up everything in the demod */
191 case DIB7000P_POWER_ALL:
192 reg_774 = 0x0000; reg_775 = 0x0000; reg_776 = 0x0; reg_899 = 0x0; reg_1280 &= 0x01ff;
193 break;
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300194
195 case DIB7000P_POWER_ANALOG_ADC:
196 /* dem, cfg, iqc, sad, agc */
197 reg_774 &= ~((1 << 15) | (1 << 14) | (1 << 11) | (1 << 10) | (1 << 9));
198 /* nud */
199 reg_776 &= ~((1 << 0));
200 /* Dout */
201 reg_1280 &= ~((1 << 11));
202 /* fall through wanted to enable the interfaces */
203
Patrick Boettchera75763f2006-10-18 08:34:16 -0300204 /* just leave power on the control-interfaces: GPIO and (I2C or SDIO) */
205 case DIB7000P_POWER_INTERFACE_ONLY: /* TODO power up either SDIO or I2C */
206 reg_1280 &= ~((1 << 14) | (1 << 13) | (1 << 12) | (1 << 10));
207 break;
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300208
Patrick Boettchera75763f2006-10-18 08:34:16 -0300209/* TODO following stuff is just converted from the dib7000-driver - check when is used what */
210 }
211
212 dib7000p_write_word(state, 774, reg_774);
213 dib7000p_write_word(state, 775, reg_775);
214 dib7000p_write_word(state, 776, reg_776);
215 dib7000p_write_word(state, 899, reg_899);
216 dib7000p_write_word(state, 1280, reg_1280);
217
218 return 0;
219}
220
221static void dib7000p_set_adc_state(struct dib7000p_state *state, enum dibx000_adc_states no)
222{
223 u16 reg_908 = dib7000p_read_word(state, 908),
224 reg_909 = dib7000p_read_word(state, 909);
225
226 switch (no) {
227 case DIBX000_SLOW_ADC_ON:
228 reg_909 |= (1 << 1) | (1 << 0);
229 dib7000p_write_word(state, 909, reg_909);
230 reg_909 &= ~(1 << 1);
231 break;
232
233 case DIBX000_SLOW_ADC_OFF:
234 reg_909 |= (1 << 1) | (1 << 0);
235 break;
236
237 case DIBX000_ADC_ON:
238 reg_908 &= 0x0fff;
239 reg_909 &= 0x0003;
240 break;
241
242 case DIBX000_ADC_OFF: // leave the VBG voltage on
243 reg_908 |= (1 << 14) | (1 << 13) | (1 << 12);
244 reg_909 |= (1 << 5) | (1 << 4) | (1 << 3) | (1 << 2);
245 break;
246
247 case DIBX000_VBG_ENABLE:
248 reg_908 &= ~(1 << 15);
249 break;
250
251 case DIBX000_VBG_DISABLE:
252 reg_908 |= (1 << 15);
253 break;
254
255 default:
256 break;
257 }
258
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300259// dprintk( "908: %x, 909: %x\n", reg_908, reg_909);
Patrick Boettchera75763f2006-10-18 08:34:16 -0300260
261 dib7000p_write_word(state, 908, reg_908);
262 dib7000p_write_word(state, 909, reg_909);
263}
264
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300265static int dib7000p_set_bandwidth(struct dib7000p_state *state, u32 bw)
Patrick Boettchera75763f2006-10-18 08:34:16 -0300266{
Patrick Boettchera75763f2006-10-18 08:34:16 -0300267 u32 timf;
268
269 // store the current bandwidth for later use
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300270 state->current_bandwidth = bw;
Patrick Boettchera75763f2006-10-18 08:34:16 -0300271
272 if (state->timf == 0) {
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300273 dprintk( "using default timf");
Patrick Boettchera75763f2006-10-18 08:34:16 -0300274 timf = state->cfg.bw->timf;
275 } else {
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300276 dprintk( "using updated timf");
Patrick Boettchera75763f2006-10-18 08:34:16 -0300277 timf = state->timf;
278 }
279
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300280 timf = timf * (bw / 50) / 160;
Patrick Boettchera75763f2006-10-18 08:34:16 -0300281
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300282 dib7000p_write_word(state, 23, (u16) ((timf >> 16) & 0xffff));
283 dib7000p_write_word(state, 24, (u16) ((timf ) & 0xffff));
Patrick Boettchera75763f2006-10-18 08:34:16 -0300284
285 return 0;
286}
287
288static int dib7000p_sad_calib(struct dib7000p_state *state)
289{
290/* internal */
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300291// 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 -0300292 dib7000p_write_word(state, 73, (0 << 1) | (0 << 0));
293 dib7000p_write_word(state, 74, 776); // 0.625*3.3 / 4096
294
295 /* do the calibration */
296 dib7000p_write_word(state, 73, (1 << 0));
297 dib7000p_write_word(state, 73, (0 << 0));
298
299 msleep(1);
300
301 return 0;
302}
303
Patrick Boettcher01373a52007-07-30 12:49:04 -0300304int dib7000p_set_wbd_ref(struct dvb_frontend *demod, u16 value)
305{
306 struct dib7000p_state *state = demod->demodulator_priv;
307 if (value > 4095)
308 value = 4095;
309 state->wbd_ref = value;
310 return dib7000p_write_word(state, 105, (dib7000p_read_word(state, 105) & 0xf000) | value);
311}
312
313EXPORT_SYMBOL(dib7000p_set_wbd_ref);
Patrick Boettchera75763f2006-10-18 08:34:16 -0300314static void dib7000p_reset_pll(struct dib7000p_state *state)
315{
316 struct dibx000_bandwidth_config *bw = &state->cfg.bw[0];
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300317 u16 clk_cfg0;
Patrick Boettchera75763f2006-10-18 08:34:16 -0300318
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300319 /* force PLL bypass */
320 clk_cfg0 = (1 << 15) | ((bw->pll_ratio & 0x3f) << 9) |
321 (bw->modulo << 7) | (bw->ADClkSrc << 6) | (bw->IO_CLK_en_core << 5) |
322 (bw->bypclk_div << 2) | (bw->enable_refdiv << 1) | (0 << 0);
323
324 dib7000p_write_word(state, 900, clk_cfg0);
325
326 /* P_pll_cfg */
Patrick Boettchera75763f2006-10-18 08:34:16 -0300327 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 -0300328 clk_cfg0 = (bw->pll_bypass << 15) | (clk_cfg0 & 0x7fff);
329 dib7000p_write_word(state, 900, clk_cfg0);
Patrick Boettchera75763f2006-10-18 08:34:16 -0300330
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300331 dib7000p_write_word(state, 18, (u16) (((bw->internal*1000) >> 16) & 0xffff));
332 dib7000p_write_word(state, 19, (u16) ( (bw->internal*1000 ) & 0xffff));
333 dib7000p_write_word(state, 21, (u16) ( (bw->ifreq >> 16) & 0xffff));
334 dib7000p_write_word(state, 22, (u16) ( (bw->ifreq ) & 0xffff));
Patrick Boettchera75763f2006-10-18 08:34:16 -0300335
336 dib7000p_write_word(state, 72, bw->sad_cfg);
337}
338
339static int dib7000p_reset_gpio(struct dib7000p_state *st)
340{
341 /* reset the GPIOs */
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300342 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 -0300343
344 dib7000p_write_word(st, 1029, st->gpio_dir);
345 dib7000p_write_word(st, 1030, st->gpio_val);
346
347 /* TODO 1031 is P_gpio_od */
348
349 dib7000p_write_word(st, 1032, st->cfg.gpio_pwm_pos);
350
351 dib7000p_write_word(st, 1037, st->cfg.pwm_freq_div);
352 return 0;
353}
354
Patrick Boettcher01373a52007-07-30 12:49:04 -0300355static int dib7000p_cfg_gpio(struct dib7000p_state *st, u8 num, u8 dir, u8 val)
356{
357 st->gpio_dir = dib7000p_read_word(st, 1029);
358 st->gpio_dir &= ~(1 << num); /* reset the direction bit */
359 st->gpio_dir |= (dir & 0x1) << num; /* set the new direction */
360 dib7000p_write_word(st, 1029, st->gpio_dir);
361
362 st->gpio_val = dib7000p_read_word(st, 1030);
363 st->gpio_val &= ~(1 << num); /* reset the direction bit */
364 st->gpio_val |= (val & 0x01) << num; /* set the new value */
365 dib7000p_write_word(st, 1030, st->gpio_val);
366
367 return 0;
368}
369
370int dib7000p_set_gpio(struct dvb_frontend *demod, u8 num, u8 dir, u8 val)
371{
372 struct dib7000p_state *state = demod->demodulator_priv;
373 return dib7000p_cfg_gpio(state, num, dir, val);
374}
375
376EXPORT_SYMBOL(dib7000p_set_gpio);
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300377static u16 dib7000p_defaults[] =
378
379{
380 // auto search configuration
381 3, 2,
382 0x0004,
383 0x1000,
384 0x0814, /* Equal Lock */
385
386 12, 6,
387 0x001b,
388 0x7740,
389 0x005b,
390 0x8d80,
391 0x01c9,
392 0xc380,
393 0x0000,
394 0x0080,
395 0x0000,
396 0x0090,
397 0x0001,
398 0xd4c0,
399
400 1, 26,
401 0x6680, // P_timf_alpha=6, P_corm_alpha=6, P_corm_thres=128 default: 6,4,26
402
403 /* set ADC level to -16 */
404 11, 79,
405 (1 << 13) - 825 - 117,
406 (1 << 13) - 837 - 117,
407 (1 << 13) - 811 - 117,
408 (1 << 13) - 766 - 117,
409 (1 << 13) - 737 - 117,
410 (1 << 13) - 693 - 117,
411 (1 << 13) - 648 - 117,
412 (1 << 13) - 619 - 117,
413 (1 << 13) - 575 - 117,
414 (1 << 13) - 531 - 117,
415 (1 << 13) - 501 - 117,
416
417 1, 142,
418 0x0410, // P_palf_filter_on=1, P_palf_filter_freeze=0, P_palf_alpha_regul=16
419
420 /* disable power smoothing */
421 8, 145,
422 0,
423 0,
424 0,
425 0,
426 0,
427 0,
428 0,
429 0,
430
431 1, 154,
432 1 << 13, // P_fft_freq_dir=1, P_fft_nb_to_cut=0
433
434 1, 168,
435 0x0ccd, // P_pha3_thres, default 0x3000
436
437// 1, 169,
438// 0x0010, // P_cti_use_cpe=0, P_cti_use_prog=0, P_cti_win_len=16, default: 0x0010
439
440 1, 183,
441 0x200f, // P_cspu_regul=512, P_cspu_win_cut=15, default: 0x2005
442
443 5, 187,
444 0x023d, // P_adp_regul_cnt=573, default: 410
445 0x00a4, // P_adp_noise_cnt=
446 0x00a4, // P_adp_regul_ext
447 0x7ff0, // P_adp_noise_ext
448 0x3ccc, // P_adp_fil
449
450 1, 198,
451 0x800, // P_equal_thres_wgn
452
453 1, 222,
454 0x0010, // P_fec_ber_rs_len=2
455
456 1, 235,
457 0x0062, // P_smo_mode, P_smo_rs_discard, P_smo_fifo_flush, P_smo_pid_parse, P_smo_error_discard
458
459 2, 901,
460 0x0006, // P_clk_cfg1
461 (3 << 10) | (1 << 6), // P_divclksel=3 P_divbitsel=1
462
463 1, 905,
464 0x2c8e, // Tuner IO bank: max drive (14mA) + divout pads max drive
465
466 0,
467};
468
Patrick Boettchera75763f2006-10-18 08:34:16 -0300469static int dib7000p_demod_reset(struct dib7000p_state *state)
470{
471 dib7000p_set_power_mode(state, DIB7000P_POWER_ALL);
472
473 dib7000p_set_adc_state(state, DIBX000_VBG_ENABLE);
474
475 /* restart all parts */
476 dib7000p_write_word(state, 770, 0xffff);
477 dib7000p_write_word(state, 771, 0xffff);
478 dib7000p_write_word(state, 772, 0x001f);
479 dib7000p_write_word(state, 898, 0x0003);
480 /* except i2c, sdio, gpio - control interfaces */
481 dib7000p_write_word(state, 1280, 0x01fc - ((1 << 7) | (1 << 6) | (1 << 5)) );
482
483 dib7000p_write_word(state, 770, 0);
484 dib7000p_write_word(state, 771, 0);
485 dib7000p_write_word(state, 772, 0);
486 dib7000p_write_word(state, 898, 0);
487 dib7000p_write_word(state, 1280, 0);
488
489 /* default */
490 dib7000p_reset_pll(state);
491
492 if (dib7000p_reset_gpio(state) != 0)
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300493 dprintk( "GPIO reset was not successful.");
Patrick Boettchera75763f2006-10-18 08:34:16 -0300494
495 if (dib7000p_set_output_mode(state, OUTMODE_HIGH_Z) != 0)
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300496 dprintk( "OUTPUT_MODE could not be reset.");
Patrick Boettchera75763f2006-10-18 08:34:16 -0300497
498 /* unforce divstr regardless whether i2c enumeration was done or not */
499 dib7000p_write_word(state, 1285, dib7000p_read_word(state, 1285) & ~(1 << 1) );
500
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300501 dib7000p_set_bandwidth(state, 8000);
502
503 dib7000p_set_adc_state(state, DIBX000_SLOW_ADC_ON);
504 dib7000p_sad_calib(state);
505 dib7000p_set_adc_state(state, DIBX000_SLOW_ADC_OFF);
506
507 // P_iqc_alpha_pha, P_iqc_alpha_amp_dcc_alpha, ...
508 if(state->cfg.tuner_is_baseband)
509 dib7000p_write_word(state, 36,0x0755);
510 else
511 dib7000p_write_word(state, 36,0x1f55);
512
513 dib7000p_write_tab(state, dib7000p_defaults);
514
Patrick Boettchera75763f2006-10-18 08:34:16 -0300515 dib7000p_set_power_mode(state, DIB7000P_POWER_INTERFACE_ONLY);
516
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300517
Patrick Boettchera75763f2006-10-18 08:34:16 -0300518 return 0;
519}
520
Patrick Boettchera75763f2006-10-18 08:34:16 -0300521static void dib7000p_pll_clk_cfg(struct dib7000p_state *state)
522{
523 u16 tmp = 0;
524 tmp = dib7000p_read_word(state, 903);
525 dib7000p_write_word(state, 903, (tmp | 0x1)); //pwr-up pll
526 tmp = dib7000p_read_word(state, 900);
527 dib7000p_write_word(state, 900, (tmp & 0x7fff) | (1 << 6)); //use High freq clock
528}
529
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300530static void dib7000p_restart_agc(struct dib7000p_state *state)
Patrick Boettchera75763f2006-10-18 08:34:16 -0300531{
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300532 // P_restart_iqc & P_restart_agc
533 dib7000p_write_word(state, 770, (1 << 11) | (1 << 9));
534 dib7000p_write_word(state, 770, 0x0000);
Patrick Boettchera75763f2006-10-18 08:34:16 -0300535}
536
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300537static int dib7000p_update_lna(struct dib7000p_state *state)
Patrick Boettchera75763f2006-10-18 08:34:16 -0300538{
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300539 u16 dyn_gain;
540
541 // when there is no LNA to program return immediatly
542 if (state->cfg.update_lna) {
Patrick Boettcher01373a52007-07-30 12:49:04 -0300543 // read dyn_gain here (because it is demod-dependent and not fe)
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300544 dyn_gain = dib7000p_read_word(state, 394);
545 if (state->cfg.update_lna(&state->demod,dyn_gain)) { // LNA has changed
546 dib7000p_restart_agc(state);
547 return 1;
548 }
549 }
550
551 return 0;
552}
553
554static int dib7000p_set_agc_config(struct dib7000p_state *state, u8 band)
555{
556 struct dibx000_agc_config *agc = NULL;
557 int i;
558 if (state->current_band == band && state->current_agc != NULL)
559 return 0;
560 state->current_band = band;
561
562 for (i = 0; i < state->cfg.agc_config_count; i++)
563 if (state->cfg.agc[i].band_caps & band) {
564 agc = &state->cfg.agc[i];
565 break;
566 }
567
568 if (agc == NULL) {
569 dprintk( "no valid AGC configuration found for band 0x%02x",band);
570 return -EINVAL;
571 }
572
573 state->current_agc = agc;
574
575 /* AGC */
576 dib7000p_write_word(state, 75 , agc->setup );
577 dib7000p_write_word(state, 76 , agc->inv_gain );
578 dib7000p_write_word(state, 77 , agc->time_stabiliz );
579 dib7000p_write_word(state, 100, (agc->alpha_level << 12) | agc->thlock);
580
581 // Demod AGC loop configuration
582 dib7000p_write_word(state, 101, (agc->alpha_mant << 5) | agc->alpha_exp);
583 dib7000p_write_word(state, 102, (agc->beta_mant << 6) | agc->beta_exp);
584
585 /* AGC continued */
586 dprintk( "WBD: ref: %d, sel: %d, active: %d, alpha: %d",
587 state->wbd_ref != 0 ? state->wbd_ref : agc->wbd_ref, agc->wbd_sel, !agc->perform_agc_softsplit, agc->wbd_sel);
588
589 if (state->wbd_ref != 0)
590 dib7000p_write_word(state, 105, (agc->wbd_inv << 12) | state->wbd_ref);
591 else
592 dib7000p_write_word(state, 105, (agc->wbd_inv << 12) | agc->wbd_ref);
593
594 dib7000p_write_word(state, 106, (agc->wbd_sel << 13) | (agc->wbd_alpha << 9) | (agc->perform_agc_softsplit << 8));
595
596 dib7000p_write_word(state, 107, agc->agc1_max);
597 dib7000p_write_word(state, 108, agc->agc1_min);
598 dib7000p_write_word(state, 109, agc->agc2_max);
599 dib7000p_write_word(state, 110, agc->agc2_min);
600 dib7000p_write_word(state, 111, (agc->agc1_pt1 << 8) | agc->agc1_pt2);
601 dib7000p_write_word(state, 112, agc->agc1_pt3);
602 dib7000p_write_word(state, 113, (agc->agc1_slope1 << 8) | agc->agc1_slope2);
603 dib7000p_write_word(state, 114, (agc->agc2_pt1 << 8) | agc->agc2_pt2);
604 dib7000p_write_word(state, 115, (agc->agc2_slope1 << 8) | agc->agc2_slope2);
605 return 0;
606}
607
608static int dib7000p_agc_startup(struct dvb_frontend *demod, struct dvb_frontend_parameters *ch)
609{
610 struct dib7000p_state *state = demod->demodulator_priv;
611 int ret = -1;
612 u8 *agc_state = &state->agc_state;
613 u8 agc_split;
614
615 switch (state->agc_state) {
616 case 0:
617 // set power-up level: interf+analog+AGC
618 dib7000p_set_power_mode(state, DIB7000P_POWER_ALL);
619 dib7000p_set_adc_state(state, DIBX000_ADC_ON);
620 dib7000p_pll_clk_cfg(state);
621
622 if (dib7000p_set_agc_config(state, BAND_OF_FREQUENCY(ch->frequency/1000)) != 0)
623 return -1;
624
625 ret = 7;
626 (*agc_state)++;
627 break;
628
629 case 1:
630 // AGC initialization
631 if (state->cfg.agc_control)
632 state->cfg.agc_control(&state->demod, 1);
633
634 dib7000p_write_word(state, 78, 32768);
635 if (!state->current_agc->perform_agc_softsplit) {
636 /* we are using the wbd - so slow AGC startup */
637 /* force 0 split on WBD and restart AGC */
638 dib7000p_write_word(state, 106, (state->current_agc->wbd_sel << 13) | (state->current_agc->wbd_alpha << 9) | (1 << 8));
639 (*agc_state)++;
640 ret = 5;
641 } else {
642 /* default AGC startup */
643 (*agc_state) = 4;
644 /* wait AGC rough lock time */
645 ret = 7;
646 }
647
648 dib7000p_restart_agc(state);
649 break;
650
651 case 2: /* fast split search path after 5sec */
652 dib7000p_write_word(state, 75, state->current_agc->setup | (1 << 4)); /* freeze AGC loop */
653 dib7000p_write_word(state, 106, (state->current_agc->wbd_sel << 13) | (2 << 9) | (0 << 8)); /* fast split search 0.25kHz */
654 (*agc_state)++;
655 ret = 14;
656 break;
657
658 case 3: /* split search ended */
Patrick Boettcher01373a52007-07-30 12:49:04 -0300659 agc_split = (u8)dib7000p_read_word(state, 396); /* store the split value for the next time */
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300660 dib7000p_write_word(state, 78, dib7000p_read_word(state, 394)); /* set AGC gain start value */
661
662 dib7000p_write_word(state, 75, state->current_agc->setup); /* std AGC loop */
663 dib7000p_write_word(state, 106, (state->current_agc->wbd_sel << 13) | (state->current_agc->wbd_alpha << 9) | agc_split); /* standard split search */
664
665 dib7000p_restart_agc(state);
666
667 dprintk( "SPLIT %p: %hd", demod, agc_split);
668
669 (*agc_state)++;
670 ret = 5;
671 break;
672
673 case 4: /* LNA startup */
674 // wait AGC accurate lock time
675 ret = 7;
676
677 if (dib7000p_update_lna(state))
678 // wait only AGC rough lock time
679 ret = 5;
680 else // nothing was done, go to the next state
681 (*agc_state)++;
682 break;
683
684 case 5:
685 if (state->cfg.agc_control)
686 state->cfg.agc_control(&state->demod, 0);
687 (*agc_state)++;
688 break;
689 default:
690 break;
691 }
692 return ret;
693}
694
695static void dib7000p_update_timf(struct dib7000p_state *state)
696{
697 u32 timf = (dib7000p_read_word(state, 427) << 16) | dib7000p_read_word(state, 428);
698 state->timf = timf * 160 / (state->current_bandwidth / 50);
699 dib7000p_write_word(state, 23, (u16) (timf >> 16));
700 dib7000p_write_word(state, 24, (u16) (timf & 0xffff));
701 dprintk( "updated timf_frequency: %d (default: %d)",state->timf, state->cfg.bw->timf);
702
703}
704
705static void dib7000p_set_channel(struct dib7000p_state *state, struct dvb_frontend_parameters *ch, u8 seq)
706{
707 u16 value, est[4];
708
709 dib7000p_set_bandwidth(state, BANDWIDTH_TO_KHZ(ch->u.ofdm.bandwidth));
Patrick Boettchera75763f2006-10-18 08:34:16 -0300710
711 /* nfft, guard, qam, alpha */
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300712 value = 0;
713 switch (ch->u.ofdm.transmission_mode) {
714 case TRANSMISSION_MODE_2K: value |= (0 << 7); break;
715 case /* 4K MODE */ 255: value |= (2 << 7); break;
716 default:
717 case TRANSMISSION_MODE_8K: value |= (1 << 7); break;
718 }
719 switch (ch->u.ofdm.guard_interval) {
720 case GUARD_INTERVAL_1_32: value |= (0 << 5); break;
721 case GUARD_INTERVAL_1_16: value |= (1 << 5); break;
722 case GUARD_INTERVAL_1_4: value |= (3 << 5); break;
723 default:
724 case GUARD_INTERVAL_1_8: value |= (2 << 5); break;
725 }
726 switch (ch->u.ofdm.constellation) {
727 case QPSK: value |= (0 << 3); break;
728 case QAM_16: value |= (1 << 3); break;
729 default:
730 case QAM_64: value |= (2 << 3); break;
731 }
732 switch (HIERARCHY_1) {
733 case HIERARCHY_2: value |= 2; break;
734 case HIERARCHY_4: value |= 4; break;
735 default:
736 case HIERARCHY_1: value |= 1; break;
737 }
738 dib7000p_write_word(state, 0, value);
Patrick Boettchera75763f2006-10-18 08:34:16 -0300739 dib7000p_write_word(state, 5, (seq << 4) | 1); /* do not force tps, search list 0 */
740
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300741 /* P_dintl_native, P_dintlv_inv, P_hrch, P_code_rate, P_select_hp */
742 value = 0;
743 if (1 != 0)
744 value |= (1 << 6);
745 if (ch->u.ofdm.hierarchy_information == 1)
746 value |= (1 << 4);
747 if (1 == 1)
748 value |= 1;
749 switch ((ch->u.ofdm.hierarchy_information == 0 || 1 == 1) ? ch->u.ofdm.code_rate_HP : ch->u.ofdm.code_rate_LP) {
750 case FEC_2_3: value |= (2 << 1); break;
751 case FEC_3_4: value |= (3 << 1); break;
752 case FEC_5_6: value |= (5 << 1); break;
753 case FEC_7_8: value |= (7 << 1); break;
754 default:
755 case FEC_1_2: value |= (1 << 1); break;
756 }
757 dib7000p_write_word(state, 208, value);
758
759 /* offset loop parameters */
760 dib7000p_write_word(state, 26, 0x6680); // timf(6xxx)
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300761 dib7000p_write_word(state, 32, 0x0003); // pha_off_max(xxx3)
Matt Doran8f6956c2007-07-31 07:09:30 -0300762 dib7000p_write_word(state, 29, 0x1273); // isi
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300763 dib7000p_write_word(state, 33, 0x0005); // sfreq(xxx5)
Patrick Boettchera75763f2006-10-18 08:34:16 -0300764
765 /* P_dvsy_sync_wait */
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300766 switch (ch->u.ofdm.transmission_mode) {
767 case TRANSMISSION_MODE_8K: value = 256; break;
768 case /* 4K MODE */ 255: value = 128; break;
769 case TRANSMISSION_MODE_2K:
770 default: value = 64; break;
Patrick Boettchera75763f2006-10-18 08:34:16 -0300771 }
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300772 switch (ch->u.ofdm.guard_interval) {
773 case GUARD_INTERVAL_1_16: value *= 2; break;
774 case GUARD_INTERVAL_1_8: value *= 4; break;
775 case GUARD_INTERVAL_1_4: value *= 8; break;
776 default:
777 case GUARD_INTERVAL_1_32: value *= 1; break;
778 }
779 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 -0300780
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300781 /* deactive the possibility of diversity reception if extended interleaver */
782 state->div_force_off = !1 && ch->u.ofdm.transmission_mode != TRANSMISSION_MODE_8K;
783 dib7000p_set_diversity_in(&state->demod, state->div_state);
Patrick Boettchera75763f2006-10-18 08:34:16 -0300784
785 /* channel estimation fine configuration */
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300786 switch (ch->u.ofdm.constellation) {
787 case QAM_64:
Patrick Boettchera75763f2006-10-18 08:34:16 -0300788 est[0] = 0x0148; /* P_adp_regul_cnt 0.04 */
789 est[1] = 0xfff0; /* P_adp_noise_cnt -0.002 */
790 est[2] = 0x00a4; /* P_adp_regul_ext 0.02 */
791 est[3] = 0xfff8; /* P_adp_noise_ext -0.001 */
792 break;
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300793 case QAM_16:
Patrick Boettchera75763f2006-10-18 08:34:16 -0300794 est[0] = 0x023d; /* P_adp_regul_cnt 0.07 */
795 est[1] = 0xffdf; /* P_adp_noise_cnt -0.004 */
796 est[2] = 0x00a4; /* P_adp_regul_ext 0.02 */
797 est[3] = 0xfff0; /* P_adp_noise_ext -0.002 */
798 break;
799 default:
800 est[0] = 0x099a; /* P_adp_regul_cnt 0.3 */
801 est[1] = 0xffae; /* P_adp_noise_cnt -0.01 */
802 est[2] = 0x0333; /* P_adp_regul_ext 0.1 */
803 est[3] = 0xfff8; /* P_adp_noise_ext -0.002 */
804 break;
805 }
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300806 for (value = 0; value < 4; value++)
807 dib7000p_write_word(state, 187 + value, est[value]);
Patrick Boettchera75763f2006-10-18 08:34:16 -0300808}
809
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300810static int dib7000p_autosearch_start(struct dvb_frontend *demod, struct dvb_frontend_parameters *ch)
Patrick Boettchera75763f2006-10-18 08:34:16 -0300811{
812 struct dib7000p_state *state = demod->demodulator_priv;
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300813 struct dvb_frontend_parameters schan;
814 u32 value, factor;
Patrick Boettchera75763f2006-10-18 08:34:16 -0300815
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300816 schan = *ch;
817 schan.u.ofdm.constellation = QAM_64;
818 schan.u.ofdm.guard_interval = GUARD_INTERVAL_1_32;
819 schan.u.ofdm.transmission_mode = TRANSMISSION_MODE_8K;
820 schan.u.ofdm.code_rate_HP = FEC_2_3;
821 schan.u.ofdm.code_rate_LP = FEC_3_4;
822 schan.u.ofdm.hierarchy_information = 0;
Patrick Boettchera75763f2006-10-18 08:34:16 -0300823
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300824 dib7000p_set_channel(state, &schan, 7);
825
826 factor = BANDWIDTH_TO_KHZ(ch->u.ofdm.bandwidth);
827 if (factor >= 5000)
828 factor = 1;
829 else
830 factor = 6;
Patrick Boettchera75763f2006-10-18 08:34:16 -0300831
832 // always use the setting for 8MHz here lock_time for 7,6 MHz are longer
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300833 value = 30 * state->cfg.bw->internal * factor;
Patrick Boettchera75763f2006-10-18 08:34:16 -0300834 dib7000p_write_word(state, 6, (u16) ((value >> 16) & 0xffff)); // lock0 wait time
835 dib7000p_write_word(state, 7, (u16) (value & 0xffff)); // lock0 wait time
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300836 value = 100 * state->cfg.bw->internal * factor;
Patrick Boettchera75763f2006-10-18 08:34:16 -0300837 dib7000p_write_word(state, 8, (u16) ((value >> 16) & 0xffff)); // lock1 wait time
838 dib7000p_write_word(state, 9, (u16) (value & 0xffff)); // lock1 wait time
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300839 value = 500 * state->cfg.bw->internal * factor;
Patrick Boettchera75763f2006-10-18 08:34:16 -0300840 dib7000p_write_word(state, 10, (u16) ((value >> 16) & 0xffff)); // lock2 wait time
841 dib7000p_write_word(state, 11, (u16) (value & 0xffff)); // lock2 wait time
842
843 value = dib7000p_read_word(state, 0);
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300844 dib7000p_write_word(state, 0, (u16) ((1 << 9) | value));
Patrick Boettchera75763f2006-10-18 08:34:16 -0300845 dib7000p_read_word(state, 1284);
846 dib7000p_write_word(state, 0, (u16) value);
847
848 return 0;
849}
850
851static int dib7000p_autosearch_is_irq(struct dvb_frontend *demod)
852{
853 struct dib7000p_state *state = demod->demodulator_priv;
854 u16 irq_pending = dib7000p_read_word(state, 1284);
855
856 if (irq_pending & 0x1) // failed
857 return 1;
858
859 if (irq_pending & 0x2) // succeeded
860 return 2;
861
862 return 0; // still pending
863}
864
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300865static void dib7000p_spur_protect(struct dib7000p_state *state, u32 rf_khz, u32 bw)
866{
867 static s16 notch[]={16143, 14402, 12238, 9713, 6902, 3888, 759, -2392};
868 static u8 sine [] ={0, 2, 3, 5, 6, 8, 9, 11, 13, 14, 16, 17, 19, 20, 22,
869 24, 25, 27, 28, 30, 31, 33, 34, 36, 38, 39, 41, 42, 44, 45, 47, 48, 50, 51,
870 53, 55, 56, 58, 59, 61, 62, 64, 65, 67, 68, 70, 71, 73, 74, 76, 77, 79, 80,
871 82, 83, 85, 86, 88, 89, 91, 92, 94, 95, 97, 98, 99, 101, 102, 104, 105,
872 107, 108, 109, 111, 112, 114, 115, 117, 118, 119, 121, 122, 123, 125, 126,
873 128, 129, 130, 132, 133, 134, 136, 137, 138, 140, 141, 142, 144, 145, 146,
874 147, 149, 150, 151, 152, 154, 155, 156, 157, 159, 160, 161, 162, 164, 165,
875 166, 167, 168, 170, 171, 172, 173, 174, 175, 177, 178, 179, 180, 181, 182,
876 183, 184, 185, 186, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198,
877 199, 200, 201, 202, 203, 204, 205, 206, 207, 207, 208, 209, 210, 211, 212,
878 213, 214, 215, 215, 216, 217, 218, 219, 220, 220, 221, 222, 223, 224, 224,
879 225, 226, 227, 227, 228, 229, 229, 230, 231, 231, 232, 233, 233, 234, 235,
880 235, 236, 237, 237, 238, 238, 239, 239, 240, 241, 241, 242, 242, 243, 243,
881 244, 244, 245, 245, 245, 246, 246, 247, 247, 248, 248, 248, 249, 249, 249,
882 250, 250, 250, 251, 251, 251, 252, 252, 252, 252, 253, 253, 253, 253, 254,
883 254, 254, 254, 254, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
884 255, 255, 255, 255, 255, 255};
885
886 u32 xtal = state->cfg.bw->xtal_hz / 1000;
Julia Lawall75b697f2009-08-01 16:48:41 -0300887 int f_rel = DIV_ROUND_CLOSEST(rf_khz, xtal) * xtal - rf_khz;
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300888 int k;
889 int coef_re[8],coef_im[8];
890 int bw_khz = bw;
891 u32 pha;
892
893 dprintk( "relative position of the Spur: %dk (RF: %dk, XTAL: %dk)", f_rel, rf_khz, xtal);
894
895
896 if (f_rel < -bw_khz/2 || f_rel > bw_khz/2)
897 return;
898
899 bw_khz /= 100;
900
901 dib7000p_write_word(state, 142 ,0x0610);
902
903 for (k = 0; k < 8; k++) {
904 pha = ((f_rel * (k+1) * 112 * 80/bw_khz) /1000) & 0x3ff;
905
906 if (pha==0) {
907 coef_re[k] = 256;
908 coef_im[k] = 0;
909 } else if(pha < 256) {
910 coef_re[k] = sine[256-(pha&0xff)];
911 coef_im[k] = sine[pha&0xff];
912 } else if (pha == 256) {
913 coef_re[k] = 0;
914 coef_im[k] = 256;
915 } else if (pha < 512) {
916 coef_re[k] = -sine[pha&0xff];
917 coef_im[k] = sine[256 - (pha&0xff)];
918 } else if (pha == 512) {
919 coef_re[k] = -256;
920 coef_im[k] = 0;
921 } else if (pha < 768) {
922 coef_re[k] = -sine[256-(pha&0xff)];
923 coef_im[k] = -sine[pha&0xff];
924 } else if (pha == 768) {
925 coef_re[k] = 0;
926 coef_im[k] = -256;
927 } else {
928 coef_re[k] = sine[pha&0xff];
929 coef_im[k] = -sine[256 - (pha&0xff)];
930 }
931
932 coef_re[k] *= notch[k];
933 coef_re[k] += (1<<14);
934 if (coef_re[k] >= (1<<24))
935 coef_re[k] = (1<<24) - 1;
936 coef_re[k] /= (1<<15);
937
938 coef_im[k] *= notch[k];
939 coef_im[k] += (1<<14);
940 if (coef_im[k] >= (1<<24))
941 coef_im[k] = (1<<24)-1;
942 coef_im[k] /= (1<<15);
943
944 dprintk( "PALF COEF: %d re: %d im: %d", k, coef_re[k], coef_im[k]);
945
946 dib7000p_write_word(state, 143, (0 << 14) | (k << 10) | (coef_re[k] & 0x3ff));
947 dib7000p_write_word(state, 144, coef_im[k] & 0x3ff);
948 dib7000p_write_word(state, 143, (1 << 14) | (k << 10) | (coef_re[k] & 0x3ff));
949 }
950 dib7000p_write_word(state,143 ,0);
951}
952
953static int dib7000p_tune(struct dvb_frontend *demod, struct dvb_frontend_parameters *ch)
Patrick Boettchera75763f2006-10-18 08:34:16 -0300954{
955 struct dib7000p_state *state = demod->demodulator_priv;
956 u16 tmp = 0;
957
958 if (ch != NULL)
959 dib7000p_set_channel(state, ch, 0);
960 else
961 return -EINVAL;
962
963 // restart demod
964 dib7000p_write_word(state, 770, 0x4000);
965 dib7000p_write_word(state, 770, 0x0000);
966 msleep(45);
967
968 /* 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 -0300969 tmp = (0 << 14) | (4 << 10) | (0 << 9) | (3 << 5) | (1 << 4) | (0x3);
970 if (state->sfn_workaround_active) {
971 dprintk( "SFN workaround is active");
972 tmp |= (1 << 9);
973 dib7000p_write_word(state, 166, 0x4000); // P_pha3_force_pha_shift
974 } else {
975 dib7000p_write_word(state, 166, 0x0000); // P_pha3_force_pha_shift
976 }
977 dib7000p_write_word(state, 29, tmp);
Patrick Boettchera75763f2006-10-18 08:34:16 -0300978
979 // never achieved a lock with that bandwidth so far - wait for osc-freq to update
980 if (state->timf == 0)
981 msleep(200);
982
983 /* offset loop parameters */
984
985 /* P_timf_alpha, P_corm_alpha=6, P_corm_thres=0x80 */
986 tmp = (6 << 8) | 0x80;
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300987 switch (ch->u.ofdm.transmission_mode) {
988 case TRANSMISSION_MODE_2K: tmp |= (7 << 12); break;
989 case /* 4K MODE */ 255: tmp |= (8 << 12); break;
990 default:
991 case TRANSMISSION_MODE_8K: tmp |= (9 << 12); break;
Patrick Boettchera75763f2006-10-18 08:34:16 -0300992 }
993 dib7000p_write_word(state, 26, tmp); /* timf_a(6xxx) */
994
995 /* P_ctrl_freeze_pha_shift=0, P_ctrl_pha_off_max */
996 tmp = (0 << 4);
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300997 switch (ch->u.ofdm.transmission_mode) {
998 case TRANSMISSION_MODE_2K: tmp |= 0x6; break;
999 case /* 4K MODE */ 255: tmp |= 0x7; break;
1000 default:
1001 case TRANSMISSION_MODE_8K: tmp |= 0x8; break;
Patrick Boettchera75763f2006-10-18 08:34:16 -03001002 }
1003 dib7000p_write_word(state, 32, tmp);
1004
1005 /* P_ctrl_sfreq_inh=0, P_ctrl_sfreq_step */
1006 tmp = (0 << 4);
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001007 switch (ch->u.ofdm.transmission_mode) {
1008 case TRANSMISSION_MODE_2K: tmp |= 0x6; break;
1009 case /* 4K MODE */ 255: tmp |= 0x7; break;
1010 default:
1011 case TRANSMISSION_MODE_8K: tmp |= 0x8; break;
Patrick Boettchera75763f2006-10-18 08:34:16 -03001012 }
1013 dib7000p_write_word(state, 33, tmp);
1014
1015 tmp = dib7000p_read_word(state,509);
1016 if (!((tmp >> 6) & 0x1)) {
1017 /* restart the fec */
1018 tmp = dib7000p_read_word(state,771);
1019 dib7000p_write_word(state, 771, tmp | (1 << 1));
1020 dib7000p_write_word(state, 771, tmp);
1021 msleep(10);
1022 tmp = dib7000p_read_word(state,509);
1023 }
1024
1025 // we achieved a lock - it's time to update the osc freq
1026 if ((tmp >> 6) & 0x1)
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001027 dib7000p_update_timf(state);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001028
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001029 if (state->cfg.spur_protect)
1030 dib7000p_spur_protect(state, ch->frequency/1000, BANDWIDTH_TO_KHZ(ch->u.ofdm.bandwidth));
1031
1032 dib7000p_set_bandwidth(state, BANDWIDTH_TO_KHZ(ch->u.ofdm.bandwidth));
Patrick Boettchera75763f2006-10-18 08:34:16 -03001033 return 0;
1034}
1035
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001036static int dib7000p_wakeup(struct dvb_frontend *demod)
Patrick Boettchera75763f2006-10-18 08:34:16 -03001037{
Patrick Boettchera75763f2006-10-18 08:34:16 -03001038 struct dib7000p_state *state = demod->demodulator_priv;
Patrick Boettchera75763f2006-10-18 08:34:16 -03001039 dib7000p_set_power_mode(state, DIB7000P_POWER_ALL);
1040 dib7000p_set_adc_state(state, DIBX000_SLOW_ADC_ON);
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001041 return 0;
Patrick Boettchera75763f2006-10-18 08:34:16 -03001042}
1043
1044static int dib7000p_sleep(struct dvb_frontend *demod)
1045{
1046 struct dib7000p_state *state = demod->demodulator_priv;
1047 return dib7000p_set_output_mode(state, OUTMODE_HIGH_Z) | dib7000p_set_power_mode(state, DIB7000P_POWER_INTERFACE_ONLY);
1048}
1049
1050static int dib7000p_identify(struct dib7000p_state *st)
1051{
1052 u16 value;
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001053 dprintk( "checking demod on I2C address: %d (%x)",
Patrick Boettchera75763f2006-10-18 08:34:16 -03001054 st->i2c_addr, st->i2c_addr);
1055
1056 if ((value = dib7000p_read_word(st, 768)) != 0x01b3) {
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001057 dprintk( "wrong Vendor ID (read=0x%x)",value);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001058 return -EREMOTEIO;
1059 }
1060
1061 if ((value = dib7000p_read_word(st, 769)) != 0x4000) {
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001062 dprintk( "wrong Device ID (%x)",value);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001063 return -EREMOTEIO;
1064 }
1065
1066 return 0;
1067}
1068
1069
1070static int dib7000p_get_frontend(struct dvb_frontend* fe,
1071 struct dvb_frontend_parameters *fep)
1072{
1073 struct dib7000p_state *state = fe->demodulator_priv;
1074 u16 tps = dib7000p_read_word(state,463);
1075
1076 fep->inversion = INVERSION_AUTO;
1077
Patrick Boettcher904a82e2008-01-25 07:31:58 -03001078 fep->u.ofdm.bandwidth = BANDWIDTH_TO_INDEX(state->current_bandwidth);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001079
1080 switch ((tps >> 8) & 0x3) {
1081 case 0: fep->u.ofdm.transmission_mode = TRANSMISSION_MODE_2K; break;
1082 case 1: fep->u.ofdm.transmission_mode = TRANSMISSION_MODE_8K; break;
1083 /* case 2: fep->u.ofdm.transmission_mode = TRANSMISSION_MODE_4K; break; */
1084 }
1085
1086 switch (tps & 0x3) {
1087 case 0: fep->u.ofdm.guard_interval = GUARD_INTERVAL_1_32; break;
1088 case 1: fep->u.ofdm.guard_interval = GUARD_INTERVAL_1_16; break;
1089 case 2: fep->u.ofdm.guard_interval = GUARD_INTERVAL_1_8; break;
1090 case 3: fep->u.ofdm.guard_interval = GUARD_INTERVAL_1_4; break;
1091 }
1092
1093 switch ((tps >> 14) & 0x3) {
1094 case 0: fep->u.ofdm.constellation = QPSK; break;
1095 case 1: fep->u.ofdm.constellation = QAM_16; break;
1096 case 2:
1097 default: fep->u.ofdm.constellation = QAM_64; break;
1098 }
1099
1100 /* as long as the frontend_param structure is fixed for hierarchical transmission I refuse to use it */
1101 /* (tps >> 13) & 0x1 == hrch is used, (tps >> 10) & 0x7 == alpha */
1102
1103 fep->u.ofdm.hierarchy_information = HIERARCHY_NONE;
1104 switch ((tps >> 5) & 0x7) {
1105 case 1: fep->u.ofdm.code_rate_HP = FEC_1_2; break;
1106 case 2: fep->u.ofdm.code_rate_HP = FEC_2_3; break;
1107 case 3: fep->u.ofdm.code_rate_HP = FEC_3_4; break;
1108 case 5: fep->u.ofdm.code_rate_HP = FEC_5_6; break;
1109 case 7:
1110 default: fep->u.ofdm.code_rate_HP = FEC_7_8; break;
1111
1112 }
1113
1114 switch ((tps >> 2) & 0x7) {
1115 case 1: fep->u.ofdm.code_rate_LP = FEC_1_2; break;
1116 case 2: fep->u.ofdm.code_rate_LP = FEC_2_3; break;
1117 case 3: fep->u.ofdm.code_rate_LP = FEC_3_4; break;
1118 case 5: fep->u.ofdm.code_rate_LP = FEC_5_6; break;
1119 case 7:
1120 default: fep->u.ofdm.code_rate_LP = FEC_7_8; break;
1121 }
1122
1123 /* native interleaver: (dib7000p_read_word(state, 464) >> 5) & 0x1 */
1124
1125 return 0;
1126}
1127
1128static int dib7000p_set_frontend(struct dvb_frontend* fe,
1129 struct dvb_frontend_parameters *fep)
1130{
1131 struct dib7000p_state *state = fe->demodulator_priv;
Soeren Moch853ea132008-01-25 06:27:06 -03001132 int time, ret;
Patrick Boettchera75763f2006-10-18 08:34:16 -03001133
Soeren Moch853ea132008-01-25 06:27:06 -03001134 dib7000p_set_output_mode(state, OUTMODE_HIGH_Z);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001135
Patrick Boettcher904a82e2008-01-25 07:31:58 -03001136 /* maybe the parameter has been changed */
Matt Doran8f6956c2007-07-31 07:09:30 -03001137 state->sfn_workaround_active = buggy_sfn_workaround;
1138
Patrick Boettchera75763f2006-10-18 08:34:16 -03001139 if (fe->ops.tuner_ops.set_params)
1140 fe->ops.tuner_ops.set_params(fe, fep);
1141
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001142 /* start up the AGC */
1143 state->agc_state = 0;
1144 do {
1145 time = dib7000p_agc_startup(fe, fep);
1146 if (time != -1)
1147 msleep(time);
1148 } while (time != -1);
1149
Patrick Boettchera75763f2006-10-18 08:34:16 -03001150 if (fep->u.ofdm.transmission_mode == TRANSMISSION_MODE_AUTO ||
1151 fep->u.ofdm.guard_interval == GUARD_INTERVAL_AUTO ||
1152 fep->u.ofdm.constellation == QAM_AUTO ||
1153 fep->u.ofdm.code_rate_HP == FEC_AUTO) {
1154 int i = 800, found;
1155
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001156 dib7000p_autosearch_start(fe, fep);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001157 do {
1158 msleep(1);
1159 found = dib7000p_autosearch_is_irq(fe);
1160 } while (found == 0 && i--);
1161
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001162 dprintk("autosearch returns: %d",found);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001163 if (found == 0 || found == 1)
1164 return 0; // no channel found
1165
1166 dib7000p_get_frontend(fe, fep);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001167 }
1168
Soeren Moch853ea132008-01-25 06:27:06 -03001169 ret = dib7000p_tune(fe, fep);
1170
Patrick Boettchera75763f2006-10-18 08:34:16 -03001171 /* make this a config parameter */
Steven Totha38d6e32008-04-22 15:37:01 -03001172 dib7000p_set_output_mode(state, state->cfg.output_mode);
Soeren Moch853ea132008-01-25 06:27:06 -03001173 return ret;
Patrick Boettchera75763f2006-10-18 08:34:16 -03001174}
1175
1176static int dib7000p_read_status(struct dvb_frontend *fe, fe_status_t *stat)
1177{
1178 struct dib7000p_state *state = fe->demodulator_priv;
1179 u16 lock = dib7000p_read_word(state, 509);
1180
1181 *stat = 0;
1182
1183 if (lock & 0x8000)
1184 *stat |= FE_HAS_SIGNAL;
1185 if (lock & 0x3000)
1186 *stat |= FE_HAS_CARRIER;
1187 if (lock & 0x0100)
1188 *stat |= FE_HAS_VITERBI;
1189 if (lock & 0x0010)
1190 *stat |= FE_HAS_SYNC;
1191 if (lock & 0x0008)
1192 *stat |= FE_HAS_LOCK;
1193
1194 return 0;
1195}
1196
1197static int dib7000p_read_ber(struct dvb_frontend *fe, u32 *ber)
1198{
1199 struct dib7000p_state *state = fe->demodulator_priv;
1200 *ber = (dib7000p_read_word(state, 500) << 16) | dib7000p_read_word(state, 501);
1201 return 0;
1202}
1203
1204static int dib7000p_read_unc_blocks(struct dvb_frontend *fe, u32 *unc)
1205{
1206 struct dib7000p_state *state = fe->demodulator_priv;
1207 *unc = dib7000p_read_word(state, 506);
1208 return 0;
1209}
1210
1211static int dib7000p_read_signal_strength(struct dvb_frontend *fe, u16 *strength)
1212{
1213 struct dib7000p_state *state = fe->demodulator_priv;
1214 u16 val = dib7000p_read_word(state, 394);
1215 *strength = 65535 - val;
1216 return 0;
1217}
1218
1219static int dib7000p_read_snr(struct dvb_frontend* fe, u16 *snr)
1220{
Olivier Grenieef801962009-09-15 06:46:52 -03001221 struct dib7000p_state *state = fe->demodulator_priv;
1222 u16 val;
1223 s32 signal_mant, signal_exp, noise_mant, noise_exp;
1224 u32 result = 0;
1225
1226 val = dib7000p_read_word(state, 479);
1227 noise_mant = (val >> 4) & 0xff;
1228 noise_exp = ((val & 0xf) << 2);
1229 val = dib7000p_read_word(state, 480);
1230 noise_exp += ((val >> 14) & 0x3);
1231 if ((noise_exp & 0x20) != 0)
1232 noise_exp -= 0x40;
1233
1234 signal_mant = (val >> 6) & 0xFF;
1235 signal_exp = (val & 0x3F);
1236 if ((signal_exp & 0x20) != 0)
1237 signal_exp -= 0x40;
1238
1239 if (signal_mant != 0)
1240 result = intlog10(2) * 10 * signal_exp + 10 *
1241 intlog10(signal_mant);
1242 else
1243 result = intlog10(2) * 10 * signal_exp - 100;
1244
1245 if (noise_mant != 0)
1246 result -= intlog10(2) * 10 * noise_exp + 10 *
1247 intlog10(noise_mant);
1248 else
1249 result -= intlog10(2) * 10 * noise_exp - 100;
1250
1251 *snr = result / ((1 << 24) / 10);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001252 return 0;
1253}
1254
1255static int dib7000p_fe_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings *tune)
1256{
1257 tune->min_delay_ms = 1000;
1258 return 0;
1259}
1260
1261static void dib7000p_release(struct dvb_frontend *demod)
1262{
1263 struct dib7000p_state *st = demod->demodulator_priv;
1264 dibx000_exit_i2c_master(&st->i2c_master);
1265 kfree(st);
1266}
1267
1268int dib7000pc_detection(struct i2c_adapter *i2c_adap)
1269{
1270 u8 tx[2], rx[2];
1271 struct i2c_msg msg[2] = {
1272 { .addr = 18 >> 1, .flags = 0, .buf = tx, .len = 2 },
1273 { .addr = 18 >> 1, .flags = I2C_M_RD, .buf = rx, .len = 2 },
1274 };
1275
1276 tx[0] = 0x03;
1277 tx[1] = 0x00;
1278
1279 if (i2c_transfer(i2c_adap, msg, 2) == 2)
1280 if (rx[0] == 0x01 && rx[1] == 0xb3) {
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001281 dprintk("-D- DiB7000PC detected");
Patrick Boettchera75763f2006-10-18 08:34:16 -03001282 return 1;
1283 }
1284
1285 msg[0].addr = msg[1].addr = 0x40;
1286
1287 if (i2c_transfer(i2c_adap, msg, 2) == 2)
1288 if (rx[0] == 0x01 && rx[1] == 0xb3) {
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001289 dprintk("-D- DiB7000PC detected");
Patrick Boettchera75763f2006-10-18 08:34:16 -03001290 return 1;
1291 }
1292
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001293 dprintk("-D- DiB7000PC not detected");
Patrick Boettchera75763f2006-10-18 08:34:16 -03001294 return 0;
1295}
1296EXPORT_SYMBOL(dib7000pc_detection);
1297
1298struct i2c_adapter * dib7000p_get_i2c_master(struct dvb_frontend *demod, enum dibx000_i2c_interface intf, int gating)
1299{
1300 struct dib7000p_state *st = demod->demodulator_priv;
1301 return dibx000_get_i2c_adapter(&st->i2c_master, intf, gating);
1302}
1303EXPORT_SYMBOL(dib7000p_get_i2c_master);
1304
1305int dib7000p_i2c_enumeration(struct i2c_adapter *i2c, int no_of_demods, u8 default_addr, struct dib7000p_config cfg[])
1306{
1307 struct dib7000p_state st = { .i2c_adap = i2c };
1308 int k = 0;
1309 u8 new_addr = 0;
1310
1311 for (k = no_of_demods-1; k >= 0; k--) {
1312 st.cfg = cfg[k];
1313
1314 /* designated i2c address */
1315 new_addr = (0x40 + k) << 1;
1316 st.i2c_addr = new_addr;
1317 if (dib7000p_identify(&st) != 0) {
1318 st.i2c_addr = default_addr;
1319 if (dib7000p_identify(&st) != 0) {
1320 dprintk("DiB7000P #%d: not identified\n", k);
1321 return -EIO;
1322 }
1323 }
1324
1325 /* start diversity to pull_down div_str - just for i2c-enumeration */
1326 dib7000p_set_output_mode(&st, OUTMODE_DIVERSITY);
1327
1328 /* set new i2c address and force divstart */
1329 dib7000p_write_word(&st, 1285, (new_addr << 2) | 0x2);
1330
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001331 dprintk("IC %d initialized (to i2c_address 0x%x)", k, new_addr);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001332 }
1333
1334 for (k = 0; k < no_of_demods; k++) {
1335 st.cfg = cfg[k];
1336 st.i2c_addr = (0x40 + k) << 1;
1337
1338 // unforce divstr
1339 dib7000p_write_word(&st, 1285, st.i2c_addr << 2);
1340
1341 /* deactivate div - it was just for i2c-enumeration */
1342 dib7000p_set_output_mode(&st, OUTMODE_HIGH_Z);
1343 }
1344
1345 return 0;
1346}
1347EXPORT_SYMBOL(dib7000p_i2c_enumeration);
1348
1349static struct dvb_frontend_ops dib7000p_ops;
1350struct dvb_frontend * dib7000p_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr, struct dib7000p_config *cfg)
1351{
1352 struct dvb_frontend *demod;
1353 struct dib7000p_state *st;
1354 st = kzalloc(sizeof(struct dib7000p_state), GFP_KERNEL);
1355 if (st == NULL)
1356 return NULL;
1357
1358 memcpy(&st->cfg, cfg, sizeof(struct dib7000p_config));
1359 st->i2c_adap = i2c_adap;
1360 st->i2c_addr = i2c_addr;
1361 st->gpio_val = cfg->gpio_val;
1362 st->gpio_dir = cfg->gpio_dir;
1363
Steven Totha38d6e32008-04-22 15:37:01 -03001364 /* Ensure the output mode remains at the previous default if it's
1365 * not specifically set by the caller.
1366 */
Anton Blanchard8d798982008-08-09 12:23:15 -03001367 if ((st->cfg.output_mode != OUTMODE_MPEG2_SERIAL) &&
1368 (st->cfg.output_mode != OUTMODE_MPEG2_PAR_GATED_CLK))
Steven Totha38d6e32008-04-22 15:37:01 -03001369 st->cfg.output_mode = OUTMODE_MPEG2_FIFO;
1370
Patrick Boettchera75763f2006-10-18 08:34:16 -03001371 demod = &st->demod;
1372 demod->demodulator_priv = st;
1373 memcpy(&st->demod.ops, &dib7000p_ops, sizeof(struct dvb_frontend_ops));
1374
1375 if (dib7000p_identify(st) != 0)
1376 goto error;
1377
1378 dibx000_init_i2c_master(&st->i2c_master, DIB7000P, st->i2c_adap, st->i2c_addr);
1379
1380 dib7000p_demod_reset(st);
1381
1382 return demod;
1383
1384error:
1385 kfree(st);
1386 return NULL;
1387}
1388EXPORT_SYMBOL(dib7000p_attach);
1389
1390static struct dvb_frontend_ops dib7000p_ops = {
1391 .info = {
1392 .name = "DiBcom 7000PC",
1393 .type = FE_OFDM,
1394 .frequency_min = 44250000,
1395 .frequency_max = 867250000,
1396 .frequency_stepsize = 62500,
1397 .caps = FE_CAN_INVERSION_AUTO |
1398 FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
1399 FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
1400 FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO |
1401 FE_CAN_TRANSMISSION_MODE_AUTO |
1402 FE_CAN_GUARD_INTERVAL_AUTO |
1403 FE_CAN_RECOVER |
1404 FE_CAN_HIERARCHY_AUTO,
1405 },
1406
1407 .release = dib7000p_release,
1408
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001409 .init = dib7000p_wakeup,
Patrick Boettchera75763f2006-10-18 08:34:16 -03001410 .sleep = dib7000p_sleep,
1411
1412 .set_frontend = dib7000p_set_frontend,
1413 .get_tune_settings = dib7000p_fe_get_tune_settings,
1414 .get_frontend = dib7000p_get_frontend,
1415
1416 .read_status = dib7000p_read_status,
1417 .read_ber = dib7000p_read_ber,
1418 .read_signal_strength = dib7000p_read_signal_strength,
1419 .read_snr = dib7000p_read_snr,
1420 .read_ucblocks = dib7000p_read_unc_blocks,
1421};
1422
1423MODULE_AUTHOR("Patrick Boettcher <pboettcher@dibcom.fr>");
1424MODULE_DESCRIPTION("Driver for the DiBcom 7000PC COFDM demodulator");
1425MODULE_LICENSE("GPL");