blob: 73f59ab06c86f44a85683d947e253f9ef5687d4a [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>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090011#include <linux/slab.h>
Patrick Boettchera75763f2006-10-18 08:34:16 -030012#include <linux/i2c.h>
13
Olivier Grenieef801962009-09-15 06:46:52 -030014#include "dvb_math.h"
Patrick Boettchera75763f2006-10-18 08:34:16 -030015#include "dvb_frontend.h"
16
17#include "dib7000p.h"
18
19static int debug;
20module_param(debug, int, 0644);
21MODULE_PARM_DESC(debug, "turn on debugging (default: 0)");
22
Matt Doran8f6956c2007-07-31 07:09:30 -030023static int buggy_sfn_workaround;
24module_param(buggy_sfn_workaround, int, 0644);
Patrick Boettcher8d999962007-07-31 10:36:06 -030025MODULE_PARM_DESC(buggy_sfn_workaround, "Enable work-around for buggy SFNs (default: 0)");
Matt Doran8f6956c2007-07-31 07:09:30 -030026
Patrick Boettcherb6884a12007-07-27 10:08:51 -030027#define dprintk(args...) do { if (debug) { printk(KERN_DEBUG "DiB7000P: "); printk(args); printk("\n"); } } while (0)
Patrick Boettchera75763f2006-10-18 08:34:16 -030028
29struct dib7000p_state {
30 struct dvb_frontend demod;
31 struct dib7000p_config cfg;
32
33 u8 i2c_addr;
34 struct i2c_adapter *i2c_adap;
35
36 struct dibx000_i2c_master i2c_master;
37
38 u16 wbd_ref;
39
Patrick Boettcher904a82e2008-01-25 07:31:58 -030040 u8 current_band;
41 u32 current_bandwidth;
Patrick Boettchera75763f2006-10-18 08:34:16 -030042 struct dibx000_agc_config *current_agc;
43 u32 timf;
44
Patrick Boettcher01373a52007-07-30 12:49:04 -030045 u8 div_force_off : 1;
46 u8 div_state : 1;
47 u16 div_sync_wait;
Patrick Boettcherb6884a12007-07-27 10:08:51 -030048
49 u8 agc_state;
50
Patrick Boettchera75763f2006-10-18 08:34:16 -030051 u16 gpio_dir;
52 u16 gpio_val;
Matt Doran8f6956c2007-07-31 07:09:30 -030053
54 u8 sfn_workaround_active :1;
Patrick Boettchera75763f2006-10-18 08:34:16 -030055};
56
57enum dib7000p_power_mode {
58 DIB7000P_POWER_ALL = 0,
Patrick Boettcherb6884a12007-07-27 10:08:51 -030059 DIB7000P_POWER_ANALOG_ADC,
Patrick Boettchera75763f2006-10-18 08:34:16 -030060 DIB7000P_POWER_INTERFACE_ONLY,
61};
62
63static u16 dib7000p_read_word(struct dib7000p_state *state, u16 reg)
64{
65 u8 wb[2] = { reg >> 8, reg & 0xff };
66 u8 rb[2];
67 struct i2c_msg msg[2] = {
68 { .addr = state->i2c_addr >> 1, .flags = 0, .buf = wb, .len = 2 },
69 { .addr = state->i2c_addr >> 1, .flags = I2C_M_RD, .buf = rb, .len = 2 },
70 };
71
72 if (i2c_transfer(state->i2c_adap, msg, 2) != 2)
Patrick Boettcherb6884a12007-07-27 10:08:51 -030073 dprintk("i2c read error on %d",reg);
Patrick Boettchera75763f2006-10-18 08:34:16 -030074
75 return (rb[0] << 8) | rb[1];
76}
77
78static int dib7000p_write_word(struct dib7000p_state *state, u16 reg, u16 val)
79{
80 u8 b[4] = {
81 (reg >> 8) & 0xff, reg & 0xff,
82 (val >> 8) & 0xff, val & 0xff,
83 };
84 struct i2c_msg msg = {
85 .addr = state->i2c_addr >> 1, .flags = 0, .buf = b, .len = 4
86 };
87 return i2c_transfer(state->i2c_adap, &msg, 1) != 1 ? -EREMOTEIO : 0;
88}
Patrick Boettcherb6884a12007-07-27 10:08:51 -030089static void dib7000p_write_tab(struct dib7000p_state *state, u16 *buf)
90{
91 u16 l = 0, r, *n;
92 n = buf;
93 l = *n++;
94 while (l) {
95 r = *n++;
96
97 do {
98 dib7000p_write_word(state, r, *n++);
99 r++;
100 } while (--l);
101 l = *n++;
102 }
103}
104
Patrick Boettchera75763f2006-10-18 08:34:16 -0300105static int dib7000p_set_output_mode(struct dib7000p_state *state, int mode)
106{
107 int ret = 0;
108 u16 outreg, fifo_threshold, smo_mode;
109
110 outreg = 0;
111 fifo_threshold = 1792;
Olivier Grenieeac1fe12009-09-23 13:41:27 -0300112 smo_mode = (dib7000p_read_word(state, 235) & 0x0050) | (1 << 1);
Patrick Boettchera75763f2006-10-18 08:34:16 -0300113
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300114 dprintk( "setting output mode for demod %p to %d",
Patrick Boettchera75763f2006-10-18 08:34:16 -0300115 &state->demod, mode);
116
117 switch (mode) {
118 case OUTMODE_MPEG2_PAR_GATED_CLK: // STBs with parallel gated clock
119 outreg = (1 << 10); /* 0x0400 */
120 break;
121 case OUTMODE_MPEG2_PAR_CONT_CLK: // STBs with parallel continues clock
122 outreg = (1 << 10) | (1 << 6); /* 0x0440 */
123 break;
124 case OUTMODE_MPEG2_SERIAL: // STBs with serial input
125 outreg = (1 << 10) | (2 << 6) | (0 << 1); /* 0x0480 */
126 break;
127 case OUTMODE_DIVERSITY:
128 if (state->cfg.hostbus_diversity)
129 outreg = (1 << 10) | (4 << 6); /* 0x0500 */
130 else
131 outreg = (1 << 11);
132 break;
133 case OUTMODE_MPEG2_FIFO: // e.g. USB feeding
134 smo_mode |= (3 << 1);
135 fifo_threshold = 512;
136 outreg = (1 << 10) | (5 << 6);
137 break;
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300138 case OUTMODE_ANALOG_ADC:
139 outreg = (1 << 10) | (3 << 6);
140 break;
Patrick Boettchera75763f2006-10-18 08:34:16 -0300141 case OUTMODE_HIGH_Z: // disable
142 outreg = 0;
143 break;
144 default:
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300145 dprintk( "Unhandled output_mode passed to be set for demod %p",&state->demod);
Patrick Boettchera75763f2006-10-18 08:34:16 -0300146 break;
147 }
148
149 if (state->cfg.output_mpeg2_in_188_bytes)
150 smo_mode |= (1 << 5) ;
151
152 ret |= dib7000p_write_word(state, 235, smo_mode);
153 ret |= dib7000p_write_word(state, 236, fifo_threshold); /* synchronous fread */
154 ret |= dib7000p_write_word(state, 1286, outreg); /* P_Div_active */
155
156 return ret;
157}
158
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300159static int dib7000p_set_diversity_in(struct dvb_frontend *demod, int onoff)
160{
161 struct dib7000p_state *state = demod->demodulator_priv;
162
163 if (state->div_force_off) {
164 dprintk( "diversity combination deactivated - forced by COFDM parameters");
165 onoff = 0;
Olivier Grenieeac1fe12009-09-23 13:41:27 -0300166 dib7000p_write_word(state, 207, 0);
167 } else
168 dib7000p_write_word(state, 207, (state->div_sync_wait << 4) | (1 << 2) | (2 << 0));
169
Patrick Boettcher01373a52007-07-30 12:49:04 -0300170 state->div_state = (u8)onoff;
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300171
172 if (onoff) {
173 dib7000p_write_word(state, 204, 6);
174 dib7000p_write_word(state, 205, 16);
175 /* P_dvsy_sync_mode = 0, P_dvsy_sync_enable=1, P_dvcb_comb_mode=2 */
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300176 } else {
177 dib7000p_write_word(state, 204, 1);
178 dib7000p_write_word(state, 205, 0);
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300179 }
180
181 return 0;
182}
183
Patrick Boettchera75763f2006-10-18 08:34:16 -0300184static int dib7000p_set_power_mode(struct dib7000p_state *state, enum dib7000p_power_mode mode)
185{
186 /* by default everything is powered off */
187 u16 reg_774 = 0xffff, reg_775 = 0xffff, reg_776 = 0x0007, reg_899 = 0x0003,
188 reg_1280 = (0xfe00) | (dib7000p_read_word(state, 1280) & 0x01ff);
189
190 /* now, depending on the requested mode, we power on */
191 switch (mode) {
192 /* power up everything in the demod */
193 case DIB7000P_POWER_ALL:
194 reg_774 = 0x0000; reg_775 = 0x0000; reg_776 = 0x0; reg_899 = 0x0; reg_1280 &= 0x01ff;
195 break;
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300196
197 case DIB7000P_POWER_ANALOG_ADC:
198 /* dem, cfg, iqc, sad, agc */
199 reg_774 &= ~((1 << 15) | (1 << 14) | (1 << 11) | (1 << 10) | (1 << 9));
200 /* nud */
201 reg_776 &= ~((1 << 0));
202 /* Dout */
203 reg_1280 &= ~((1 << 11));
204 /* fall through wanted to enable the interfaces */
205
Patrick Boettchera75763f2006-10-18 08:34:16 -0300206 /* just leave power on the control-interfaces: GPIO and (I2C or SDIO) */
207 case DIB7000P_POWER_INTERFACE_ONLY: /* TODO power up either SDIO or I2C */
208 reg_1280 &= ~((1 << 14) | (1 << 13) | (1 << 12) | (1 << 10));
209 break;
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300210
Patrick Boettchera75763f2006-10-18 08:34:16 -0300211/* TODO following stuff is just converted from the dib7000-driver - check when is used what */
212 }
213
214 dib7000p_write_word(state, 774, reg_774);
215 dib7000p_write_word(state, 775, reg_775);
216 dib7000p_write_word(state, 776, reg_776);
217 dib7000p_write_word(state, 899, reg_899);
218 dib7000p_write_word(state, 1280, reg_1280);
219
220 return 0;
221}
222
223static void dib7000p_set_adc_state(struct dib7000p_state *state, enum dibx000_adc_states no)
224{
225 u16 reg_908 = dib7000p_read_word(state, 908),
226 reg_909 = dib7000p_read_word(state, 909);
227
228 switch (no) {
229 case DIBX000_SLOW_ADC_ON:
230 reg_909 |= (1 << 1) | (1 << 0);
231 dib7000p_write_word(state, 909, reg_909);
232 reg_909 &= ~(1 << 1);
233 break;
234
235 case DIBX000_SLOW_ADC_OFF:
236 reg_909 |= (1 << 1) | (1 << 0);
237 break;
238
239 case DIBX000_ADC_ON:
240 reg_908 &= 0x0fff;
241 reg_909 &= 0x0003;
242 break;
243
244 case DIBX000_ADC_OFF: // leave the VBG voltage on
245 reg_908 |= (1 << 14) | (1 << 13) | (1 << 12);
246 reg_909 |= (1 << 5) | (1 << 4) | (1 << 3) | (1 << 2);
247 break;
248
249 case DIBX000_VBG_ENABLE:
250 reg_908 &= ~(1 << 15);
251 break;
252
253 case DIBX000_VBG_DISABLE:
254 reg_908 |= (1 << 15);
255 break;
256
257 default:
258 break;
259 }
260
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300261// dprintk( "908: %x, 909: %x\n", reg_908, reg_909);
Patrick Boettchera75763f2006-10-18 08:34:16 -0300262
Olivier Grenie90e12ce2010-09-07 12:50:45 -0300263 reg_908 |= (state->cfg.enable_current_mirror & 1) << 7;
264
Patrick Boettchera75763f2006-10-18 08:34:16 -0300265 dib7000p_write_word(state, 908, reg_908);
266 dib7000p_write_word(state, 909, reg_909);
267}
268
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300269static int dib7000p_set_bandwidth(struct dib7000p_state *state, u32 bw)
Patrick Boettchera75763f2006-10-18 08:34:16 -0300270{
Patrick Boettchera75763f2006-10-18 08:34:16 -0300271 u32 timf;
272
273 // store the current bandwidth for later use
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300274 state->current_bandwidth = bw;
Patrick Boettchera75763f2006-10-18 08:34:16 -0300275
276 if (state->timf == 0) {
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300277 dprintk( "using default timf");
Patrick Boettchera75763f2006-10-18 08:34:16 -0300278 timf = state->cfg.bw->timf;
279 } else {
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300280 dprintk( "using updated timf");
Patrick Boettchera75763f2006-10-18 08:34:16 -0300281 timf = state->timf;
282 }
283
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300284 timf = timf * (bw / 50) / 160;
Patrick Boettchera75763f2006-10-18 08:34:16 -0300285
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300286 dib7000p_write_word(state, 23, (u16) ((timf >> 16) & 0xffff));
287 dib7000p_write_word(state, 24, (u16) ((timf ) & 0xffff));
Patrick Boettchera75763f2006-10-18 08:34:16 -0300288
289 return 0;
290}
291
292static int dib7000p_sad_calib(struct dib7000p_state *state)
293{
294/* internal */
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300295// 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 -0300296 dib7000p_write_word(state, 73, (0 << 1) | (0 << 0));
297 dib7000p_write_word(state, 74, 776); // 0.625*3.3 / 4096
298
299 /* do the calibration */
300 dib7000p_write_word(state, 73, (1 << 0));
301 dib7000p_write_word(state, 73, (0 << 0));
302
303 msleep(1);
304
305 return 0;
306}
307
Patrick Boettcher01373a52007-07-30 12:49:04 -0300308int dib7000p_set_wbd_ref(struct dvb_frontend *demod, u16 value)
309{
310 struct dib7000p_state *state = demod->demodulator_priv;
311 if (value > 4095)
312 value = 4095;
313 state->wbd_ref = value;
314 return dib7000p_write_word(state, 105, (dib7000p_read_word(state, 105) & 0xf000) | value);
315}
316
317EXPORT_SYMBOL(dib7000p_set_wbd_ref);
Patrick Boettchera75763f2006-10-18 08:34:16 -0300318static void dib7000p_reset_pll(struct dib7000p_state *state)
319{
320 struct dibx000_bandwidth_config *bw = &state->cfg.bw[0];
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300321 u16 clk_cfg0;
Patrick Boettchera75763f2006-10-18 08:34:16 -0300322
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300323 /* force PLL bypass */
324 clk_cfg0 = (1 << 15) | ((bw->pll_ratio & 0x3f) << 9) |
325 (bw->modulo << 7) | (bw->ADClkSrc << 6) | (bw->IO_CLK_en_core << 5) |
326 (bw->bypclk_div << 2) | (bw->enable_refdiv << 1) | (0 << 0);
327
328 dib7000p_write_word(state, 900, clk_cfg0);
329
330 /* P_pll_cfg */
Patrick Boettchera75763f2006-10-18 08:34:16 -0300331 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 -0300332 clk_cfg0 = (bw->pll_bypass << 15) | (clk_cfg0 & 0x7fff);
333 dib7000p_write_word(state, 900, clk_cfg0);
Patrick Boettchera75763f2006-10-18 08:34:16 -0300334
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300335 dib7000p_write_word(state, 18, (u16) (((bw->internal*1000) >> 16) & 0xffff));
336 dib7000p_write_word(state, 19, (u16) ( (bw->internal*1000 ) & 0xffff));
337 dib7000p_write_word(state, 21, (u16) ( (bw->ifreq >> 16) & 0xffff));
338 dib7000p_write_word(state, 22, (u16) ( (bw->ifreq ) & 0xffff));
Patrick Boettchera75763f2006-10-18 08:34:16 -0300339
340 dib7000p_write_word(state, 72, bw->sad_cfg);
341}
342
343static int dib7000p_reset_gpio(struct dib7000p_state *st)
344{
345 /* reset the GPIOs */
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300346 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 -0300347
348 dib7000p_write_word(st, 1029, st->gpio_dir);
349 dib7000p_write_word(st, 1030, st->gpio_val);
350
351 /* TODO 1031 is P_gpio_od */
352
353 dib7000p_write_word(st, 1032, st->cfg.gpio_pwm_pos);
354
355 dib7000p_write_word(st, 1037, st->cfg.pwm_freq_div);
356 return 0;
357}
358
Patrick Boettcher01373a52007-07-30 12:49:04 -0300359static int dib7000p_cfg_gpio(struct dib7000p_state *st, u8 num, u8 dir, u8 val)
360{
361 st->gpio_dir = dib7000p_read_word(st, 1029);
362 st->gpio_dir &= ~(1 << num); /* reset the direction bit */
363 st->gpio_dir |= (dir & 0x1) << num; /* set the new direction */
364 dib7000p_write_word(st, 1029, st->gpio_dir);
365
366 st->gpio_val = dib7000p_read_word(st, 1030);
367 st->gpio_val &= ~(1 << num); /* reset the direction bit */
368 st->gpio_val |= (val & 0x01) << num; /* set the new value */
369 dib7000p_write_word(st, 1030, st->gpio_val);
370
371 return 0;
372}
373
374int dib7000p_set_gpio(struct dvb_frontend *demod, u8 num, u8 dir, u8 val)
375{
376 struct dib7000p_state *state = demod->demodulator_priv;
377 return dib7000p_cfg_gpio(state, num, dir, val);
378}
379
380EXPORT_SYMBOL(dib7000p_set_gpio);
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300381static u16 dib7000p_defaults[] =
382
383{
384 // auto search configuration
385 3, 2,
386 0x0004,
387 0x1000,
388 0x0814, /* Equal Lock */
389
390 12, 6,
391 0x001b,
392 0x7740,
393 0x005b,
394 0x8d80,
395 0x01c9,
396 0xc380,
397 0x0000,
398 0x0080,
399 0x0000,
400 0x0090,
401 0x0001,
402 0xd4c0,
403
404 1, 26,
405 0x6680, // P_timf_alpha=6, P_corm_alpha=6, P_corm_thres=128 default: 6,4,26
406
407 /* set ADC level to -16 */
408 11, 79,
409 (1 << 13) - 825 - 117,
410 (1 << 13) - 837 - 117,
411 (1 << 13) - 811 - 117,
412 (1 << 13) - 766 - 117,
413 (1 << 13) - 737 - 117,
414 (1 << 13) - 693 - 117,
415 (1 << 13) - 648 - 117,
416 (1 << 13) - 619 - 117,
417 (1 << 13) - 575 - 117,
418 (1 << 13) - 531 - 117,
419 (1 << 13) - 501 - 117,
420
421 1, 142,
422 0x0410, // P_palf_filter_on=1, P_palf_filter_freeze=0, P_palf_alpha_regul=16
423
424 /* disable power smoothing */
425 8, 145,
426 0,
427 0,
428 0,
429 0,
430 0,
431 0,
432 0,
433 0,
434
435 1, 154,
436 1 << 13, // P_fft_freq_dir=1, P_fft_nb_to_cut=0
437
438 1, 168,
439 0x0ccd, // P_pha3_thres, default 0x3000
440
441// 1, 169,
442// 0x0010, // P_cti_use_cpe=0, P_cti_use_prog=0, P_cti_win_len=16, default: 0x0010
443
444 1, 183,
445 0x200f, // P_cspu_regul=512, P_cspu_win_cut=15, default: 0x2005
446
447 5, 187,
448 0x023d, // P_adp_regul_cnt=573, default: 410
449 0x00a4, // P_adp_noise_cnt=
450 0x00a4, // P_adp_regul_ext
451 0x7ff0, // P_adp_noise_ext
452 0x3ccc, // P_adp_fil
453
454 1, 198,
455 0x800, // P_equal_thres_wgn
456
457 1, 222,
458 0x0010, // P_fec_ber_rs_len=2
459
460 1, 235,
461 0x0062, // P_smo_mode, P_smo_rs_discard, P_smo_fifo_flush, P_smo_pid_parse, P_smo_error_discard
462
463 2, 901,
464 0x0006, // P_clk_cfg1
465 (3 << 10) | (1 << 6), // P_divclksel=3 P_divbitsel=1
466
467 1, 905,
468 0x2c8e, // Tuner IO bank: max drive (14mA) + divout pads max drive
469
470 0,
471};
472
Patrick Boettchera75763f2006-10-18 08:34:16 -0300473static int dib7000p_demod_reset(struct dib7000p_state *state)
474{
475 dib7000p_set_power_mode(state, DIB7000P_POWER_ALL);
476
477 dib7000p_set_adc_state(state, DIBX000_VBG_ENABLE);
478
479 /* restart all parts */
480 dib7000p_write_word(state, 770, 0xffff);
481 dib7000p_write_word(state, 771, 0xffff);
482 dib7000p_write_word(state, 772, 0x001f);
483 dib7000p_write_word(state, 898, 0x0003);
484 /* except i2c, sdio, gpio - control interfaces */
485 dib7000p_write_word(state, 1280, 0x01fc - ((1 << 7) | (1 << 6) | (1 << 5)) );
486
487 dib7000p_write_word(state, 770, 0);
488 dib7000p_write_word(state, 771, 0);
489 dib7000p_write_word(state, 772, 0);
490 dib7000p_write_word(state, 898, 0);
491 dib7000p_write_word(state, 1280, 0);
492
493 /* default */
494 dib7000p_reset_pll(state);
495
496 if (dib7000p_reset_gpio(state) != 0)
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300497 dprintk( "GPIO reset was not successful.");
Patrick Boettchera75763f2006-10-18 08:34:16 -0300498
499 if (dib7000p_set_output_mode(state, OUTMODE_HIGH_Z) != 0)
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300500 dprintk( "OUTPUT_MODE could not be reset.");
Patrick Boettchera75763f2006-10-18 08:34:16 -0300501
502 /* unforce divstr regardless whether i2c enumeration was done or not */
503 dib7000p_write_word(state, 1285, dib7000p_read_word(state, 1285) & ~(1 << 1) );
504
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300505 dib7000p_set_bandwidth(state, 8000);
506
507 dib7000p_set_adc_state(state, DIBX000_SLOW_ADC_ON);
508 dib7000p_sad_calib(state);
509 dib7000p_set_adc_state(state, DIBX000_SLOW_ADC_OFF);
510
511 // P_iqc_alpha_pha, P_iqc_alpha_amp_dcc_alpha, ...
512 if(state->cfg.tuner_is_baseband)
513 dib7000p_write_word(state, 36,0x0755);
514 else
515 dib7000p_write_word(state, 36,0x1f55);
516
517 dib7000p_write_tab(state, dib7000p_defaults);
518
Patrick Boettchera75763f2006-10-18 08:34:16 -0300519 dib7000p_set_power_mode(state, DIB7000P_POWER_INTERFACE_ONLY);
520
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300521
Patrick Boettchera75763f2006-10-18 08:34:16 -0300522 return 0;
523}
524
Patrick Boettchera75763f2006-10-18 08:34:16 -0300525static void dib7000p_pll_clk_cfg(struct dib7000p_state *state)
526{
527 u16 tmp = 0;
528 tmp = dib7000p_read_word(state, 903);
529 dib7000p_write_word(state, 903, (tmp | 0x1)); //pwr-up pll
530 tmp = dib7000p_read_word(state, 900);
531 dib7000p_write_word(state, 900, (tmp & 0x7fff) | (1 << 6)); //use High freq clock
532}
533
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300534static void dib7000p_restart_agc(struct dib7000p_state *state)
Patrick Boettchera75763f2006-10-18 08:34:16 -0300535{
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300536 // P_restart_iqc & P_restart_agc
537 dib7000p_write_word(state, 770, (1 << 11) | (1 << 9));
538 dib7000p_write_word(state, 770, 0x0000);
Patrick Boettchera75763f2006-10-18 08:34:16 -0300539}
540
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300541static int dib7000p_update_lna(struct dib7000p_state *state)
Patrick Boettchera75763f2006-10-18 08:34:16 -0300542{
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300543 u16 dyn_gain;
544
545 // when there is no LNA to program return immediatly
546 if (state->cfg.update_lna) {
Patrick Boettcher01373a52007-07-30 12:49:04 -0300547 // read dyn_gain here (because it is demod-dependent and not fe)
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300548 dyn_gain = dib7000p_read_word(state, 394);
549 if (state->cfg.update_lna(&state->demod,dyn_gain)) { // LNA has changed
550 dib7000p_restart_agc(state);
551 return 1;
552 }
553 }
554
555 return 0;
556}
557
558static int dib7000p_set_agc_config(struct dib7000p_state *state, u8 band)
559{
560 struct dibx000_agc_config *agc = NULL;
561 int i;
562 if (state->current_band == band && state->current_agc != NULL)
563 return 0;
564 state->current_band = band;
565
566 for (i = 0; i < state->cfg.agc_config_count; i++)
567 if (state->cfg.agc[i].band_caps & band) {
568 agc = &state->cfg.agc[i];
569 break;
570 }
571
572 if (agc == NULL) {
573 dprintk( "no valid AGC configuration found for band 0x%02x",band);
574 return -EINVAL;
575 }
576
577 state->current_agc = agc;
578
579 /* AGC */
580 dib7000p_write_word(state, 75 , agc->setup );
581 dib7000p_write_word(state, 76 , agc->inv_gain );
582 dib7000p_write_word(state, 77 , agc->time_stabiliz );
583 dib7000p_write_word(state, 100, (agc->alpha_level << 12) | agc->thlock);
584
585 // Demod AGC loop configuration
586 dib7000p_write_word(state, 101, (agc->alpha_mant << 5) | agc->alpha_exp);
587 dib7000p_write_word(state, 102, (agc->beta_mant << 6) | agc->beta_exp);
588
589 /* AGC continued */
590 dprintk( "WBD: ref: %d, sel: %d, active: %d, alpha: %d",
591 state->wbd_ref != 0 ? state->wbd_ref : agc->wbd_ref, agc->wbd_sel, !agc->perform_agc_softsplit, agc->wbd_sel);
592
593 if (state->wbd_ref != 0)
594 dib7000p_write_word(state, 105, (agc->wbd_inv << 12) | state->wbd_ref);
595 else
596 dib7000p_write_word(state, 105, (agc->wbd_inv << 12) | agc->wbd_ref);
597
598 dib7000p_write_word(state, 106, (agc->wbd_sel << 13) | (agc->wbd_alpha << 9) | (agc->perform_agc_softsplit << 8));
599
600 dib7000p_write_word(state, 107, agc->agc1_max);
601 dib7000p_write_word(state, 108, agc->agc1_min);
602 dib7000p_write_word(state, 109, agc->agc2_max);
603 dib7000p_write_word(state, 110, agc->agc2_min);
604 dib7000p_write_word(state, 111, (agc->agc1_pt1 << 8) | agc->agc1_pt2);
605 dib7000p_write_word(state, 112, agc->agc1_pt3);
606 dib7000p_write_word(state, 113, (agc->agc1_slope1 << 8) | agc->agc1_slope2);
607 dib7000p_write_word(state, 114, (agc->agc2_pt1 << 8) | agc->agc2_pt2);
608 dib7000p_write_word(state, 115, (agc->agc2_slope1 << 8) | agc->agc2_slope2);
609 return 0;
610}
611
612static int dib7000p_agc_startup(struct dvb_frontend *demod, struct dvb_frontend_parameters *ch)
613{
614 struct dib7000p_state *state = demod->demodulator_priv;
615 int ret = -1;
616 u8 *agc_state = &state->agc_state;
617 u8 agc_split;
618
619 switch (state->agc_state) {
620 case 0:
621 // set power-up level: interf+analog+AGC
622 dib7000p_set_power_mode(state, DIB7000P_POWER_ALL);
623 dib7000p_set_adc_state(state, DIBX000_ADC_ON);
624 dib7000p_pll_clk_cfg(state);
625
626 if (dib7000p_set_agc_config(state, BAND_OF_FREQUENCY(ch->frequency/1000)) != 0)
627 return -1;
628
629 ret = 7;
630 (*agc_state)++;
631 break;
632
633 case 1:
634 // AGC initialization
635 if (state->cfg.agc_control)
636 state->cfg.agc_control(&state->demod, 1);
637
638 dib7000p_write_word(state, 78, 32768);
639 if (!state->current_agc->perform_agc_softsplit) {
640 /* we are using the wbd - so slow AGC startup */
641 /* force 0 split on WBD and restart AGC */
642 dib7000p_write_word(state, 106, (state->current_agc->wbd_sel << 13) | (state->current_agc->wbd_alpha << 9) | (1 << 8));
643 (*agc_state)++;
644 ret = 5;
645 } else {
646 /* default AGC startup */
647 (*agc_state) = 4;
648 /* wait AGC rough lock time */
649 ret = 7;
650 }
651
652 dib7000p_restart_agc(state);
653 break;
654
655 case 2: /* fast split search path after 5sec */
656 dib7000p_write_word(state, 75, state->current_agc->setup | (1 << 4)); /* freeze AGC loop */
657 dib7000p_write_word(state, 106, (state->current_agc->wbd_sel << 13) | (2 << 9) | (0 << 8)); /* fast split search 0.25kHz */
658 (*agc_state)++;
659 ret = 14;
660 break;
661
662 case 3: /* split search ended */
Patrick Boettcher01373a52007-07-30 12:49:04 -0300663 agc_split = (u8)dib7000p_read_word(state, 396); /* store the split value for the next time */
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300664 dib7000p_write_word(state, 78, dib7000p_read_word(state, 394)); /* set AGC gain start value */
665
666 dib7000p_write_word(state, 75, state->current_agc->setup); /* std AGC loop */
667 dib7000p_write_word(state, 106, (state->current_agc->wbd_sel << 13) | (state->current_agc->wbd_alpha << 9) | agc_split); /* standard split search */
668
669 dib7000p_restart_agc(state);
670
671 dprintk( "SPLIT %p: %hd", demod, agc_split);
672
673 (*agc_state)++;
674 ret = 5;
675 break;
676
677 case 4: /* LNA startup */
678 // wait AGC accurate lock time
679 ret = 7;
680
681 if (dib7000p_update_lna(state))
682 // wait only AGC rough lock time
683 ret = 5;
684 else // nothing was done, go to the next state
685 (*agc_state)++;
686 break;
687
688 case 5:
689 if (state->cfg.agc_control)
690 state->cfg.agc_control(&state->demod, 0);
691 (*agc_state)++;
692 break;
693 default:
694 break;
695 }
696 return ret;
697}
698
699static void dib7000p_update_timf(struct dib7000p_state *state)
700{
701 u32 timf = (dib7000p_read_word(state, 427) << 16) | dib7000p_read_word(state, 428);
702 state->timf = timf * 160 / (state->current_bandwidth / 50);
703 dib7000p_write_word(state, 23, (u16) (timf >> 16));
704 dib7000p_write_word(state, 24, (u16) (timf & 0xffff));
705 dprintk( "updated timf_frequency: %d (default: %d)",state->timf, state->cfg.bw->timf);
706
707}
708
709static void dib7000p_set_channel(struct dib7000p_state *state, struct dvb_frontend_parameters *ch, u8 seq)
710{
711 u16 value, est[4];
712
713 dib7000p_set_bandwidth(state, BANDWIDTH_TO_KHZ(ch->u.ofdm.bandwidth));
Patrick Boettchera75763f2006-10-18 08:34:16 -0300714
715 /* nfft, guard, qam, alpha */
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300716 value = 0;
717 switch (ch->u.ofdm.transmission_mode) {
718 case TRANSMISSION_MODE_2K: value |= (0 << 7); break;
719 case /* 4K MODE */ 255: value |= (2 << 7); break;
720 default:
721 case TRANSMISSION_MODE_8K: value |= (1 << 7); break;
722 }
723 switch (ch->u.ofdm.guard_interval) {
724 case GUARD_INTERVAL_1_32: value |= (0 << 5); break;
725 case GUARD_INTERVAL_1_16: value |= (1 << 5); break;
726 case GUARD_INTERVAL_1_4: value |= (3 << 5); break;
727 default:
728 case GUARD_INTERVAL_1_8: value |= (2 << 5); break;
729 }
730 switch (ch->u.ofdm.constellation) {
731 case QPSK: value |= (0 << 3); break;
732 case QAM_16: value |= (1 << 3); break;
733 default:
734 case QAM_64: value |= (2 << 3); break;
735 }
736 switch (HIERARCHY_1) {
737 case HIERARCHY_2: value |= 2; break;
738 case HIERARCHY_4: value |= 4; break;
739 default:
740 case HIERARCHY_1: value |= 1; break;
741 }
742 dib7000p_write_word(state, 0, value);
Patrick Boettchera75763f2006-10-18 08:34:16 -0300743 dib7000p_write_word(state, 5, (seq << 4) | 1); /* do not force tps, search list 0 */
744
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300745 /* P_dintl_native, P_dintlv_inv, P_hrch, P_code_rate, P_select_hp */
746 value = 0;
747 if (1 != 0)
748 value |= (1 << 6);
749 if (ch->u.ofdm.hierarchy_information == 1)
750 value |= (1 << 4);
751 if (1 == 1)
752 value |= 1;
753 switch ((ch->u.ofdm.hierarchy_information == 0 || 1 == 1) ? ch->u.ofdm.code_rate_HP : ch->u.ofdm.code_rate_LP) {
754 case FEC_2_3: value |= (2 << 1); break;
755 case FEC_3_4: value |= (3 << 1); break;
756 case FEC_5_6: value |= (5 << 1); break;
757 case FEC_7_8: value |= (7 << 1); break;
758 default:
759 case FEC_1_2: value |= (1 << 1); break;
760 }
761 dib7000p_write_word(state, 208, value);
762
763 /* offset loop parameters */
764 dib7000p_write_word(state, 26, 0x6680); // timf(6xxx)
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300765 dib7000p_write_word(state, 32, 0x0003); // pha_off_max(xxx3)
Matt Doran8f6956c2007-07-31 07:09:30 -0300766 dib7000p_write_word(state, 29, 0x1273); // isi
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300767 dib7000p_write_word(state, 33, 0x0005); // sfreq(xxx5)
Patrick Boettchera75763f2006-10-18 08:34:16 -0300768
769 /* P_dvsy_sync_wait */
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300770 switch (ch->u.ofdm.transmission_mode) {
771 case TRANSMISSION_MODE_8K: value = 256; break;
772 case /* 4K MODE */ 255: value = 128; break;
773 case TRANSMISSION_MODE_2K:
774 default: value = 64; break;
Patrick Boettchera75763f2006-10-18 08:34:16 -0300775 }
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300776 switch (ch->u.ofdm.guard_interval) {
777 case GUARD_INTERVAL_1_16: value *= 2; break;
778 case GUARD_INTERVAL_1_8: value *= 4; break;
779 case GUARD_INTERVAL_1_4: value *= 8; break;
780 default:
781 case GUARD_INTERVAL_1_32: value *= 1; break;
782 }
783 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 -0300784
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300785 /* deactive the possibility of diversity reception if extended interleaver */
786 state->div_force_off = !1 && ch->u.ofdm.transmission_mode != TRANSMISSION_MODE_8K;
787 dib7000p_set_diversity_in(&state->demod, state->div_state);
Patrick Boettchera75763f2006-10-18 08:34:16 -0300788
789 /* channel estimation fine configuration */
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300790 switch (ch->u.ofdm.constellation) {
791 case QAM_64:
Patrick Boettchera75763f2006-10-18 08:34:16 -0300792 est[0] = 0x0148; /* P_adp_regul_cnt 0.04 */
793 est[1] = 0xfff0; /* P_adp_noise_cnt -0.002 */
794 est[2] = 0x00a4; /* P_adp_regul_ext 0.02 */
795 est[3] = 0xfff8; /* P_adp_noise_ext -0.001 */
796 break;
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300797 case QAM_16:
Patrick Boettchera75763f2006-10-18 08:34:16 -0300798 est[0] = 0x023d; /* P_adp_regul_cnt 0.07 */
799 est[1] = 0xffdf; /* P_adp_noise_cnt -0.004 */
800 est[2] = 0x00a4; /* P_adp_regul_ext 0.02 */
801 est[3] = 0xfff0; /* P_adp_noise_ext -0.002 */
802 break;
803 default:
804 est[0] = 0x099a; /* P_adp_regul_cnt 0.3 */
805 est[1] = 0xffae; /* P_adp_noise_cnt -0.01 */
806 est[2] = 0x0333; /* P_adp_regul_ext 0.1 */
807 est[3] = 0xfff8; /* P_adp_noise_ext -0.002 */
808 break;
809 }
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300810 for (value = 0; value < 4; value++)
811 dib7000p_write_word(state, 187 + value, est[value]);
Patrick Boettchera75763f2006-10-18 08:34:16 -0300812}
813
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300814static int dib7000p_autosearch_start(struct dvb_frontend *demod, struct dvb_frontend_parameters *ch)
Patrick Boettchera75763f2006-10-18 08:34:16 -0300815{
816 struct dib7000p_state *state = demod->demodulator_priv;
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300817 struct dvb_frontend_parameters schan;
818 u32 value, factor;
Patrick Boettchera75763f2006-10-18 08:34:16 -0300819
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300820 schan = *ch;
821 schan.u.ofdm.constellation = QAM_64;
822 schan.u.ofdm.guard_interval = GUARD_INTERVAL_1_32;
823 schan.u.ofdm.transmission_mode = TRANSMISSION_MODE_8K;
824 schan.u.ofdm.code_rate_HP = FEC_2_3;
825 schan.u.ofdm.code_rate_LP = FEC_3_4;
826 schan.u.ofdm.hierarchy_information = 0;
Patrick Boettchera75763f2006-10-18 08:34:16 -0300827
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300828 dib7000p_set_channel(state, &schan, 7);
829
830 factor = BANDWIDTH_TO_KHZ(ch->u.ofdm.bandwidth);
831 if (factor >= 5000)
832 factor = 1;
833 else
834 factor = 6;
Patrick Boettchera75763f2006-10-18 08:34:16 -0300835
836 // always use the setting for 8MHz here lock_time for 7,6 MHz are longer
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300837 value = 30 * state->cfg.bw->internal * factor;
Patrick Boettchera75763f2006-10-18 08:34:16 -0300838 dib7000p_write_word(state, 6, (u16) ((value >> 16) & 0xffff)); // lock0 wait time
839 dib7000p_write_word(state, 7, (u16) (value & 0xffff)); // lock0 wait time
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300840 value = 100 * state->cfg.bw->internal * factor;
Patrick Boettchera75763f2006-10-18 08:34:16 -0300841 dib7000p_write_word(state, 8, (u16) ((value >> 16) & 0xffff)); // lock1 wait time
842 dib7000p_write_word(state, 9, (u16) (value & 0xffff)); // lock1 wait time
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300843 value = 500 * state->cfg.bw->internal * factor;
Patrick Boettchera75763f2006-10-18 08:34:16 -0300844 dib7000p_write_word(state, 10, (u16) ((value >> 16) & 0xffff)); // lock2 wait time
845 dib7000p_write_word(state, 11, (u16) (value & 0xffff)); // lock2 wait time
846
847 value = dib7000p_read_word(state, 0);
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300848 dib7000p_write_word(state, 0, (u16) ((1 << 9) | value));
Patrick Boettchera75763f2006-10-18 08:34:16 -0300849 dib7000p_read_word(state, 1284);
850 dib7000p_write_word(state, 0, (u16) value);
851
852 return 0;
853}
854
855static int dib7000p_autosearch_is_irq(struct dvb_frontend *demod)
856{
857 struct dib7000p_state *state = demod->demodulator_priv;
858 u16 irq_pending = dib7000p_read_word(state, 1284);
859
860 if (irq_pending & 0x1) // failed
861 return 1;
862
863 if (irq_pending & 0x2) // succeeded
864 return 2;
865
866 return 0; // still pending
867}
868
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300869static void dib7000p_spur_protect(struct dib7000p_state *state, u32 rf_khz, u32 bw)
870{
871 static s16 notch[]={16143, 14402, 12238, 9713, 6902, 3888, 759, -2392};
872 static u8 sine [] ={0, 2, 3, 5, 6, 8, 9, 11, 13, 14, 16, 17, 19, 20, 22,
873 24, 25, 27, 28, 30, 31, 33, 34, 36, 38, 39, 41, 42, 44, 45, 47, 48, 50, 51,
874 53, 55, 56, 58, 59, 61, 62, 64, 65, 67, 68, 70, 71, 73, 74, 76, 77, 79, 80,
875 82, 83, 85, 86, 88, 89, 91, 92, 94, 95, 97, 98, 99, 101, 102, 104, 105,
876 107, 108, 109, 111, 112, 114, 115, 117, 118, 119, 121, 122, 123, 125, 126,
877 128, 129, 130, 132, 133, 134, 136, 137, 138, 140, 141, 142, 144, 145, 146,
878 147, 149, 150, 151, 152, 154, 155, 156, 157, 159, 160, 161, 162, 164, 165,
879 166, 167, 168, 170, 171, 172, 173, 174, 175, 177, 178, 179, 180, 181, 182,
880 183, 184, 185, 186, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198,
881 199, 200, 201, 202, 203, 204, 205, 206, 207, 207, 208, 209, 210, 211, 212,
882 213, 214, 215, 215, 216, 217, 218, 219, 220, 220, 221, 222, 223, 224, 224,
883 225, 226, 227, 227, 228, 229, 229, 230, 231, 231, 232, 233, 233, 234, 235,
884 235, 236, 237, 237, 238, 238, 239, 239, 240, 241, 241, 242, 242, 243, 243,
885 244, 244, 245, 245, 245, 246, 246, 247, 247, 248, 248, 248, 249, 249, 249,
886 250, 250, 250, 251, 251, 251, 252, 252, 252, 252, 253, 253, 253, 253, 254,
887 254, 254, 254, 254, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
888 255, 255, 255, 255, 255, 255};
889
890 u32 xtal = state->cfg.bw->xtal_hz / 1000;
Julia Lawall75b697f2009-08-01 16:48:41 -0300891 int f_rel = DIV_ROUND_CLOSEST(rf_khz, xtal) * xtal - rf_khz;
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300892 int k;
893 int coef_re[8],coef_im[8];
894 int bw_khz = bw;
895 u32 pha;
896
897 dprintk( "relative position of the Spur: %dk (RF: %dk, XTAL: %dk)", f_rel, rf_khz, xtal);
898
899
900 if (f_rel < -bw_khz/2 || f_rel > bw_khz/2)
901 return;
902
903 bw_khz /= 100;
904
905 dib7000p_write_word(state, 142 ,0x0610);
906
907 for (k = 0; k < 8; k++) {
908 pha = ((f_rel * (k+1) * 112 * 80/bw_khz) /1000) & 0x3ff;
909
910 if (pha==0) {
911 coef_re[k] = 256;
912 coef_im[k] = 0;
913 } else if(pha < 256) {
914 coef_re[k] = sine[256-(pha&0xff)];
915 coef_im[k] = sine[pha&0xff];
916 } else if (pha == 256) {
917 coef_re[k] = 0;
918 coef_im[k] = 256;
919 } else if (pha < 512) {
920 coef_re[k] = -sine[pha&0xff];
921 coef_im[k] = sine[256 - (pha&0xff)];
922 } else if (pha == 512) {
923 coef_re[k] = -256;
924 coef_im[k] = 0;
925 } else if (pha < 768) {
926 coef_re[k] = -sine[256-(pha&0xff)];
927 coef_im[k] = -sine[pha&0xff];
928 } else if (pha == 768) {
929 coef_re[k] = 0;
930 coef_im[k] = -256;
931 } else {
932 coef_re[k] = sine[pha&0xff];
933 coef_im[k] = -sine[256 - (pha&0xff)];
934 }
935
936 coef_re[k] *= notch[k];
937 coef_re[k] += (1<<14);
938 if (coef_re[k] >= (1<<24))
939 coef_re[k] = (1<<24) - 1;
940 coef_re[k] /= (1<<15);
941
942 coef_im[k] *= notch[k];
943 coef_im[k] += (1<<14);
944 if (coef_im[k] >= (1<<24))
945 coef_im[k] = (1<<24)-1;
946 coef_im[k] /= (1<<15);
947
948 dprintk( "PALF COEF: %d re: %d im: %d", k, coef_re[k], coef_im[k]);
949
950 dib7000p_write_word(state, 143, (0 << 14) | (k << 10) | (coef_re[k] & 0x3ff));
951 dib7000p_write_word(state, 144, coef_im[k] & 0x3ff);
952 dib7000p_write_word(state, 143, (1 << 14) | (k << 10) | (coef_re[k] & 0x3ff));
953 }
954 dib7000p_write_word(state,143 ,0);
955}
956
957static int dib7000p_tune(struct dvb_frontend *demod, struct dvb_frontend_parameters *ch)
Patrick Boettchera75763f2006-10-18 08:34:16 -0300958{
959 struct dib7000p_state *state = demod->demodulator_priv;
960 u16 tmp = 0;
961
962 if (ch != NULL)
963 dib7000p_set_channel(state, ch, 0);
964 else
965 return -EINVAL;
966
967 // restart demod
968 dib7000p_write_word(state, 770, 0x4000);
969 dib7000p_write_word(state, 770, 0x0000);
970 msleep(45);
971
972 /* 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 -0300973 tmp = (0 << 14) | (4 << 10) | (0 << 9) | (3 << 5) | (1 << 4) | (0x3);
974 if (state->sfn_workaround_active) {
975 dprintk( "SFN workaround is active");
976 tmp |= (1 << 9);
977 dib7000p_write_word(state, 166, 0x4000); // P_pha3_force_pha_shift
978 } else {
979 dib7000p_write_word(state, 166, 0x0000); // P_pha3_force_pha_shift
980 }
981 dib7000p_write_word(state, 29, tmp);
Patrick Boettchera75763f2006-10-18 08:34:16 -0300982
983 // never achieved a lock with that bandwidth so far - wait for osc-freq to update
984 if (state->timf == 0)
985 msleep(200);
986
987 /* offset loop parameters */
988
989 /* P_timf_alpha, P_corm_alpha=6, P_corm_thres=0x80 */
990 tmp = (6 << 8) | 0x80;
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300991 switch (ch->u.ofdm.transmission_mode) {
992 case TRANSMISSION_MODE_2K: tmp |= (7 << 12); break;
993 case /* 4K MODE */ 255: tmp |= (8 << 12); break;
994 default:
995 case TRANSMISSION_MODE_8K: tmp |= (9 << 12); break;
Patrick Boettchera75763f2006-10-18 08:34:16 -0300996 }
997 dib7000p_write_word(state, 26, tmp); /* timf_a(6xxx) */
998
999 /* P_ctrl_freeze_pha_shift=0, P_ctrl_pha_off_max */
1000 tmp = (0 << 4);
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001001 switch (ch->u.ofdm.transmission_mode) {
1002 case TRANSMISSION_MODE_2K: tmp |= 0x6; break;
1003 case /* 4K MODE */ 255: tmp |= 0x7; break;
1004 default:
1005 case TRANSMISSION_MODE_8K: tmp |= 0x8; break;
Patrick Boettchera75763f2006-10-18 08:34:16 -03001006 }
1007 dib7000p_write_word(state, 32, tmp);
1008
1009 /* P_ctrl_sfreq_inh=0, P_ctrl_sfreq_step */
1010 tmp = (0 << 4);
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001011 switch (ch->u.ofdm.transmission_mode) {
1012 case TRANSMISSION_MODE_2K: tmp |= 0x6; break;
1013 case /* 4K MODE */ 255: tmp |= 0x7; break;
1014 default:
1015 case TRANSMISSION_MODE_8K: tmp |= 0x8; break;
Patrick Boettchera75763f2006-10-18 08:34:16 -03001016 }
1017 dib7000p_write_word(state, 33, tmp);
1018
1019 tmp = dib7000p_read_word(state,509);
1020 if (!((tmp >> 6) & 0x1)) {
1021 /* restart the fec */
1022 tmp = dib7000p_read_word(state,771);
1023 dib7000p_write_word(state, 771, tmp | (1 << 1));
1024 dib7000p_write_word(state, 771, tmp);
1025 msleep(10);
1026 tmp = dib7000p_read_word(state,509);
1027 }
1028
1029 // we achieved a lock - it's time to update the osc freq
1030 if ((tmp >> 6) & 0x1)
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001031 dib7000p_update_timf(state);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001032
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001033 if (state->cfg.spur_protect)
1034 dib7000p_spur_protect(state, ch->frequency/1000, BANDWIDTH_TO_KHZ(ch->u.ofdm.bandwidth));
1035
1036 dib7000p_set_bandwidth(state, BANDWIDTH_TO_KHZ(ch->u.ofdm.bandwidth));
Patrick Boettchera75763f2006-10-18 08:34:16 -03001037 return 0;
1038}
1039
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001040static int dib7000p_wakeup(struct dvb_frontend *demod)
Patrick Boettchera75763f2006-10-18 08:34:16 -03001041{
Patrick Boettchera75763f2006-10-18 08:34:16 -03001042 struct dib7000p_state *state = demod->demodulator_priv;
Patrick Boettchera75763f2006-10-18 08:34:16 -03001043 dib7000p_set_power_mode(state, DIB7000P_POWER_ALL);
1044 dib7000p_set_adc_state(state, DIBX000_SLOW_ADC_ON);
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001045 return 0;
Patrick Boettchera75763f2006-10-18 08:34:16 -03001046}
1047
1048static int dib7000p_sleep(struct dvb_frontend *demod)
1049{
1050 struct dib7000p_state *state = demod->demodulator_priv;
1051 return dib7000p_set_output_mode(state, OUTMODE_HIGH_Z) | dib7000p_set_power_mode(state, DIB7000P_POWER_INTERFACE_ONLY);
1052}
1053
1054static int dib7000p_identify(struct dib7000p_state *st)
1055{
1056 u16 value;
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001057 dprintk( "checking demod on I2C address: %d (%x)",
Patrick Boettchera75763f2006-10-18 08:34:16 -03001058 st->i2c_addr, st->i2c_addr);
1059
1060 if ((value = dib7000p_read_word(st, 768)) != 0x01b3) {
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001061 dprintk( "wrong Vendor ID (read=0x%x)",value);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001062 return -EREMOTEIO;
1063 }
1064
1065 if ((value = dib7000p_read_word(st, 769)) != 0x4000) {
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001066 dprintk( "wrong Device ID (%x)",value);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001067 return -EREMOTEIO;
1068 }
1069
1070 return 0;
1071}
1072
1073
1074static int dib7000p_get_frontend(struct dvb_frontend* fe,
1075 struct dvb_frontend_parameters *fep)
1076{
1077 struct dib7000p_state *state = fe->demodulator_priv;
1078 u16 tps = dib7000p_read_word(state,463);
1079
1080 fep->inversion = INVERSION_AUTO;
1081
Patrick Boettcher904a82e2008-01-25 07:31:58 -03001082 fep->u.ofdm.bandwidth = BANDWIDTH_TO_INDEX(state->current_bandwidth);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001083
1084 switch ((tps >> 8) & 0x3) {
1085 case 0: fep->u.ofdm.transmission_mode = TRANSMISSION_MODE_2K; break;
1086 case 1: fep->u.ofdm.transmission_mode = TRANSMISSION_MODE_8K; break;
1087 /* case 2: fep->u.ofdm.transmission_mode = TRANSMISSION_MODE_4K; break; */
1088 }
1089
1090 switch (tps & 0x3) {
1091 case 0: fep->u.ofdm.guard_interval = GUARD_INTERVAL_1_32; break;
1092 case 1: fep->u.ofdm.guard_interval = GUARD_INTERVAL_1_16; break;
1093 case 2: fep->u.ofdm.guard_interval = GUARD_INTERVAL_1_8; break;
1094 case 3: fep->u.ofdm.guard_interval = GUARD_INTERVAL_1_4; break;
1095 }
1096
1097 switch ((tps >> 14) & 0x3) {
1098 case 0: fep->u.ofdm.constellation = QPSK; break;
1099 case 1: fep->u.ofdm.constellation = QAM_16; break;
1100 case 2:
1101 default: fep->u.ofdm.constellation = QAM_64; break;
1102 }
1103
1104 /* as long as the frontend_param structure is fixed for hierarchical transmission I refuse to use it */
1105 /* (tps >> 13) & 0x1 == hrch is used, (tps >> 10) & 0x7 == alpha */
1106
1107 fep->u.ofdm.hierarchy_information = HIERARCHY_NONE;
1108 switch ((tps >> 5) & 0x7) {
1109 case 1: fep->u.ofdm.code_rate_HP = FEC_1_2; break;
1110 case 2: fep->u.ofdm.code_rate_HP = FEC_2_3; break;
1111 case 3: fep->u.ofdm.code_rate_HP = FEC_3_4; break;
1112 case 5: fep->u.ofdm.code_rate_HP = FEC_5_6; break;
1113 case 7:
1114 default: fep->u.ofdm.code_rate_HP = FEC_7_8; break;
1115
1116 }
1117
1118 switch ((tps >> 2) & 0x7) {
1119 case 1: fep->u.ofdm.code_rate_LP = FEC_1_2; break;
1120 case 2: fep->u.ofdm.code_rate_LP = FEC_2_3; break;
1121 case 3: fep->u.ofdm.code_rate_LP = FEC_3_4; break;
1122 case 5: fep->u.ofdm.code_rate_LP = FEC_5_6; break;
1123 case 7:
1124 default: fep->u.ofdm.code_rate_LP = FEC_7_8; break;
1125 }
1126
1127 /* native interleaver: (dib7000p_read_word(state, 464) >> 5) & 0x1 */
1128
1129 return 0;
1130}
1131
1132static int dib7000p_set_frontend(struct dvb_frontend* fe,
1133 struct dvb_frontend_parameters *fep)
1134{
1135 struct dib7000p_state *state = fe->demodulator_priv;
Soeren Moch853ea132008-01-25 06:27:06 -03001136 int time, ret;
Patrick Boettchera75763f2006-10-18 08:34:16 -03001137
Soeren Moch853ea132008-01-25 06:27:06 -03001138 dib7000p_set_output_mode(state, OUTMODE_HIGH_Z);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001139
Patrick Boettcher904a82e2008-01-25 07:31:58 -03001140 /* maybe the parameter has been changed */
Matt Doran8f6956c2007-07-31 07:09:30 -03001141 state->sfn_workaround_active = buggy_sfn_workaround;
1142
Patrick Boettchera75763f2006-10-18 08:34:16 -03001143 if (fe->ops.tuner_ops.set_params)
1144 fe->ops.tuner_ops.set_params(fe, fep);
1145
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001146 /* start up the AGC */
1147 state->agc_state = 0;
1148 do {
1149 time = dib7000p_agc_startup(fe, fep);
1150 if (time != -1)
1151 msleep(time);
1152 } while (time != -1);
1153
Patrick Boettchera75763f2006-10-18 08:34:16 -03001154 if (fep->u.ofdm.transmission_mode == TRANSMISSION_MODE_AUTO ||
1155 fep->u.ofdm.guard_interval == GUARD_INTERVAL_AUTO ||
1156 fep->u.ofdm.constellation == QAM_AUTO ||
1157 fep->u.ofdm.code_rate_HP == FEC_AUTO) {
1158 int i = 800, found;
1159
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001160 dib7000p_autosearch_start(fe, fep);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001161 do {
1162 msleep(1);
1163 found = dib7000p_autosearch_is_irq(fe);
1164 } while (found == 0 && i--);
1165
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001166 dprintk("autosearch returns: %d",found);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001167 if (found == 0 || found == 1)
1168 return 0; // no channel found
1169
1170 dib7000p_get_frontend(fe, fep);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001171 }
1172
Soeren Moch853ea132008-01-25 06:27:06 -03001173 ret = dib7000p_tune(fe, fep);
1174
Patrick Boettchera75763f2006-10-18 08:34:16 -03001175 /* make this a config parameter */
Steven Totha38d6e32008-04-22 15:37:01 -03001176 dib7000p_set_output_mode(state, state->cfg.output_mode);
Soeren Moch853ea132008-01-25 06:27:06 -03001177 return ret;
Patrick Boettchera75763f2006-10-18 08:34:16 -03001178}
1179
1180static int dib7000p_read_status(struct dvb_frontend *fe, fe_status_t *stat)
1181{
1182 struct dib7000p_state *state = fe->demodulator_priv;
1183 u16 lock = dib7000p_read_word(state, 509);
1184
1185 *stat = 0;
1186
1187 if (lock & 0x8000)
1188 *stat |= FE_HAS_SIGNAL;
1189 if (lock & 0x3000)
1190 *stat |= FE_HAS_CARRIER;
1191 if (lock & 0x0100)
1192 *stat |= FE_HAS_VITERBI;
1193 if (lock & 0x0010)
1194 *stat |= FE_HAS_SYNC;
Olivier Grenieeac1fe12009-09-23 13:41:27 -03001195 if ((lock & 0x0038) == 0x38)
Patrick Boettchera75763f2006-10-18 08:34:16 -03001196 *stat |= FE_HAS_LOCK;
1197
1198 return 0;
1199}
1200
1201static int dib7000p_read_ber(struct dvb_frontend *fe, u32 *ber)
1202{
1203 struct dib7000p_state *state = fe->demodulator_priv;
1204 *ber = (dib7000p_read_word(state, 500) << 16) | dib7000p_read_word(state, 501);
1205 return 0;
1206}
1207
1208static int dib7000p_read_unc_blocks(struct dvb_frontend *fe, u32 *unc)
1209{
1210 struct dib7000p_state *state = fe->demodulator_priv;
1211 *unc = dib7000p_read_word(state, 506);
1212 return 0;
1213}
1214
1215static int dib7000p_read_signal_strength(struct dvb_frontend *fe, u16 *strength)
1216{
1217 struct dib7000p_state *state = fe->demodulator_priv;
1218 u16 val = dib7000p_read_word(state, 394);
1219 *strength = 65535 - val;
1220 return 0;
1221}
1222
1223static int dib7000p_read_snr(struct dvb_frontend* fe, u16 *snr)
1224{
Olivier Grenieef801962009-09-15 06:46:52 -03001225 struct dib7000p_state *state = fe->demodulator_priv;
1226 u16 val;
1227 s32 signal_mant, signal_exp, noise_mant, noise_exp;
1228 u32 result = 0;
1229
1230 val = dib7000p_read_word(state, 479);
1231 noise_mant = (val >> 4) & 0xff;
1232 noise_exp = ((val & 0xf) << 2);
1233 val = dib7000p_read_word(state, 480);
1234 noise_exp += ((val >> 14) & 0x3);
1235 if ((noise_exp & 0x20) != 0)
1236 noise_exp -= 0x40;
1237
1238 signal_mant = (val >> 6) & 0xFF;
1239 signal_exp = (val & 0x3F);
1240 if ((signal_exp & 0x20) != 0)
1241 signal_exp -= 0x40;
1242
1243 if (signal_mant != 0)
1244 result = intlog10(2) * 10 * signal_exp + 10 *
1245 intlog10(signal_mant);
1246 else
1247 result = intlog10(2) * 10 * signal_exp - 100;
1248
1249 if (noise_mant != 0)
1250 result -= intlog10(2) * 10 * noise_exp + 10 *
1251 intlog10(noise_mant);
1252 else
1253 result -= intlog10(2) * 10 * noise_exp - 100;
1254
1255 *snr = result / ((1 << 24) / 10);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001256 return 0;
1257}
1258
1259static int dib7000p_fe_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings *tune)
1260{
1261 tune->min_delay_ms = 1000;
1262 return 0;
1263}
1264
1265static void dib7000p_release(struct dvb_frontend *demod)
1266{
1267 struct dib7000p_state *st = demod->demodulator_priv;
1268 dibx000_exit_i2c_master(&st->i2c_master);
1269 kfree(st);
1270}
1271
1272int dib7000pc_detection(struct i2c_adapter *i2c_adap)
1273{
1274 u8 tx[2], rx[2];
1275 struct i2c_msg msg[2] = {
1276 { .addr = 18 >> 1, .flags = 0, .buf = tx, .len = 2 },
1277 { .addr = 18 >> 1, .flags = I2C_M_RD, .buf = rx, .len = 2 },
1278 };
1279
1280 tx[0] = 0x03;
1281 tx[1] = 0x00;
1282
1283 if (i2c_transfer(i2c_adap, msg, 2) == 2)
1284 if (rx[0] == 0x01 && rx[1] == 0xb3) {
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001285 dprintk("-D- DiB7000PC detected");
Patrick Boettchera75763f2006-10-18 08:34:16 -03001286 return 1;
1287 }
1288
1289 msg[0].addr = msg[1].addr = 0x40;
1290
1291 if (i2c_transfer(i2c_adap, msg, 2) == 2)
1292 if (rx[0] == 0x01 && rx[1] == 0xb3) {
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001293 dprintk("-D- DiB7000PC detected");
Patrick Boettchera75763f2006-10-18 08:34:16 -03001294 return 1;
1295 }
1296
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001297 dprintk("-D- DiB7000PC not detected");
Patrick Boettchera75763f2006-10-18 08:34:16 -03001298 return 0;
1299}
1300EXPORT_SYMBOL(dib7000pc_detection);
1301
1302struct i2c_adapter * dib7000p_get_i2c_master(struct dvb_frontend *demod, enum dibx000_i2c_interface intf, int gating)
1303{
1304 struct dib7000p_state *st = demod->demodulator_priv;
1305 return dibx000_get_i2c_adapter(&st->i2c_master, intf, gating);
1306}
1307EXPORT_SYMBOL(dib7000p_get_i2c_master);
1308
Olivier Grenief8731f42009-09-18 04:08:43 -03001309int dib7000p_pid_filter_ctrl(struct dvb_frontend *fe, u8 onoff)
1310{
1311 struct dib7000p_state *state = fe->demodulator_priv;
1312 u16 val = dib7000p_read_word(state, 235) & 0xffef;
1313 val |= (onoff & 0x1) << 4;
1314 dprintk("PID filter enabled %d", onoff);
1315 return dib7000p_write_word(state, 235, val);
1316}
1317EXPORT_SYMBOL(dib7000p_pid_filter_ctrl);
1318
1319int dib7000p_pid_filter(struct dvb_frontend *fe, u8 id, u16 pid, u8 onoff)
1320{
1321 struct dib7000p_state *state = fe->demodulator_priv;
1322 dprintk("PID filter: index %x, PID %d, OnOff %d", id, pid, onoff);
1323 return dib7000p_write_word(state, 241 + id, onoff ? (1 << 13) | pid : 0);
1324}
1325EXPORT_SYMBOL(dib7000p_pid_filter);
1326
Patrick Boettchera75763f2006-10-18 08:34:16 -03001327int dib7000p_i2c_enumeration(struct i2c_adapter *i2c, int no_of_demods, u8 default_addr, struct dib7000p_config cfg[])
1328{
Randy Dunlap30d81bb2010-02-08 20:30:44 -03001329 struct dib7000p_state *dpst;
Patrick Boettchera75763f2006-10-18 08:34:16 -03001330 int k = 0;
1331 u8 new_addr = 0;
1332
Randy Dunlap30d81bb2010-02-08 20:30:44 -03001333 dpst = kzalloc(sizeof(struct dib7000p_state), GFP_KERNEL);
1334 if (!dpst)
Andrew Morton0b427602010-04-27 19:09:45 -03001335 return -ENOMEM;
Randy Dunlap30d81bb2010-02-08 20:30:44 -03001336
1337 dpst->i2c_adap = i2c;
1338
Patrick Boettchera75763f2006-10-18 08:34:16 -03001339 for (k = no_of_demods-1; k >= 0; k--) {
Randy Dunlap30d81bb2010-02-08 20:30:44 -03001340 dpst->cfg = cfg[k];
Patrick Boettchera75763f2006-10-18 08:34:16 -03001341
1342 /* designated i2c address */
1343 new_addr = (0x40 + k) << 1;
Randy Dunlap30d81bb2010-02-08 20:30:44 -03001344 dpst->i2c_addr = new_addr;
1345 dib7000p_write_word(dpst, 1287, 0x0003); /* sram lead in, rdy */
1346 if (dib7000p_identify(dpst) != 0) {
1347 dpst->i2c_addr = default_addr;
1348 dib7000p_write_word(dpst, 1287, 0x0003); /* sram lead in, rdy */
1349 if (dib7000p_identify(dpst) != 0) {
Patrick Boettchera75763f2006-10-18 08:34:16 -03001350 dprintk("DiB7000P #%d: not identified\n", k);
Randy Dunlap30d81bb2010-02-08 20:30:44 -03001351 kfree(dpst);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001352 return -EIO;
1353 }
1354 }
1355
1356 /* start diversity to pull_down div_str - just for i2c-enumeration */
Randy Dunlap30d81bb2010-02-08 20:30:44 -03001357 dib7000p_set_output_mode(dpst, OUTMODE_DIVERSITY);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001358
1359 /* set new i2c address and force divstart */
Randy Dunlap30d81bb2010-02-08 20:30:44 -03001360 dib7000p_write_word(dpst, 1285, (new_addr << 2) | 0x2);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001361
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001362 dprintk("IC %d initialized (to i2c_address 0x%x)", k, new_addr);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001363 }
1364
1365 for (k = 0; k < no_of_demods; k++) {
Randy Dunlap30d81bb2010-02-08 20:30:44 -03001366 dpst->cfg = cfg[k];
1367 dpst->i2c_addr = (0x40 + k) << 1;
Patrick Boettchera75763f2006-10-18 08:34:16 -03001368
1369 // unforce divstr
Randy Dunlap30d81bb2010-02-08 20:30:44 -03001370 dib7000p_write_word(dpst, 1285, dpst->i2c_addr << 2);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001371
1372 /* deactivate div - it was just for i2c-enumeration */
Randy Dunlap30d81bb2010-02-08 20:30:44 -03001373 dib7000p_set_output_mode(dpst, OUTMODE_HIGH_Z);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001374 }
1375
Randy Dunlap30d81bb2010-02-08 20:30:44 -03001376 kfree(dpst);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001377 return 0;
1378}
1379EXPORT_SYMBOL(dib7000p_i2c_enumeration);
1380
1381static struct dvb_frontend_ops dib7000p_ops;
1382struct dvb_frontend * dib7000p_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr, struct dib7000p_config *cfg)
1383{
1384 struct dvb_frontend *demod;
1385 struct dib7000p_state *st;
1386 st = kzalloc(sizeof(struct dib7000p_state), GFP_KERNEL);
1387 if (st == NULL)
1388 return NULL;
1389
1390 memcpy(&st->cfg, cfg, sizeof(struct dib7000p_config));
1391 st->i2c_adap = i2c_adap;
1392 st->i2c_addr = i2c_addr;
1393 st->gpio_val = cfg->gpio_val;
1394 st->gpio_dir = cfg->gpio_dir;
1395
Steven Totha38d6e32008-04-22 15:37:01 -03001396 /* Ensure the output mode remains at the previous default if it's
1397 * not specifically set by the caller.
1398 */
Anton Blanchard8d798982008-08-09 12:23:15 -03001399 if ((st->cfg.output_mode != OUTMODE_MPEG2_SERIAL) &&
1400 (st->cfg.output_mode != OUTMODE_MPEG2_PAR_GATED_CLK))
Steven Totha38d6e32008-04-22 15:37:01 -03001401 st->cfg.output_mode = OUTMODE_MPEG2_FIFO;
1402
Patrick Boettchera75763f2006-10-18 08:34:16 -03001403 demod = &st->demod;
1404 demod->demodulator_priv = st;
1405 memcpy(&st->demod.ops, &dib7000p_ops, sizeof(struct dvb_frontend_ops));
1406
Olivier Grenieeac1fe12009-09-23 13:41:27 -03001407 dib7000p_write_word(st, 1287, 0x0003); /* sram lead in, rdy */
1408
Patrick Boettchera75763f2006-10-18 08:34:16 -03001409 if (dib7000p_identify(st) != 0)
1410 goto error;
1411
Martin Samek7646b9d2009-09-30 22:59:09 -03001412 /* FIXME: make sure the dev.parent field is initialized, or else
1413 request_firmware() will hit an OOPS (this should be moved somewhere
1414 more common) */
1415 st->i2c_master.gated_tuner_i2c_adap.dev.parent = i2c_adap->dev.parent;
1416
Patrick Boettchera75763f2006-10-18 08:34:16 -03001417 dibx000_init_i2c_master(&st->i2c_master, DIB7000P, st->i2c_adap, st->i2c_addr);
1418
1419 dib7000p_demod_reset(st);
1420
1421 return demod;
1422
1423error:
1424 kfree(st);
1425 return NULL;
1426}
1427EXPORT_SYMBOL(dib7000p_attach);
1428
1429static struct dvb_frontend_ops dib7000p_ops = {
1430 .info = {
1431 .name = "DiBcom 7000PC",
1432 .type = FE_OFDM,
1433 .frequency_min = 44250000,
1434 .frequency_max = 867250000,
1435 .frequency_stepsize = 62500,
1436 .caps = FE_CAN_INVERSION_AUTO |
1437 FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
1438 FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
1439 FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO |
1440 FE_CAN_TRANSMISSION_MODE_AUTO |
1441 FE_CAN_GUARD_INTERVAL_AUTO |
1442 FE_CAN_RECOVER |
1443 FE_CAN_HIERARCHY_AUTO,
1444 },
1445
1446 .release = dib7000p_release,
1447
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001448 .init = dib7000p_wakeup,
Patrick Boettchera75763f2006-10-18 08:34:16 -03001449 .sleep = dib7000p_sleep,
1450
1451 .set_frontend = dib7000p_set_frontend,
1452 .get_tune_settings = dib7000p_fe_get_tune_settings,
1453 .get_frontend = dib7000p_get_frontend,
1454
1455 .read_status = dib7000p_read_status,
1456 .read_ber = dib7000p_read_ber,
1457 .read_signal_strength = dib7000p_read_signal_strength,
1458 .read_snr = dib7000p_read_snr,
1459 .read_ucblocks = dib7000p_read_unc_blocks,
1460};
1461
1462MODULE_AUTHOR("Patrick Boettcher <pboettcher@dibcom.fr>");
1463MODULE_DESCRIPTION("Driver for the DiBcom 7000PC COFDM demodulator");
1464MODULE_LICENSE("GPL");