blob: aa7dc45033235e661a04c1e53d55a2abecae8894 [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
13#include "dvb_frontend.h"
14
15#include "dib7000p.h"
16
17static int debug;
18module_param(debug, int, 0644);
19MODULE_PARM_DESC(debug, "turn on debugging (default: 0)");
20
Matt Doran8f6956c2007-07-31 07:09:30 -030021static int buggy_sfn_workaround;
22module_param(buggy_sfn_workaround, int, 0644);
23MODULE_PARM_DESC(debug, "Enable work-around for buggy SFNs (default: 0)");
24
Patrick Boettcherb6884a12007-07-27 10:08:51 -030025#define dprintk(args...) do { if (debug) { printk(KERN_DEBUG "DiB7000P: "); printk(args); printk("\n"); } } while (0)
Patrick Boettchera75763f2006-10-18 08:34:16 -030026
27struct dib7000p_state {
28 struct dvb_frontend demod;
29 struct dib7000p_config cfg;
30
31 u8 i2c_addr;
32 struct i2c_adapter *i2c_adap;
33
34 struct dibx000_i2c_master i2c_master;
35
36 u16 wbd_ref;
37
38 u8 current_band;
39 fe_bandwidth_t current_bandwidth;
40 struct dibx000_agc_config *current_agc;
41 u32 timf;
42
Patrick Boettcher01373a52007-07-30 12:49:04 -030043 u8 div_force_off : 1;
44 u8 div_state : 1;
45 u16 div_sync_wait;
Patrick Boettcherb6884a12007-07-27 10:08:51 -030046
47 u8 agc_state;
48
Patrick Boettchera75763f2006-10-18 08:34:16 -030049 u16 gpio_dir;
50 u16 gpio_val;
Matt Doran8f6956c2007-07-31 07:09:30 -030051
52 u8 sfn_workaround_active :1;
Patrick Boettchera75763f2006-10-18 08:34:16 -030053};
54
55enum dib7000p_power_mode {
56 DIB7000P_POWER_ALL = 0,
Patrick Boettcherb6884a12007-07-27 10:08:51 -030057 DIB7000P_POWER_ANALOG_ADC,
Patrick Boettchera75763f2006-10-18 08:34:16 -030058 DIB7000P_POWER_INTERFACE_ONLY,
59};
60
61static u16 dib7000p_read_word(struct dib7000p_state *state, u16 reg)
62{
63 u8 wb[2] = { reg >> 8, reg & 0xff };
64 u8 rb[2];
65 struct i2c_msg msg[2] = {
66 { .addr = state->i2c_addr >> 1, .flags = 0, .buf = wb, .len = 2 },
67 { .addr = state->i2c_addr >> 1, .flags = I2C_M_RD, .buf = rb, .len = 2 },
68 };
69
70 if (i2c_transfer(state->i2c_adap, msg, 2) != 2)
Patrick Boettcherb6884a12007-07-27 10:08:51 -030071 dprintk("i2c read error on %d",reg);
Patrick Boettchera75763f2006-10-18 08:34:16 -030072
73 return (rb[0] << 8) | rb[1];
74}
75
76static int dib7000p_write_word(struct dib7000p_state *state, u16 reg, u16 val)
77{
78 u8 b[4] = {
79 (reg >> 8) & 0xff, reg & 0xff,
80 (val >> 8) & 0xff, val & 0xff,
81 };
82 struct i2c_msg msg = {
83 .addr = state->i2c_addr >> 1, .flags = 0, .buf = b, .len = 4
84 };
85 return i2c_transfer(state->i2c_adap, &msg, 1) != 1 ? -EREMOTEIO : 0;
86}
Patrick Boettcherb6884a12007-07-27 10:08:51 -030087static void dib7000p_write_tab(struct dib7000p_state *state, u16 *buf)
88{
89 u16 l = 0, r, *n;
90 n = buf;
91 l = *n++;
92 while (l) {
93 r = *n++;
94
95 do {
96 dib7000p_write_word(state, r, *n++);
97 r++;
98 } while (--l);
99 l = *n++;
100 }
101}
102
Patrick Boettchera75763f2006-10-18 08:34:16 -0300103static int dib7000p_set_output_mode(struct dib7000p_state *state, int mode)
104{
105 int ret = 0;
106 u16 outreg, fifo_threshold, smo_mode;
107
108 outreg = 0;
109 fifo_threshold = 1792;
110 smo_mode = (dib7000p_read_word(state, 235) & 0x0010) | (1 << 1);
111
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300112 dprintk( "setting output mode for demod %p to %d",
Patrick Boettchera75763f2006-10-18 08:34:16 -0300113 &state->demod, mode);
114
115 switch (mode) {
116 case OUTMODE_MPEG2_PAR_GATED_CLK: // STBs with parallel gated clock
117 outreg = (1 << 10); /* 0x0400 */
118 break;
119 case OUTMODE_MPEG2_PAR_CONT_CLK: // STBs with parallel continues clock
120 outreg = (1 << 10) | (1 << 6); /* 0x0440 */
121 break;
122 case OUTMODE_MPEG2_SERIAL: // STBs with serial input
123 outreg = (1 << 10) | (2 << 6) | (0 << 1); /* 0x0480 */
124 break;
125 case OUTMODE_DIVERSITY:
126 if (state->cfg.hostbus_diversity)
127 outreg = (1 << 10) | (4 << 6); /* 0x0500 */
128 else
129 outreg = (1 << 11);
130 break;
131 case OUTMODE_MPEG2_FIFO: // e.g. USB feeding
132 smo_mode |= (3 << 1);
133 fifo_threshold = 512;
134 outreg = (1 << 10) | (5 << 6);
135 break;
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300136 case OUTMODE_ANALOG_ADC:
137 outreg = (1 << 10) | (3 << 6);
138 break;
Patrick Boettchera75763f2006-10-18 08:34:16 -0300139 case OUTMODE_HIGH_Z: // disable
140 outreg = 0;
141 break;
142 default:
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300143 dprintk( "Unhandled output_mode passed to be set for demod %p",&state->demod);
Patrick Boettchera75763f2006-10-18 08:34:16 -0300144 break;
145 }
146
147 if (state->cfg.output_mpeg2_in_188_bytes)
148 smo_mode |= (1 << 5) ;
149
150 ret |= dib7000p_write_word(state, 235, smo_mode);
151 ret |= dib7000p_write_word(state, 236, fifo_threshold); /* synchronous fread */
152 ret |= dib7000p_write_word(state, 1286, outreg); /* P_Div_active */
153
154 return ret;
155}
156
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300157static int dib7000p_set_diversity_in(struct dvb_frontend *demod, int onoff)
158{
159 struct dib7000p_state *state = demod->demodulator_priv;
160
161 if (state->div_force_off) {
162 dprintk( "diversity combination deactivated - forced by COFDM parameters");
163 onoff = 0;
164 }
Patrick Boettcher01373a52007-07-30 12:49:04 -0300165 state->div_state = (u8)onoff;
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300166
167 if (onoff) {
168 dib7000p_write_word(state, 204, 6);
169 dib7000p_write_word(state, 205, 16);
170 /* P_dvsy_sync_mode = 0, P_dvsy_sync_enable=1, P_dvcb_comb_mode=2 */
171 dib7000p_write_word(state, 207, (state->div_sync_wait << 4) | (1 << 2) | (2 << 0));
172 } else {
173 dib7000p_write_word(state, 204, 1);
174 dib7000p_write_word(state, 205, 0);
175 dib7000p_write_word(state, 207, 0);
176 }
177
178 return 0;
179}
180
Patrick Boettchera75763f2006-10-18 08:34:16 -0300181static int dib7000p_set_power_mode(struct dib7000p_state *state, enum dib7000p_power_mode mode)
182{
183 /* by default everything is powered off */
184 u16 reg_774 = 0xffff, reg_775 = 0xffff, reg_776 = 0x0007, reg_899 = 0x0003,
185 reg_1280 = (0xfe00) | (dib7000p_read_word(state, 1280) & 0x01ff);
186
187 /* now, depending on the requested mode, we power on */
188 switch (mode) {
189 /* power up everything in the demod */
190 case DIB7000P_POWER_ALL:
191 reg_774 = 0x0000; reg_775 = 0x0000; reg_776 = 0x0; reg_899 = 0x0; reg_1280 &= 0x01ff;
192 break;
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300193
194 case DIB7000P_POWER_ANALOG_ADC:
195 /* dem, cfg, iqc, sad, agc */
196 reg_774 &= ~((1 << 15) | (1 << 14) | (1 << 11) | (1 << 10) | (1 << 9));
197 /* nud */
198 reg_776 &= ~((1 << 0));
199 /* Dout */
200 reg_1280 &= ~((1 << 11));
201 /* fall through wanted to enable the interfaces */
202
Patrick Boettchera75763f2006-10-18 08:34:16 -0300203 /* just leave power on the control-interfaces: GPIO and (I2C or SDIO) */
204 case DIB7000P_POWER_INTERFACE_ONLY: /* TODO power up either SDIO or I2C */
205 reg_1280 &= ~((1 << 14) | (1 << 13) | (1 << 12) | (1 << 10));
206 break;
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300207
Patrick Boettchera75763f2006-10-18 08:34:16 -0300208/* TODO following stuff is just converted from the dib7000-driver - check when is used what */
209 }
210
211 dib7000p_write_word(state, 774, reg_774);
212 dib7000p_write_word(state, 775, reg_775);
213 dib7000p_write_word(state, 776, reg_776);
214 dib7000p_write_word(state, 899, reg_899);
215 dib7000p_write_word(state, 1280, reg_1280);
216
217 return 0;
218}
219
220static void dib7000p_set_adc_state(struct dib7000p_state *state, enum dibx000_adc_states no)
221{
222 u16 reg_908 = dib7000p_read_word(state, 908),
223 reg_909 = dib7000p_read_word(state, 909);
224
225 switch (no) {
226 case DIBX000_SLOW_ADC_ON:
227 reg_909 |= (1 << 1) | (1 << 0);
228 dib7000p_write_word(state, 909, reg_909);
229 reg_909 &= ~(1 << 1);
230 break;
231
232 case DIBX000_SLOW_ADC_OFF:
233 reg_909 |= (1 << 1) | (1 << 0);
234 break;
235
236 case DIBX000_ADC_ON:
237 reg_908 &= 0x0fff;
238 reg_909 &= 0x0003;
239 break;
240
241 case DIBX000_ADC_OFF: // leave the VBG voltage on
242 reg_908 |= (1 << 14) | (1 << 13) | (1 << 12);
243 reg_909 |= (1 << 5) | (1 << 4) | (1 << 3) | (1 << 2);
244 break;
245
246 case DIBX000_VBG_ENABLE:
247 reg_908 &= ~(1 << 15);
248 break;
249
250 case DIBX000_VBG_DISABLE:
251 reg_908 |= (1 << 15);
252 break;
253
254 default:
255 break;
256 }
257
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300258// dprintk( "908: %x, 909: %x\n", reg_908, reg_909);
Patrick Boettchera75763f2006-10-18 08:34:16 -0300259
260 dib7000p_write_word(state, 908, reg_908);
261 dib7000p_write_word(state, 909, reg_909);
262}
263
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300264static int dib7000p_set_bandwidth(struct dib7000p_state *state, u32 bw)
Patrick Boettchera75763f2006-10-18 08:34:16 -0300265{
Patrick Boettchera75763f2006-10-18 08:34:16 -0300266 u32 timf;
267
268 // store the current bandwidth for later use
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300269 state->current_bandwidth = bw;
Patrick Boettchera75763f2006-10-18 08:34:16 -0300270
271 if (state->timf == 0) {
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300272 dprintk( "using default timf");
Patrick Boettchera75763f2006-10-18 08:34:16 -0300273 timf = state->cfg.bw->timf;
274 } else {
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300275 dprintk( "using updated timf");
Patrick Boettchera75763f2006-10-18 08:34:16 -0300276 timf = state->timf;
277 }
278
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300279 timf = timf * (bw / 50) / 160;
Patrick Boettchera75763f2006-10-18 08:34:16 -0300280
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300281 dib7000p_write_word(state, 23, (u16) ((timf >> 16) & 0xffff));
282 dib7000p_write_word(state, 24, (u16) ((timf ) & 0xffff));
Patrick Boettchera75763f2006-10-18 08:34:16 -0300283
284 return 0;
285}
286
287static int dib7000p_sad_calib(struct dib7000p_state *state)
288{
289/* internal */
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300290// 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 -0300291 dib7000p_write_word(state, 73, (0 << 1) | (0 << 0));
292 dib7000p_write_word(state, 74, 776); // 0.625*3.3 / 4096
293
294 /* do the calibration */
295 dib7000p_write_word(state, 73, (1 << 0));
296 dib7000p_write_word(state, 73, (0 << 0));
297
298 msleep(1);
299
300 return 0;
301}
302
Patrick Boettcher01373a52007-07-30 12:49:04 -0300303int dib7000p_set_wbd_ref(struct dvb_frontend *demod, u16 value)
304{
305 struct dib7000p_state *state = demod->demodulator_priv;
306 if (value > 4095)
307 value = 4095;
308 state->wbd_ref = value;
309 return dib7000p_write_word(state, 105, (dib7000p_read_word(state, 105) & 0xf000) | value);
310}
311
312EXPORT_SYMBOL(dib7000p_set_wbd_ref);
Patrick Boettchera75763f2006-10-18 08:34:16 -0300313static void dib7000p_reset_pll(struct dib7000p_state *state)
314{
315 struct dibx000_bandwidth_config *bw = &state->cfg.bw[0];
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300316 u16 clk_cfg0;
Patrick Boettchera75763f2006-10-18 08:34:16 -0300317
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300318 /* force PLL bypass */
319 clk_cfg0 = (1 << 15) | ((bw->pll_ratio & 0x3f) << 9) |
320 (bw->modulo << 7) | (bw->ADClkSrc << 6) | (bw->IO_CLK_en_core << 5) |
321 (bw->bypclk_div << 2) | (bw->enable_refdiv << 1) | (0 << 0);
322
323 dib7000p_write_word(state, 900, clk_cfg0);
324
325 /* P_pll_cfg */
Patrick Boettchera75763f2006-10-18 08:34:16 -0300326 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 -0300327 clk_cfg0 = (bw->pll_bypass << 15) | (clk_cfg0 & 0x7fff);
328 dib7000p_write_word(state, 900, clk_cfg0);
Patrick Boettchera75763f2006-10-18 08:34:16 -0300329
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300330 dib7000p_write_word(state, 18, (u16) (((bw->internal*1000) >> 16) & 0xffff));
331 dib7000p_write_word(state, 19, (u16) ( (bw->internal*1000 ) & 0xffff));
332 dib7000p_write_word(state, 21, (u16) ( (bw->ifreq >> 16) & 0xffff));
333 dib7000p_write_word(state, 22, (u16) ( (bw->ifreq ) & 0xffff));
Patrick Boettchera75763f2006-10-18 08:34:16 -0300334
335 dib7000p_write_word(state, 72, bw->sad_cfg);
336}
337
338static int dib7000p_reset_gpio(struct dib7000p_state *st)
339{
340 /* reset the GPIOs */
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300341 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 -0300342
343 dib7000p_write_word(st, 1029, st->gpio_dir);
344 dib7000p_write_word(st, 1030, st->gpio_val);
345
346 /* TODO 1031 is P_gpio_od */
347
348 dib7000p_write_word(st, 1032, st->cfg.gpio_pwm_pos);
349
350 dib7000p_write_word(st, 1037, st->cfg.pwm_freq_div);
351 return 0;
352}
353
Patrick Boettcher01373a52007-07-30 12:49:04 -0300354static int dib7000p_cfg_gpio(struct dib7000p_state *st, u8 num, u8 dir, u8 val)
355{
356 st->gpio_dir = dib7000p_read_word(st, 1029);
357 st->gpio_dir &= ~(1 << num); /* reset the direction bit */
358 st->gpio_dir |= (dir & 0x1) << num; /* set the new direction */
359 dib7000p_write_word(st, 1029, st->gpio_dir);
360
361 st->gpio_val = dib7000p_read_word(st, 1030);
362 st->gpio_val &= ~(1 << num); /* reset the direction bit */
363 st->gpio_val |= (val & 0x01) << num; /* set the new value */
364 dib7000p_write_word(st, 1030, st->gpio_val);
365
366 return 0;
367}
368
369int dib7000p_set_gpio(struct dvb_frontend *demod, u8 num, u8 dir, u8 val)
370{
371 struct dib7000p_state *state = demod->demodulator_priv;
372 return dib7000p_cfg_gpio(state, num, dir, val);
373}
374
375EXPORT_SYMBOL(dib7000p_set_gpio);
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300376static u16 dib7000p_defaults[] =
377
378{
379 // auto search configuration
380 3, 2,
381 0x0004,
382 0x1000,
383 0x0814, /* Equal Lock */
384
385 12, 6,
386 0x001b,
387 0x7740,
388 0x005b,
389 0x8d80,
390 0x01c9,
391 0xc380,
392 0x0000,
393 0x0080,
394 0x0000,
395 0x0090,
396 0x0001,
397 0xd4c0,
398
399 1, 26,
400 0x6680, // P_timf_alpha=6, P_corm_alpha=6, P_corm_thres=128 default: 6,4,26
401
402 /* set ADC level to -16 */
403 11, 79,
404 (1 << 13) - 825 - 117,
405 (1 << 13) - 837 - 117,
406 (1 << 13) - 811 - 117,
407 (1 << 13) - 766 - 117,
408 (1 << 13) - 737 - 117,
409 (1 << 13) - 693 - 117,
410 (1 << 13) - 648 - 117,
411 (1 << 13) - 619 - 117,
412 (1 << 13) - 575 - 117,
413 (1 << 13) - 531 - 117,
414 (1 << 13) - 501 - 117,
415
416 1, 142,
417 0x0410, // P_palf_filter_on=1, P_palf_filter_freeze=0, P_palf_alpha_regul=16
418
419 /* disable power smoothing */
420 8, 145,
421 0,
422 0,
423 0,
424 0,
425 0,
426 0,
427 0,
428 0,
429
430 1, 154,
431 1 << 13, // P_fft_freq_dir=1, P_fft_nb_to_cut=0
432
433 1, 168,
434 0x0ccd, // P_pha3_thres, default 0x3000
435
436// 1, 169,
437// 0x0010, // P_cti_use_cpe=0, P_cti_use_prog=0, P_cti_win_len=16, default: 0x0010
438
439 1, 183,
440 0x200f, // P_cspu_regul=512, P_cspu_win_cut=15, default: 0x2005
441
442 5, 187,
443 0x023d, // P_adp_regul_cnt=573, default: 410
444 0x00a4, // P_adp_noise_cnt=
445 0x00a4, // P_adp_regul_ext
446 0x7ff0, // P_adp_noise_ext
447 0x3ccc, // P_adp_fil
448
449 1, 198,
450 0x800, // P_equal_thres_wgn
451
452 1, 222,
453 0x0010, // P_fec_ber_rs_len=2
454
455 1, 235,
456 0x0062, // P_smo_mode, P_smo_rs_discard, P_smo_fifo_flush, P_smo_pid_parse, P_smo_error_discard
457
458 2, 901,
459 0x0006, // P_clk_cfg1
460 (3 << 10) | (1 << 6), // P_divclksel=3 P_divbitsel=1
461
462 1, 905,
463 0x2c8e, // Tuner IO bank: max drive (14mA) + divout pads max drive
464
465 0,
466};
467
Patrick Boettchera75763f2006-10-18 08:34:16 -0300468static int dib7000p_demod_reset(struct dib7000p_state *state)
469{
470 dib7000p_set_power_mode(state, DIB7000P_POWER_ALL);
471
472 dib7000p_set_adc_state(state, DIBX000_VBG_ENABLE);
473
474 /* restart all parts */
475 dib7000p_write_word(state, 770, 0xffff);
476 dib7000p_write_word(state, 771, 0xffff);
477 dib7000p_write_word(state, 772, 0x001f);
478 dib7000p_write_word(state, 898, 0x0003);
479 /* except i2c, sdio, gpio - control interfaces */
480 dib7000p_write_word(state, 1280, 0x01fc - ((1 << 7) | (1 << 6) | (1 << 5)) );
481
482 dib7000p_write_word(state, 770, 0);
483 dib7000p_write_word(state, 771, 0);
484 dib7000p_write_word(state, 772, 0);
485 dib7000p_write_word(state, 898, 0);
486 dib7000p_write_word(state, 1280, 0);
487
488 /* default */
489 dib7000p_reset_pll(state);
490
491 if (dib7000p_reset_gpio(state) != 0)
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300492 dprintk( "GPIO reset was not successful.");
Patrick Boettchera75763f2006-10-18 08:34:16 -0300493
494 if (dib7000p_set_output_mode(state, OUTMODE_HIGH_Z) != 0)
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300495 dprintk( "OUTPUT_MODE could not be reset.");
Patrick Boettchera75763f2006-10-18 08:34:16 -0300496
497 /* unforce divstr regardless whether i2c enumeration was done or not */
498 dib7000p_write_word(state, 1285, dib7000p_read_word(state, 1285) & ~(1 << 1) );
499
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300500 dib7000p_set_bandwidth(state, 8000);
501
502 dib7000p_set_adc_state(state, DIBX000_SLOW_ADC_ON);
503 dib7000p_sad_calib(state);
504 dib7000p_set_adc_state(state, DIBX000_SLOW_ADC_OFF);
505
506 // P_iqc_alpha_pha, P_iqc_alpha_amp_dcc_alpha, ...
507 if(state->cfg.tuner_is_baseband)
508 dib7000p_write_word(state, 36,0x0755);
509 else
510 dib7000p_write_word(state, 36,0x1f55);
511
512 dib7000p_write_tab(state, dib7000p_defaults);
513
Patrick Boettchera75763f2006-10-18 08:34:16 -0300514 dib7000p_set_power_mode(state, DIB7000P_POWER_INTERFACE_ONLY);
515
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300516
Patrick Boettchera75763f2006-10-18 08:34:16 -0300517 return 0;
518}
519
Patrick Boettchera75763f2006-10-18 08:34:16 -0300520static void dib7000p_pll_clk_cfg(struct dib7000p_state *state)
521{
522 u16 tmp = 0;
523 tmp = dib7000p_read_word(state, 903);
524 dib7000p_write_word(state, 903, (tmp | 0x1)); //pwr-up pll
525 tmp = dib7000p_read_word(state, 900);
526 dib7000p_write_word(state, 900, (tmp & 0x7fff) | (1 << 6)); //use High freq clock
527}
528
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300529static void dib7000p_restart_agc(struct dib7000p_state *state)
Patrick Boettchera75763f2006-10-18 08:34:16 -0300530{
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300531 // P_restart_iqc & P_restart_agc
532 dib7000p_write_word(state, 770, (1 << 11) | (1 << 9));
533 dib7000p_write_word(state, 770, 0x0000);
Patrick Boettchera75763f2006-10-18 08:34:16 -0300534}
535
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300536static int dib7000p_update_lna(struct dib7000p_state *state)
Patrick Boettchera75763f2006-10-18 08:34:16 -0300537{
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300538 u16 dyn_gain;
539
540 // when there is no LNA to program return immediatly
541 if (state->cfg.update_lna) {
Patrick Boettcher01373a52007-07-30 12:49:04 -0300542 // read dyn_gain here (because it is demod-dependent and not fe)
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300543 dyn_gain = dib7000p_read_word(state, 394);
544 if (state->cfg.update_lna(&state->demod,dyn_gain)) { // LNA has changed
545 dib7000p_restart_agc(state);
546 return 1;
547 }
548 }
549
550 return 0;
551}
552
553static int dib7000p_set_agc_config(struct dib7000p_state *state, u8 band)
554{
555 struct dibx000_agc_config *agc = NULL;
556 int i;
557 if (state->current_band == band && state->current_agc != NULL)
558 return 0;
559 state->current_band = band;
560
561 for (i = 0; i < state->cfg.agc_config_count; i++)
562 if (state->cfg.agc[i].band_caps & band) {
563 agc = &state->cfg.agc[i];
564 break;
565 }
566
567 if (agc == NULL) {
568 dprintk( "no valid AGC configuration found for band 0x%02x",band);
569 return -EINVAL;
570 }
571
572 state->current_agc = agc;
573
574 /* AGC */
575 dib7000p_write_word(state, 75 , agc->setup );
576 dib7000p_write_word(state, 76 , agc->inv_gain );
577 dib7000p_write_word(state, 77 , agc->time_stabiliz );
578 dib7000p_write_word(state, 100, (agc->alpha_level << 12) | agc->thlock);
579
580 // Demod AGC loop configuration
581 dib7000p_write_word(state, 101, (agc->alpha_mant << 5) | agc->alpha_exp);
582 dib7000p_write_word(state, 102, (agc->beta_mant << 6) | agc->beta_exp);
583
584 /* AGC continued */
585 dprintk( "WBD: ref: %d, sel: %d, active: %d, alpha: %d",
586 state->wbd_ref != 0 ? state->wbd_ref : agc->wbd_ref, agc->wbd_sel, !agc->perform_agc_softsplit, agc->wbd_sel);
587
588 if (state->wbd_ref != 0)
589 dib7000p_write_word(state, 105, (agc->wbd_inv << 12) | state->wbd_ref);
590 else
591 dib7000p_write_word(state, 105, (agc->wbd_inv << 12) | agc->wbd_ref);
592
593 dib7000p_write_word(state, 106, (agc->wbd_sel << 13) | (agc->wbd_alpha << 9) | (agc->perform_agc_softsplit << 8));
594
595 dib7000p_write_word(state, 107, agc->agc1_max);
596 dib7000p_write_word(state, 108, agc->agc1_min);
597 dib7000p_write_word(state, 109, agc->agc2_max);
598 dib7000p_write_word(state, 110, agc->agc2_min);
599 dib7000p_write_word(state, 111, (agc->agc1_pt1 << 8) | agc->agc1_pt2);
600 dib7000p_write_word(state, 112, agc->agc1_pt3);
601 dib7000p_write_word(state, 113, (agc->agc1_slope1 << 8) | agc->agc1_slope2);
602 dib7000p_write_word(state, 114, (agc->agc2_pt1 << 8) | agc->agc2_pt2);
603 dib7000p_write_word(state, 115, (agc->agc2_slope1 << 8) | agc->agc2_slope2);
604 return 0;
605}
606
607static int dib7000p_agc_startup(struct dvb_frontend *demod, struct dvb_frontend_parameters *ch)
608{
609 struct dib7000p_state *state = demod->demodulator_priv;
610 int ret = -1;
611 u8 *agc_state = &state->agc_state;
612 u8 agc_split;
613
614 switch (state->agc_state) {
615 case 0:
616 // set power-up level: interf+analog+AGC
617 dib7000p_set_power_mode(state, DIB7000P_POWER_ALL);
618 dib7000p_set_adc_state(state, DIBX000_ADC_ON);
619 dib7000p_pll_clk_cfg(state);
620
621 if (dib7000p_set_agc_config(state, BAND_OF_FREQUENCY(ch->frequency/1000)) != 0)
622 return -1;
623
624 ret = 7;
625 (*agc_state)++;
626 break;
627
628 case 1:
629 // AGC initialization
630 if (state->cfg.agc_control)
631 state->cfg.agc_control(&state->demod, 1);
632
633 dib7000p_write_word(state, 78, 32768);
634 if (!state->current_agc->perform_agc_softsplit) {
635 /* we are using the wbd - so slow AGC startup */
636 /* force 0 split on WBD and restart AGC */
637 dib7000p_write_word(state, 106, (state->current_agc->wbd_sel << 13) | (state->current_agc->wbd_alpha << 9) | (1 << 8));
638 (*agc_state)++;
639 ret = 5;
640 } else {
641 /* default AGC startup */
642 (*agc_state) = 4;
643 /* wait AGC rough lock time */
644 ret = 7;
645 }
646
647 dib7000p_restart_agc(state);
648 break;
649
650 case 2: /* fast split search path after 5sec */
651 dib7000p_write_word(state, 75, state->current_agc->setup | (1 << 4)); /* freeze AGC loop */
652 dib7000p_write_word(state, 106, (state->current_agc->wbd_sel << 13) | (2 << 9) | (0 << 8)); /* fast split search 0.25kHz */
653 (*agc_state)++;
654 ret = 14;
655 break;
656
657 case 3: /* split search ended */
Patrick Boettcher01373a52007-07-30 12:49:04 -0300658 agc_split = (u8)dib7000p_read_word(state, 396); /* store the split value for the next time */
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300659 dib7000p_write_word(state, 78, dib7000p_read_word(state, 394)); /* set AGC gain start value */
660
661 dib7000p_write_word(state, 75, state->current_agc->setup); /* std AGC loop */
662 dib7000p_write_word(state, 106, (state->current_agc->wbd_sel << 13) | (state->current_agc->wbd_alpha << 9) | agc_split); /* standard split search */
663
664 dib7000p_restart_agc(state);
665
666 dprintk( "SPLIT %p: %hd", demod, agc_split);
667
668 (*agc_state)++;
669 ret = 5;
670 break;
671
672 case 4: /* LNA startup */
673 // wait AGC accurate lock time
674 ret = 7;
675
676 if (dib7000p_update_lna(state))
677 // wait only AGC rough lock time
678 ret = 5;
679 else // nothing was done, go to the next state
680 (*agc_state)++;
681 break;
682
683 case 5:
684 if (state->cfg.agc_control)
685 state->cfg.agc_control(&state->demod, 0);
686 (*agc_state)++;
687 break;
688 default:
689 break;
690 }
691 return ret;
692}
693
694static void dib7000p_update_timf(struct dib7000p_state *state)
695{
696 u32 timf = (dib7000p_read_word(state, 427) << 16) | dib7000p_read_word(state, 428);
697 state->timf = timf * 160 / (state->current_bandwidth / 50);
698 dib7000p_write_word(state, 23, (u16) (timf >> 16));
699 dib7000p_write_word(state, 24, (u16) (timf & 0xffff));
700 dprintk( "updated timf_frequency: %d (default: %d)",state->timf, state->cfg.bw->timf);
701
702}
703
704static void dib7000p_set_channel(struct dib7000p_state *state, struct dvb_frontend_parameters *ch, u8 seq)
705{
706 u16 value, est[4];
707
708 dib7000p_set_bandwidth(state, BANDWIDTH_TO_KHZ(ch->u.ofdm.bandwidth));
Patrick Boettchera75763f2006-10-18 08:34:16 -0300709
710 /* nfft, guard, qam, alpha */
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300711 value = 0;
712 switch (ch->u.ofdm.transmission_mode) {
713 case TRANSMISSION_MODE_2K: value |= (0 << 7); break;
714 case /* 4K MODE */ 255: value |= (2 << 7); break;
715 default:
716 case TRANSMISSION_MODE_8K: value |= (1 << 7); break;
717 }
718 switch (ch->u.ofdm.guard_interval) {
719 case GUARD_INTERVAL_1_32: value |= (0 << 5); break;
720 case GUARD_INTERVAL_1_16: value |= (1 << 5); break;
721 case GUARD_INTERVAL_1_4: value |= (3 << 5); break;
722 default:
723 case GUARD_INTERVAL_1_8: value |= (2 << 5); break;
724 }
725 switch (ch->u.ofdm.constellation) {
726 case QPSK: value |= (0 << 3); break;
727 case QAM_16: value |= (1 << 3); break;
728 default:
729 case QAM_64: value |= (2 << 3); break;
730 }
731 switch (HIERARCHY_1) {
732 case HIERARCHY_2: value |= 2; break;
733 case HIERARCHY_4: value |= 4; break;
734 default:
735 case HIERARCHY_1: value |= 1; break;
736 }
737 dib7000p_write_word(state, 0, value);
Patrick Boettchera75763f2006-10-18 08:34:16 -0300738 dib7000p_write_word(state, 5, (seq << 4) | 1); /* do not force tps, search list 0 */
739
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300740 /* P_dintl_native, P_dintlv_inv, P_hrch, P_code_rate, P_select_hp */
741 value = 0;
742 if (1 != 0)
743 value |= (1 << 6);
744 if (ch->u.ofdm.hierarchy_information == 1)
745 value |= (1 << 4);
746 if (1 == 1)
747 value |= 1;
748 switch ((ch->u.ofdm.hierarchy_information == 0 || 1 == 1) ? ch->u.ofdm.code_rate_HP : ch->u.ofdm.code_rate_LP) {
749 case FEC_2_3: value |= (2 << 1); break;
750 case FEC_3_4: value |= (3 << 1); break;
751 case FEC_5_6: value |= (5 << 1); break;
752 case FEC_7_8: value |= (7 << 1); break;
753 default:
754 case FEC_1_2: value |= (1 << 1); break;
755 }
756 dib7000p_write_word(state, 208, value);
757
758 /* offset loop parameters */
759 dib7000p_write_word(state, 26, 0x6680); // timf(6xxx)
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300760 dib7000p_write_word(state, 32, 0x0003); // pha_off_max(xxx3)
Matt Doran8f6956c2007-07-31 07:09:30 -0300761 dib7000p_write_word(state, 29, 0x1273); // isi
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300762 dib7000p_write_word(state, 33, 0x0005); // sfreq(xxx5)
Patrick Boettchera75763f2006-10-18 08:34:16 -0300763
764 /* P_dvsy_sync_wait */
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300765 switch (ch->u.ofdm.transmission_mode) {
766 case TRANSMISSION_MODE_8K: value = 256; break;
767 case /* 4K MODE */ 255: value = 128; break;
768 case TRANSMISSION_MODE_2K:
769 default: value = 64; break;
Patrick Boettchera75763f2006-10-18 08:34:16 -0300770 }
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300771 switch (ch->u.ofdm.guard_interval) {
772 case GUARD_INTERVAL_1_16: value *= 2; break;
773 case GUARD_INTERVAL_1_8: value *= 4; break;
774 case GUARD_INTERVAL_1_4: value *= 8; break;
775 default:
776 case GUARD_INTERVAL_1_32: value *= 1; break;
777 }
778 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 -0300779
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300780 /* deactive the possibility of diversity reception if extended interleaver */
781 state->div_force_off = !1 && ch->u.ofdm.transmission_mode != TRANSMISSION_MODE_8K;
782 dib7000p_set_diversity_in(&state->demod, state->div_state);
Patrick Boettchera75763f2006-10-18 08:34:16 -0300783
784 /* channel estimation fine configuration */
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300785 switch (ch->u.ofdm.constellation) {
786 case QAM_64:
Patrick Boettchera75763f2006-10-18 08:34:16 -0300787 est[0] = 0x0148; /* P_adp_regul_cnt 0.04 */
788 est[1] = 0xfff0; /* P_adp_noise_cnt -0.002 */
789 est[2] = 0x00a4; /* P_adp_regul_ext 0.02 */
790 est[3] = 0xfff8; /* P_adp_noise_ext -0.001 */
791 break;
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300792 case QAM_16:
Patrick Boettchera75763f2006-10-18 08:34:16 -0300793 est[0] = 0x023d; /* P_adp_regul_cnt 0.07 */
794 est[1] = 0xffdf; /* P_adp_noise_cnt -0.004 */
795 est[2] = 0x00a4; /* P_adp_regul_ext 0.02 */
796 est[3] = 0xfff0; /* P_adp_noise_ext -0.002 */
797 break;
798 default:
799 est[0] = 0x099a; /* P_adp_regul_cnt 0.3 */
800 est[1] = 0xffae; /* P_adp_noise_cnt -0.01 */
801 est[2] = 0x0333; /* P_adp_regul_ext 0.1 */
802 est[3] = 0xfff8; /* P_adp_noise_ext -0.002 */
803 break;
804 }
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300805 for (value = 0; value < 4; value++)
806 dib7000p_write_word(state, 187 + value, est[value]);
Patrick Boettchera75763f2006-10-18 08:34:16 -0300807}
808
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300809static int dib7000p_autosearch_start(struct dvb_frontend *demod, struct dvb_frontend_parameters *ch)
Patrick Boettchera75763f2006-10-18 08:34:16 -0300810{
811 struct dib7000p_state *state = demod->demodulator_priv;
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300812 struct dvb_frontend_parameters schan;
813 u32 value, factor;
Patrick Boettchera75763f2006-10-18 08:34:16 -0300814
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300815 schan = *ch;
816 schan.u.ofdm.constellation = QAM_64;
817 schan.u.ofdm.guard_interval = GUARD_INTERVAL_1_32;
818 schan.u.ofdm.transmission_mode = TRANSMISSION_MODE_8K;
819 schan.u.ofdm.code_rate_HP = FEC_2_3;
820 schan.u.ofdm.code_rate_LP = FEC_3_4;
821 schan.u.ofdm.hierarchy_information = 0;
Patrick Boettchera75763f2006-10-18 08:34:16 -0300822
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300823 dib7000p_set_channel(state, &schan, 7);
824
825 factor = BANDWIDTH_TO_KHZ(ch->u.ofdm.bandwidth);
826 if (factor >= 5000)
827 factor = 1;
828 else
829 factor = 6;
Patrick Boettchera75763f2006-10-18 08:34:16 -0300830
831 // always use the setting for 8MHz here lock_time for 7,6 MHz are longer
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300832 value = 30 * state->cfg.bw->internal * factor;
Patrick Boettchera75763f2006-10-18 08:34:16 -0300833 dib7000p_write_word(state, 6, (u16) ((value >> 16) & 0xffff)); // lock0 wait time
834 dib7000p_write_word(state, 7, (u16) (value & 0xffff)); // lock0 wait time
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300835 value = 100 * state->cfg.bw->internal * factor;
Patrick Boettchera75763f2006-10-18 08:34:16 -0300836 dib7000p_write_word(state, 8, (u16) ((value >> 16) & 0xffff)); // lock1 wait time
837 dib7000p_write_word(state, 9, (u16) (value & 0xffff)); // lock1 wait time
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300838 value = 500 * state->cfg.bw->internal * factor;
Patrick Boettchera75763f2006-10-18 08:34:16 -0300839 dib7000p_write_word(state, 10, (u16) ((value >> 16) & 0xffff)); // lock2 wait time
840 dib7000p_write_word(state, 11, (u16) (value & 0xffff)); // lock2 wait time
841
842 value = dib7000p_read_word(state, 0);
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300843 dib7000p_write_word(state, 0, (u16) ((1 << 9) | value));
Patrick Boettchera75763f2006-10-18 08:34:16 -0300844 dib7000p_read_word(state, 1284);
845 dib7000p_write_word(state, 0, (u16) value);
846
847 return 0;
848}
849
850static int dib7000p_autosearch_is_irq(struct dvb_frontend *demod)
851{
852 struct dib7000p_state *state = demod->demodulator_priv;
853 u16 irq_pending = dib7000p_read_word(state, 1284);
854
855 if (irq_pending & 0x1) // failed
856 return 1;
857
858 if (irq_pending & 0x2) // succeeded
859 return 2;
860
861 return 0; // still pending
862}
863
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300864static void dib7000p_spur_protect(struct dib7000p_state *state, u32 rf_khz, u32 bw)
865{
866 static s16 notch[]={16143, 14402, 12238, 9713, 6902, 3888, 759, -2392};
867 static u8 sine [] ={0, 2, 3, 5, 6, 8, 9, 11, 13, 14, 16, 17, 19, 20, 22,
868 24, 25, 27, 28, 30, 31, 33, 34, 36, 38, 39, 41, 42, 44, 45, 47, 48, 50, 51,
869 53, 55, 56, 58, 59, 61, 62, 64, 65, 67, 68, 70, 71, 73, 74, 76, 77, 79, 80,
870 82, 83, 85, 86, 88, 89, 91, 92, 94, 95, 97, 98, 99, 101, 102, 104, 105,
871 107, 108, 109, 111, 112, 114, 115, 117, 118, 119, 121, 122, 123, 125, 126,
872 128, 129, 130, 132, 133, 134, 136, 137, 138, 140, 141, 142, 144, 145, 146,
873 147, 149, 150, 151, 152, 154, 155, 156, 157, 159, 160, 161, 162, 164, 165,
874 166, 167, 168, 170, 171, 172, 173, 174, 175, 177, 178, 179, 180, 181, 182,
875 183, 184, 185, 186, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198,
876 199, 200, 201, 202, 203, 204, 205, 206, 207, 207, 208, 209, 210, 211, 212,
877 213, 214, 215, 215, 216, 217, 218, 219, 220, 220, 221, 222, 223, 224, 224,
878 225, 226, 227, 227, 228, 229, 229, 230, 231, 231, 232, 233, 233, 234, 235,
879 235, 236, 237, 237, 238, 238, 239, 239, 240, 241, 241, 242, 242, 243, 243,
880 244, 244, 245, 245, 245, 246, 246, 247, 247, 248, 248, 248, 249, 249, 249,
881 250, 250, 250, 251, 251, 251, 252, 252, 252, 252, 253, 253, 253, 253, 254,
882 254, 254, 254, 254, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
883 255, 255, 255, 255, 255, 255};
884
885 u32 xtal = state->cfg.bw->xtal_hz / 1000;
886 int f_rel = ( (rf_khz + xtal/2) / xtal) * xtal - rf_khz;
887 int k;
888 int coef_re[8],coef_im[8];
889 int bw_khz = bw;
890 u32 pha;
891
892 dprintk( "relative position of the Spur: %dk (RF: %dk, XTAL: %dk)", f_rel, rf_khz, xtal);
893
894
895 if (f_rel < -bw_khz/2 || f_rel > bw_khz/2)
896 return;
897
898 bw_khz /= 100;
899
900 dib7000p_write_word(state, 142 ,0x0610);
901
902 for (k = 0; k < 8; k++) {
903 pha = ((f_rel * (k+1) * 112 * 80/bw_khz) /1000) & 0x3ff;
904
905 if (pha==0) {
906 coef_re[k] = 256;
907 coef_im[k] = 0;
908 } else if(pha < 256) {
909 coef_re[k] = sine[256-(pha&0xff)];
910 coef_im[k] = sine[pha&0xff];
911 } else if (pha == 256) {
912 coef_re[k] = 0;
913 coef_im[k] = 256;
914 } else if (pha < 512) {
915 coef_re[k] = -sine[pha&0xff];
916 coef_im[k] = sine[256 - (pha&0xff)];
917 } else if (pha == 512) {
918 coef_re[k] = -256;
919 coef_im[k] = 0;
920 } else if (pha < 768) {
921 coef_re[k] = -sine[256-(pha&0xff)];
922 coef_im[k] = -sine[pha&0xff];
923 } else if (pha == 768) {
924 coef_re[k] = 0;
925 coef_im[k] = -256;
926 } else {
927 coef_re[k] = sine[pha&0xff];
928 coef_im[k] = -sine[256 - (pha&0xff)];
929 }
930
931 coef_re[k] *= notch[k];
932 coef_re[k] += (1<<14);
933 if (coef_re[k] >= (1<<24))
934 coef_re[k] = (1<<24) - 1;
935 coef_re[k] /= (1<<15);
936
937 coef_im[k] *= notch[k];
938 coef_im[k] += (1<<14);
939 if (coef_im[k] >= (1<<24))
940 coef_im[k] = (1<<24)-1;
941 coef_im[k] /= (1<<15);
942
943 dprintk( "PALF COEF: %d re: %d im: %d", k, coef_re[k], coef_im[k]);
944
945 dib7000p_write_word(state, 143, (0 << 14) | (k << 10) | (coef_re[k] & 0x3ff));
946 dib7000p_write_word(state, 144, coef_im[k] & 0x3ff);
947 dib7000p_write_word(state, 143, (1 << 14) | (k << 10) | (coef_re[k] & 0x3ff));
948 }
949 dib7000p_write_word(state,143 ,0);
950}
951
952static int dib7000p_tune(struct dvb_frontend *demod, struct dvb_frontend_parameters *ch)
Patrick Boettchera75763f2006-10-18 08:34:16 -0300953{
954 struct dib7000p_state *state = demod->demodulator_priv;
955 u16 tmp = 0;
956
957 if (ch != NULL)
958 dib7000p_set_channel(state, ch, 0);
959 else
960 return -EINVAL;
961
962 // restart demod
963 dib7000p_write_word(state, 770, 0x4000);
964 dib7000p_write_word(state, 770, 0x0000);
965 msleep(45);
966
967 /* 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 -0300968 tmp = (0 << 14) | (4 << 10) | (0 << 9) | (3 << 5) | (1 << 4) | (0x3);
969 if (state->sfn_workaround_active) {
970 dprintk( "SFN workaround is active");
971 tmp |= (1 << 9);
972 dib7000p_write_word(state, 166, 0x4000); // P_pha3_force_pha_shift
973 } else {
974 dib7000p_write_word(state, 166, 0x0000); // P_pha3_force_pha_shift
975 }
976 dib7000p_write_word(state, 29, tmp);
Patrick Boettchera75763f2006-10-18 08:34:16 -0300977
978 // never achieved a lock with that bandwidth so far - wait for osc-freq to update
979 if (state->timf == 0)
980 msleep(200);
981
982 /* offset loop parameters */
983
984 /* P_timf_alpha, P_corm_alpha=6, P_corm_thres=0x80 */
985 tmp = (6 << 8) | 0x80;
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300986 switch (ch->u.ofdm.transmission_mode) {
987 case TRANSMISSION_MODE_2K: tmp |= (7 << 12); break;
988 case /* 4K MODE */ 255: tmp |= (8 << 12); break;
989 default:
990 case TRANSMISSION_MODE_8K: tmp |= (9 << 12); break;
Patrick Boettchera75763f2006-10-18 08:34:16 -0300991 }
992 dib7000p_write_word(state, 26, tmp); /* timf_a(6xxx) */
993
994 /* P_ctrl_freeze_pha_shift=0, P_ctrl_pha_off_max */
995 tmp = (0 << 4);
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300996 switch (ch->u.ofdm.transmission_mode) {
997 case TRANSMISSION_MODE_2K: tmp |= 0x6; break;
998 case /* 4K MODE */ 255: tmp |= 0x7; break;
999 default:
1000 case TRANSMISSION_MODE_8K: tmp |= 0x8; break;
Patrick Boettchera75763f2006-10-18 08:34:16 -03001001 }
1002 dib7000p_write_word(state, 32, tmp);
1003
1004 /* P_ctrl_sfreq_inh=0, P_ctrl_sfreq_step */
1005 tmp = (0 << 4);
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001006 switch (ch->u.ofdm.transmission_mode) {
1007 case TRANSMISSION_MODE_2K: tmp |= 0x6; break;
1008 case /* 4K MODE */ 255: tmp |= 0x7; break;
1009 default:
1010 case TRANSMISSION_MODE_8K: tmp |= 0x8; break;
Patrick Boettchera75763f2006-10-18 08:34:16 -03001011 }
1012 dib7000p_write_word(state, 33, tmp);
1013
1014 tmp = dib7000p_read_word(state,509);
1015 if (!((tmp >> 6) & 0x1)) {
1016 /* restart the fec */
1017 tmp = dib7000p_read_word(state,771);
1018 dib7000p_write_word(state, 771, tmp | (1 << 1));
1019 dib7000p_write_word(state, 771, tmp);
1020 msleep(10);
1021 tmp = dib7000p_read_word(state,509);
1022 }
1023
1024 // we achieved a lock - it's time to update the osc freq
1025 if ((tmp >> 6) & 0x1)
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001026 dib7000p_update_timf(state);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001027
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001028 if (state->cfg.spur_protect)
1029 dib7000p_spur_protect(state, ch->frequency/1000, BANDWIDTH_TO_KHZ(ch->u.ofdm.bandwidth));
1030
1031 dib7000p_set_bandwidth(state, BANDWIDTH_TO_KHZ(ch->u.ofdm.bandwidth));
Patrick Boettchera75763f2006-10-18 08:34:16 -03001032 return 0;
1033}
1034
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001035static int dib7000p_wakeup(struct dvb_frontend *demod)
Patrick Boettchera75763f2006-10-18 08:34:16 -03001036{
Patrick Boettchera75763f2006-10-18 08:34:16 -03001037 struct dib7000p_state *state = demod->demodulator_priv;
Patrick Boettchera75763f2006-10-18 08:34:16 -03001038 dib7000p_set_power_mode(state, DIB7000P_POWER_ALL);
1039 dib7000p_set_adc_state(state, DIBX000_SLOW_ADC_ON);
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001040 return 0;
Patrick Boettchera75763f2006-10-18 08:34:16 -03001041}
1042
1043static int dib7000p_sleep(struct dvb_frontend *demod)
1044{
1045 struct dib7000p_state *state = demod->demodulator_priv;
1046 return dib7000p_set_output_mode(state, OUTMODE_HIGH_Z) | dib7000p_set_power_mode(state, DIB7000P_POWER_INTERFACE_ONLY);
1047}
1048
1049static int dib7000p_identify(struct dib7000p_state *st)
1050{
1051 u16 value;
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001052 dprintk( "checking demod on I2C address: %d (%x)",
Patrick Boettchera75763f2006-10-18 08:34:16 -03001053 st->i2c_addr, st->i2c_addr);
1054
1055 if ((value = dib7000p_read_word(st, 768)) != 0x01b3) {
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001056 dprintk( "wrong Vendor ID (read=0x%x)",value);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001057 return -EREMOTEIO;
1058 }
1059
1060 if ((value = dib7000p_read_word(st, 769)) != 0x4000) {
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001061 dprintk( "wrong Device ID (%x)",value);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001062 return -EREMOTEIO;
1063 }
1064
1065 return 0;
1066}
1067
1068
1069static int dib7000p_get_frontend(struct dvb_frontend* fe,
1070 struct dvb_frontend_parameters *fep)
1071{
1072 struct dib7000p_state *state = fe->demodulator_priv;
1073 u16 tps = dib7000p_read_word(state,463);
1074
1075 fep->inversion = INVERSION_AUTO;
1076
1077 fep->u.ofdm.bandwidth = state->current_bandwidth;
1078
1079 switch ((tps >> 8) & 0x3) {
1080 case 0: fep->u.ofdm.transmission_mode = TRANSMISSION_MODE_2K; break;
1081 case 1: fep->u.ofdm.transmission_mode = TRANSMISSION_MODE_8K; break;
1082 /* case 2: fep->u.ofdm.transmission_mode = TRANSMISSION_MODE_4K; break; */
1083 }
1084
1085 switch (tps & 0x3) {
1086 case 0: fep->u.ofdm.guard_interval = GUARD_INTERVAL_1_32; break;
1087 case 1: fep->u.ofdm.guard_interval = GUARD_INTERVAL_1_16; break;
1088 case 2: fep->u.ofdm.guard_interval = GUARD_INTERVAL_1_8; break;
1089 case 3: fep->u.ofdm.guard_interval = GUARD_INTERVAL_1_4; break;
1090 }
1091
1092 switch ((tps >> 14) & 0x3) {
1093 case 0: fep->u.ofdm.constellation = QPSK; break;
1094 case 1: fep->u.ofdm.constellation = QAM_16; break;
1095 case 2:
1096 default: fep->u.ofdm.constellation = QAM_64; break;
1097 }
1098
1099 /* as long as the frontend_param structure is fixed for hierarchical transmission I refuse to use it */
1100 /* (tps >> 13) & 0x1 == hrch is used, (tps >> 10) & 0x7 == alpha */
1101
1102 fep->u.ofdm.hierarchy_information = HIERARCHY_NONE;
1103 switch ((tps >> 5) & 0x7) {
1104 case 1: fep->u.ofdm.code_rate_HP = FEC_1_2; break;
1105 case 2: fep->u.ofdm.code_rate_HP = FEC_2_3; break;
1106 case 3: fep->u.ofdm.code_rate_HP = FEC_3_4; break;
1107 case 5: fep->u.ofdm.code_rate_HP = FEC_5_6; break;
1108 case 7:
1109 default: fep->u.ofdm.code_rate_HP = FEC_7_8; break;
1110
1111 }
1112
1113 switch ((tps >> 2) & 0x7) {
1114 case 1: fep->u.ofdm.code_rate_LP = FEC_1_2; break;
1115 case 2: fep->u.ofdm.code_rate_LP = FEC_2_3; break;
1116 case 3: fep->u.ofdm.code_rate_LP = FEC_3_4; break;
1117 case 5: fep->u.ofdm.code_rate_LP = FEC_5_6; break;
1118 case 7:
1119 default: fep->u.ofdm.code_rate_LP = FEC_7_8; break;
1120 }
1121
1122 /* native interleaver: (dib7000p_read_word(state, 464) >> 5) & 0x1 */
1123
1124 return 0;
1125}
1126
1127static int dib7000p_set_frontend(struct dvb_frontend* fe,
1128 struct dvb_frontend_parameters *fep)
1129{
1130 struct dib7000p_state *state = fe->demodulator_priv;
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001131 int time;
Patrick Boettchera75763f2006-10-18 08:34:16 -03001132
1133 state->current_bandwidth = fep->u.ofdm.bandwidth;
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001134 dib7000p_set_bandwidth(state, BANDWIDTH_TO_KHZ(fep->u.ofdm.bandwidth));
Patrick Boettchera75763f2006-10-18 08:34:16 -03001135
Matt Doran8f6956c2007-07-31 07:09:30 -03001136 /* maybe the parameter has been changed */
1137 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
1169 /* make this a config parameter */
1170 dib7000p_set_output_mode(state, OUTMODE_MPEG2_FIFO);
1171
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001172 return dib7000p_tune(fe, fep);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001173}
1174
1175static int dib7000p_read_status(struct dvb_frontend *fe, fe_status_t *stat)
1176{
1177 struct dib7000p_state *state = fe->demodulator_priv;
1178 u16 lock = dib7000p_read_word(state, 509);
1179
1180 *stat = 0;
1181
1182 if (lock & 0x8000)
1183 *stat |= FE_HAS_SIGNAL;
1184 if (lock & 0x3000)
1185 *stat |= FE_HAS_CARRIER;
1186 if (lock & 0x0100)
1187 *stat |= FE_HAS_VITERBI;
1188 if (lock & 0x0010)
1189 *stat |= FE_HAS_SYNC;
1190 if (lock & 0x0008)
1191 *stat |= FE_HAS_LOCK;
1192
1193 return 0;
1194}
1195
1196static int dib7000p_read_ber(struct dvb_frontend *fe, u32 *ber)
1197{
1198 struct dib7000p_state *state = fe->demodulator_priv;
1199 *ber = (dib7000p_read_word(state, 500) << 16) | dib7000p_read_word(state, 501);
1200 return 0;
1201}
1202
1203static int dib7000p_read_unc_blocks(struct dvb_frontend *fe, u32 *unc)
1204{
1205 struct dib7000p_state *state = fe->demodulator_priv;
1206 *unc = dib7000p_read_word(state, 506);
1207 return 0;
1208}
1209
1210static int dib7000p_read_signal_strength(struct dvb_frontend *fe, u16 *strength)
1211{
1212 struct dib7000p_state *state = fe->demodulator_priv;
1213 u16 val = dib7000p_read_word(state, 394);
1214 *strength = 65535 - val;
1215 return 0;
1216}
1217
1218static int dib7000p_read_snr(struct dvb_frontend* fe, u16 *snr)
1219{
1220 *snr = 0x0000;
1221 return 0;
1222}
1223
1224static int dib7000p_fe_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings *tune)
1225{
1226 tune->min_delay_ms = 1000;
1227 return 0;
1228}
1229
1230static void dib7000p_release(struct dvb_frontend *demod)
1231{
1232 struct dib7000p_state *st = demod->demodulator_priv;
1233 dibx000_exit_i2c_master(&st->i2c_master);
1234 kfree(st);
1235}
1236
1237int dib7000pc_detection(struct i2c_adapter *i2c_adap)
1238{
1239 u8 tx[2], rx[2];
1240 struct i2c_msg msg[2] = {
1241 { .addr = 18 >> 1, .flags = 0, .buf = tx, .len = 2 },
1242 { .addr = 18 >> 1, .flags = I2C_M_RD, .buf = rx, .len = 2 },
1243 };
1244
1245 tx[0] = 0x03;
1246 tx[1] = 0x00;
1247
1248 if (i2c_transfer(i2c_adap, msg, 2) == 2)
1249 if (rx[0] == 0x01 && rx[1] == 0xb3) {
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001250 dprintk("-D- DiB7000PC detected");
Patrick Boettchera75763f2006-10-18 08:34:16 -03001251 return 1;
1252 }
1253
1254 msg[0].addr = msg[1].addr = 0x40;
1255
1256 if (i2c_transfer(i2c_adap, msg, 2) == 2)
1257 if (rx[0] == 0x01 && rx[1] == 0xb3) {
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001258 dprintk("-D- DiB7000PC detected");
Patrick Boettchera75763f2006-10-18 08:34:16 -03001259 return 1;
1260 }
1261
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001262 dprintk("-D- DiB7000PC not detected");
Patrick Boettchera75763f2006-10-18 08:34:16 -03001263 return 0;
1264}
1265EXPORT_SYMBOL(dib7000pc_detection);
1266
1267struct i2c_adapter * dib7000p_get_i2c_master(struct dvb_frontend *demod, enum dibx000_i2c_interface intf, int gating)
1268{
1269 struct dib7000p_state *st = demod->demodulator_priv;
1270 return dibx000_get_i2c_adapter(&st->i2c_master, intf, gating);
1271}
1272EXPORT_SYMBOL(dib7000p_get_i2c_master);
1273
1274int dib7000p_i2c_enumeration(struct i2c_adapter *i2c, int no_of_demods, u8 default_addr, struct dib7000p_config cfg[])
1275{
1276 struct dib7000p_state st = { .i2c_adap = i2c };
1277 int k = 0;
1278 u8 new_addr = 0;
1279
1280 for (k = no_of_demods-1; k >= 0; k--) {
1281 st.cfg = cfg[k];
1282
1283 /* designated i2c address */
1284 new_addr = (0x40 + k) << 1;
1285 st.i2c_addr = new_addr;
1286 if (dib7000p_identify(&st) != 0) {
1287 st.i2c_addr = default_addr;
1288 if (dib7000p_identify(&st) != 0) {
1289 dprintk("DiB7000P #%d: not identified\n", k);
1290 return -EIO;
1291 }
1292 }
1293
1294 /* start diversity to pull_down div_str - just for i2c-enumeration */
1295 dib7000p_set_output_mode(&st, OUTMODE_DIVERSITY);
1296
1297 /* set new i2c address and force divstart */
1298 dib7000p_write_word(&st, 1285, (new_addr << 2) | 0x2);
1299
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001300 dprintk("IC %d initialized (to i2c_address 0x%x)", k, new_addr);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001301 }
1302
1303 for (k = 0; k < no_of_demods; k++) {
1304 st.cfg = cfg[k];
1305 st.i2c_addr = (0x40 + k) << 1;
1306
1307 // unforce divstr
1308 dib7000p_write_word(&st, 1285, st.i2c_addr << 2);
1309
1310 /* deactivate div - it was just for i2c-enumeration */
1311 dib7000p_set_output_mode(&st, OUTMODE_HIGH_Z);
1312 }
1313
1314 return 0;
1315}
1316EXPORT_SYMBOL(dib7000p_i2c_enumeration);
1317
1318static struct dvb_frontend_ops dib7000p_ops;
1319struct dvb_frontend * dib7000p_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr, struct dib7000p_config *cfg)
1320{
1321 struct dvb_frontend *demod;
1322 struct dib7000p_state *st;
1323 st = kzalloc(sizeof(struct dib7000p_state), GFP_KERNEL);
1324 if (st == NULL)
1325 return NULL;
1326
1327 memcpy(&st->cfg, cfg, sizeof(struct dib7000p_config));
1328 st->i2c_adap = i2c_adap;
1329 st->i2c_addr = i2c_addr;
1330 st->gpio_val = cfg->gpio_val;
1331 st->gpio_dir = cfg->gpio_dir;
1332
1333 demod = &st->demod;
1334 demod->demodulator_priv = st;
1335 memcpy(&st->demod.ops, &dib7000p_ops, sizeof(struct dvb_frontend_ops));
1336
1337 if (dib7000p_identify(st) != 0)
1338 goto error;
1339
1340 dibx000_init_i2c_master(&st->i2c_master, DIB7000P, st->i2c_adap, st->i2c_addr);
1341
1342 dib7000p_demod_reset(st);
1343
1344 return demod;
1345
1346error:
1347 kfree(st);
1348 return NULL;
1349}
1350EXPORT_SYMBOL(dib7000p_attach);
1351
1352static struct dvb_frontend_ops dib7000p_ops = {
1353 .info = {
1354 .name = "DiBcom 7000PC",
1355 .type = FE_OFDM,
1356 .frequency_min = 44250000,
1357 .frequency_max = 867250000,
1358 .frequency_stepsize = 62500,
1359 .caps = FE_CAN_INVERSION_AUTO |
1360 FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
1361 FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
1362 FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO |
1363 FE_CAN_TRANSMISSION_MODE_AUTO |
1364 FE_CAN_GUARD_INTERVAL_AUTO |
1365 FE_CAN_RECOVER |
1366 FE_CAN_HIERARCHY_AUTO,
1367 },
1368
1369 .release = dib7000p_release,
1370
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001371 .init = dib7000p_wakeup,
Patrick Boettchera75763f2006-10-18 08:34:16 -03001372 .sleep = dib7000p_sleep,
1373
1374 .set_frontend = dib7000p_set_frontend,
1375 .get_tune_settings = dib7000p_fe_get_tune_settings,
1376 .get_frontend = dib7000p_get_frontend,
1377
1378 .read_status = dib7000p_read_status,
1379 .read_ber = dib7000p_read_ber,
1380 .read_signal_strength = dib7000p_read_signal_strength,
1381 .read_snr = dib7000p_read_snr,
1382 .read_ucblocks = dib7000p_read_unc_blocks,
1383};
1384
1385MODULE_AUTHOR("Patrick Boettcher <pboettcher@dibcom.fr>");
1386MODULE_DESCRIPTION("Driver for the DiBcom 7000PC COFDM demodulator");
1387MODULE_LICENSE("GPL");