blob: 3aed0d43392152688bbe4176ebc8ee68712ab724 [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 Grenie970d14c2010-09-07 12:50:46 -0300263 reg_909 |= (state->cfg.disable_sample_and_hold & 1) << 4;
Olivier Grenie90e12ce2010-09-07 12:50:45 -0300264 reg_908 |= (state->cfg.enable_current_mirror & 1) << 7;
265
Patrick Boettchera75763f2006-10-18 08:34:16 -0300266 dib7000p_write_word(state, 908, reg_908);
267 dib7000p_write_word(state, 909, reg_909);
268}
269
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300270static int dib7000p_set_bandwidth(struct dib7000p_state *state, u32 bw)
Patrick Boettchera75763f2006-10-18 08:34:16 -0300271{
Patrick Boettchera75763f2006-10-18 08:34:16 -0300272 u32 timf;
273
274 // store the current bandwidth for later use
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300275 state->current_bandwidth = bw;
Patrick Boettchera75763f2006-10-18 08:34:16 -0300276
277 if (state->timf == 0) {
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300278 dprintk( "using default timf");
Patrick Boettchera75763f2006-10-18 08:34:16 -0300279 timf = state->cfg.bw->timf;
280 } else {
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300281 dprintk( "using updated timf");
Patrick Boettchera75763f2006-10-18 08:34:16 -0300282 timf = state->timf;
283 }
284
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300285 timf = timf * (bw / 50) / 160;
Patrick Boettchera75763f2006-10-18 08:34:16 -0300286
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300287 dib7000p_write_word(state, 23, (u16) ((timf >> 16) & 0xffff));
288 dib7000p_write_word(state, 24, (u16) ((timf ) & 0xffff));
Patrick Boettchera75763f2006-10-18 08:34:16 -0300289
290 return 0;
291}
292
293static int dib7000p_sad_calib(struct dib7000p_state *state)
294{
295/* internal */
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300296// 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 -0300297 dib7000p_write_word(state, 73, (0 << 1) | (0 << 0));
298 dib7000p_write_word(state, 74, 776); // 0.625*3.3 / 4096
299
300 /* do the calibration */
301 dib7000p_write_word(state, 73, (1 << 0));
302 dib7000p_write_word(state, 73, (0 << 0));
303
304 msleep(1);
305
306 return 0;
307}
308
Patrick Boettcher01373a52007-07-30 12:49:04 -0300309int dib7000p_set_wbd_ref(struct dvb_frontend *demod, u16 value)
310{
311 struct dib7000p_state *state = demod->demodulator_priv;
312 if (value > 4095)
313 value = 4095;
314 state->wbd_ref = value;
315 return dib7000p_write_word(state, 105, (dib7000p_read_word(state, 105) & 0xf000) | value);
316}
317
318EXPORT_SYMBOL(dib7000p_set_wbd_ref);
Patrick Boettchera75763f2006-10-18 08:34:16 -0300319static void dib7000p_reset_pll(struct dib7000p_state *state)
320{
321 struct dibx000_bandwidth_config *bw = &state->cfg.bw[0];
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300322 u16 clk_cfg0;
Patrick Boettchera75763f2006-10-18 08:34:16 -0300323
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300324 /* force PLL bypass */
325 clk_cfg0 = (1 << 15) | ((bw->pll_ratio & 0x3f) << 9) |
326 (bw->modulo << 7) | (bw->ADClkSrc << 6) | (bw->IO_CLK_en_core << 5) |
327 (bw->bypclk_div << 2) | (bw->enable_refdiv << 1) | (0 << 0);
328
329 dib7000p_write_word(state, 900, clk_cfg0);
330
331 /* P_pll_cfg */
Patrick Boettchera75763f2006-10-18 08:34:16 -0300332 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 -0300333 clk_cfg0 = (bw->pll_bypass << 15) | (clk_cfg0 & 0x7fff);
334 dib7000p_write_word(state, 900, clk_cfg0);
Patrick Boettchera75763f2006-10-18 08:34:16 -0300335
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300336 dib7000p_write_word(state, 18, (u16) (((bw->internal*1000) >> 16) & 0xffff));
337 dib7000p_write_word(state, 19, (u16) ( (bw->internal*1000 ) & 0xffff));
338 dib7000p_write_word(state, 21, (u16) ( (bw->ifreq >> 16) & 0xffff));
339 dib7000p_write_word(state, 22, (u16) ( (bw->ifreq ) & 0xffff));
Patrick Boettchera75763f2006-10-18 08:34:16 -0300340
341 dib7000p_write_word(state, 72, bw->sad_cfg);
342}
343
344static int dib7000p_reset_gpio(struct dib7000p_state *st)
345{
346 /* reset the GPIOs */
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300347 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 -0300348
349 dib7000p_write_word(st, 1029, st->gpio_dir);
350 dib7000p_write_word(st, 1030, st->gpio_val);
351
352 /* TODO 1031 is P_gpio_od */
353
354 dib7000p_write_word(st, 1032, st->cfg.gpio_pwm_pos);
355
356 dib7000p_write_word(st, 1037, st->cfg.pwm_freq_div);
357 return 0;
358}
359
Patrick Boettcher01373a52007-07-30 12:49:04 -0300360static int dib7000p_cfg_gpio(struct dib7000p_state *st, u8 num, u8 dir, u8 val)
361{
362 st->gpio_dir = dib7000p_read_word(st, 1029);
363 st->gpio_dir &= ~(1 << num); /* reset the direction bit */
364 st->gpio_dir |= (dir & 0x1) << num; /* set the new direction */
365 dib7000p_write_word(st, 1029, st->gpio_dir);
366
367 st->gpio_val = dib7000p_read_word(st, 1030);
368 st->gpio_val &= ~(1 << num); /* reset the direction bit */
369 st->gpio_val |= (val & 0x01) << num; /* set the new value */
370 dib7000p_write_word(st, 1030, st->gpio_val);
371
372 return 0;
373}
374
375int dib7000p_set_gpio(struct dvb_frontend *demod, u8 num, u8 dir, u8 val)
376{
377 struct dib7000p_state *state = demod->demodulator_priv;
378 return dib7000p_cfg_gpio(state, num, dir, val);
379}
380
381EXPORT_SYMBOL(dib7000p_set_gpio);
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300382static u16 dib7000p_defaults[] =
383
384{
385 // auto search configuration
386 3, 2,
387 0x0004,
388 0x1000,
389 0x0814, /* Equal Lock */
390
391 12, 6,
392 0x001b,
393 0x7740,
394 0x005b,
395 0x8d80,
396 0x01c9,
397 0xc380,
398 0x0000,
399 0x0080,
400 0x0000,
401 0x0090,
402 0x0001,
403 0xd4c0,
404
405 1, 26,
406 0x6680, // P_timf_alpha=6, P_corm_alpha=6, P_corm_thres=128 default: 6,4,26
407
408 /* set ADC level to -16 */
409 11, 79,
410 (1 << 13) - 825 - 117,
411 (1 << 13) - 837 - 117,
412 (1 << 13) - 811 - 117,
413 (1 << 13) - 766 - 117,
414 (1 << 13) - 737 - 117,
415 (1 << 13) - 693 - 117,
416 (1 << 13) - 648 - 117,
417 (1 << 13) - 619 - 117,
418 (1 << 13) - 575 - 117,
419 (1 << 13) - 531 - 117,
420 (1 << 13) - 501 - 117,
421
422 1, 142,
423 0x0410, // P_palf_filter_on=1, P_palf_filter_freeze=0, P_palf_alpha_regul=16
424
425 /* disable power smoothing */
426 8, 145,
427 0,
428 0,
429 0,
430 0,
431 0,
432 0,
433 0,
434 0,
435
436 1, 154,
437 1 << 13, // P_fft_freq_dir=1, P_fft_nb_to_cut=0
438
439 1, 168,
440 0x0ccd, // P_pha3_thres, default 0x3000
441
442// 1, 169,
443// 0x0010, // P_cti_use_cpe=0, P_cti_use_prog=0, P_cti_win_len=16, default: 0x0010
444
445 1, 183,
446 0x200f, // P_cspu_regul=512, P_cspu_win_cut=15, default: 0x2005
447
448 5, 187,
449 0x023d, // P_adp_regul_cnt=573, default: 410
450 0x00a4, // P_adp_noise_cnt=
451 0x00a4, // P_adp_regul_ext
452 0x7ff0, // P_adp_noise_ext
453 0x3ccc, // P_adp_fil
454
455 1, 198,
456 0x800, // P_equal_thres_wgn
457
458 1, 222,
459 0x0010, // P_fec_ber_rs_len=2
460
461 1, 235,
462 0x0062, // P_smo_mode, P_smo_rs_discard, P_smo_fifo_flush, P_smo_pid_parse, P_smo_error_discard
463
464 2, 901,
465 0x0006, // P_clk_cfg1
466 (3 << 10) | (1 << 6), // P_divclksel=3 P_divbitsel=1
467
468 1, 905,
469 0x2c8e, // Tuner IO bank: max drive (14mA) + divout pads max drive
470
471 0,
472};
473
Patrick Boettchera75763f2006-10-18 08:34:16 -0300474static int dib7000p_demod_reset(struct dib7000p_state *state)
475{
476 dib7000p_set_power_mode(state, DIB7000P_POWER_ALL);
477
478 dib7000p_set_adc_state(state, DIBX000_VBG_ENABLE);
479
480 /* restart all parts */
481 dib7000p_write_word(state, 770, 0xffff);
482 dib7000p_write_word(state, 771, 0xffff);
483 dib7000p_write_word(state, 772, 0x001f);
484 dib7000p_write_word(state, 898, 0x0003);
485 /* except i2c, sdio, gpio - control interfaces */
486 dib7000p_write_word(state, 1280, 0x01fc - ((1 << 7) | (1 << 6) | (1 << 5)) );
487
488 dib7000p_write_word(state, 770, 0);
489 dib7000p_write_word(state, 771, 0);
490 dib7000p_write_word(state, 772, 0);
491 dib7000p_write_word(state, 898, 0);
492 dib7000p_write_word(state, 1280, 0);
493
494 /* default */
495 dib7000p_reset_pll(state);
496
497 if (dib7000p_reset_gpio(state) != 0)
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300498 dprintk( "GPIO reset was not successful.");
Patrick Boettchera75763f2006-10-18 08:34:16 -0300499
500 if (dib7000p_set_output_mode(state, OUTMODE_HIGH_Z) != 0)
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300501 dprintk( "OUTPUT_MODE could not be reset.");
Patrick Boettchera75763f2006-10-18 08:34:16 -0300502
503 /* unforce divstr regardless whether i2c enumeration was done or not */
504 dib7000p_write_word(state, 1285, dib7000p_read_word(state, 1285) & ~(1 << 1) );
505
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300506 dib7000p_set_bandwidth(state, 8000);
507
508 dib7000p_set_adc_state(state, DIBX000_SLOW_ADC_ON);
509 dib7000p_sad_calib(state);
510 dib7000p_set_adc_state(state, DIBX000_SLOW_ADC_OFF);
511
512 // P_iqc_alpha_pha, P_iqc_alpha_amp_dcc_alpha, ...
513 if(state->cfg.tuner_is_baseband)
514 dib7000p_write_word(state, 36,0x0755);
515 else
516 dib7000p_write_word(state, 36,0x1f55);
517
518 dib7000p_write_tab(state, dib7000p_defaults);
519
Patrick Boettchera75763f2006-10-18 08:34:16 -0300520 dib7000p_set_power_mode(state, DIB7000P_POWER_INTERFACE_ONLY);
521
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300522
Patrick Boettchera75763f2006-10-18 08:34:16 -0300523 return 0;
524}
525
Patrick Boettchera75763f2006-10-18 08:34:16 -0300526static void dib7000p_pll_clk_cfg(struct dib7000p_state *state)
527{
528 u16 tmp = 0;
529 tmp = dib7000p_read_word(state, 903);
530 dib7000p_write_word(state, 903, (tmp | 0x1)); //pwr-up pll
531 tmp = dib7000p_read_word(state, 900);
532 dib7000p_write_word(state, 900, (tmp & 0x7fff) | (1 << 6)); //use High freq clock
533}
534
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300535static void dib7000p_restart_agc(struct dib7000p_state *state)
Patrick Boettchera75763f2006-10-18 08:34:16 -0300536{
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300537 // P_restart_iqc & P_restart_agc
538 dib7000p_write_word(state, 770, (1 << 11) | (1 << 9));
539 dib7000p_write_word(state, 770, 0x0000);
Patrick Boettchera75763f2006-10-18 08:34:16 -0300540}
541
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300542static int dib7000p_update_lna(struct dib7000p_state *state)
Patrick Boettchera75763f2006-10-18 08:34:16 -0300543{
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300544 u16 dyn_gain;
545
546 // when there is no LNA to program return immediatly
547 if (state->cfg.update_lna) {
Patrick Boettcher01373a52007-07-30 12:49:04 -0300548 // read dyn_gain here (because it is demod-dependent and not fe)
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300549 dyn_gain = dib7000p_read_word(state, 394);
550 if (state->cfg.update_lna(&state->demod,dyn_gain)) { // LNA has changed
551 dib7000p_restart_agc(state);
552 return 1;
553 }
554 }
555
556 return 0;
557}
558
559static int dib7000p_set_agc_config(struct dib7000p_state *state, u8 band)
560{
561 struct dibx000_agc_config *agc = NULL;
562 int i;
563 if (state->current_band == band && state->current_agc != NULL)
564 return 0;
565 state->current_band = band;
566
567 for (i = 0; i < state->cfg.agc_config_count; i++)
568 if (state->cfg.agc[i].band_caps & band) {
569 agc = &state->cfg.agc[i];
570 break;
571 }
572
573 if (agc == NULL) {
574 dprintk( "no valid AGC configuration found for band 0x%02x",band);
575 return -EINVAL;
576 }
577
578 state->current_agc = agc;
579
580 /* AGC */
581 dib7000p_write_word(state, 75 , agc->setup );
582 dib7000p_write_word(state, 76 , agc->inv_gain );
583 dib7000p_write_word(state, 77 , agc->time_stabiliz );
584 dib7000p_write_word(state, 100, (agc->alpha_level << 12) | agc->thlock);
585
586 // Demod AGC loop configuration
587 dib7000p_write_word(state, 101, (agc->alpha_mant << 5) | agc->alpha_exp);
588 dib7000p_write_word(state, 102, (agc->beta_mant << 6) | agc->beta_exp);
589
590 /* AGC continued */
591 dprintk( "WBD: ref: %d, sel: %d, active: %d, alpha: %d",
592 state->wbd_ref != 0 ? state->wbd_ref : agc->wbd_ref, agc->wbd_sel, !agc->perform_agc_softsplit, agc->wbd_sel);
593
594 if (state->wbd_ref != 0)
595 dib7000p_write_word(state, 105, (agc->wbd_inv << 12) | state->wbd_ref);
596 else
597 dib7000p_write_word(state, 105, (agc->wbd_inv << 12) | agc->wbd_ref);
598
599 dib7000p_write_word(state, 106, (agc->wbd_sel << 13) | (agc->wbd_alpha << 9) | (agc->perform_agc_softsplit << 8));
600
601 dib7000p_write_word(state, 107, agc->agc1_max);
602 dib7000p_write_word(state, 108, agc->agc1_min);
603 dib7000p_write_word(state, 109, agc->agc2_max);
604 dib7000p_write_word(state, 110, agc->agc2_min);
605 dib7000p_write_word(state, 111, (agc->agc1_pt1 << 8) | agc->agc1_pt2);
606 dib7000p_write_word(state, 112, agc->agc1_pt3);
607 dib7000p_write_word(state, 113, (agc->agc1_slope1 << 8) | agc->agc1_slope2);
608 dib7000p_write_word(state, 114, (agc->agc2_pt1 << 8) | agc->agc2_pt2);
609 dib7000p_write_word(state, 115, (agc->agc2_slope1 << 8) | agc->agc2_slope2);
610 return 0;
611}
612
613static int dib7000p_agc_startup(struct dvb_frontend *demod, struct dvb_frontend_parameters *ch)
614{
615 struct dib7000p_state *state = demod->demodulator_priv;
616 int ret = -1;
617 u8 *agc_state = &state->agc_state;
618 u8 agc_split;
619
620 switch (state->agc_state) {
621 case 0:
622 // set power-up level: interf+analog+AGC
623 dib7000p_set_power_mode(state, DIB7000P_POWER_ALL);
624 dib7000p_set_adc_state(state, DIBX000_ADC_ON);
625 dib7000p_pll_clk_cfg(state);
626
627 if (dib7000p_set_agc_config(state, BAND_OF_FREQUENCY(ch->frequency/1000)) != 0)
628 return -1;
629
630 ret = 7;
631 (*agc_state)++;
632 break;
633
634 case 1:
635 // AGC initialization
636 if (state->cfg.agc_control)
637 state->cfg.agc_control(&state->demod, 1);
638
639 dib7000p_write_word(state, 78, 32768);
640 if (!state->current_agc->perform_agc_softsplit) {
641 /* we are using the wbd - so slow AGC startup */
642 /* force 0 split on WBD and restart AGC */
643 dib7000p_write_word(state, 106, (state->current_agc->wbd_sel << 13) | (state->current_agc->wbd_alpha << 9) | (1 << 8));
644 (*agc_state)++;
645 ret = 5;
646 } else {
647 /* default AGC startup */
648 (*agc_state) = 4;
649 /* wait AGC rough lock time */
650 ret = 7;
651 }
652
653 dib7000p_restart_agc(state);
654 break;
655
656 case 2: /* fast split search path after 5sec */
657 dib7000p_write_word(state, 75, state->current_agc->setup | (1 << 4)); /* freeze AGC loop */
658 dib7000p_write_word(state, 106, (state->current_agc->wbd_sel << 13) | (2 << 9) | (0 << 8)); /* fast split search 0.25kHz */
659 (*agc_state)++;
660 ret = 14;
661 break;
662
663 case 3: /* split search ended */
Patrick Boettcher01373a52007-07-30 12:49:04 -0300664 agc_split = (u8)dib7000p_read_word(state, 396); /* store the split value for the next time */
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300665 dib7000p_write_word(state, 78, dib7000p_read_word(state, 394)); /* set AGC gain start value */
666
667 dib7000p_write_word(state, 75, state->current_agc->setup); /* std AGC loop */
668 dib7000p_write_word(state, 106, (state->current_agc->wbd_sel << 13) | (state->current_agc->wbd_alpha << 9) | agc_split); /* standard split search */
669
670 dib7000p_restart_agc(state);
671
672 dprintk( "SPLIT %p: %hd", demod, agc_split);
673
674 (*agc_state)++;
675 ret = 5;
676 break;
677
678 case 4: /* LNA startup */
679 // wait AGC accurate lock time
680 ret = 7;
681
682 if (dib7000p_update_lna(state))
683 // wait only AGC rough lock time
684 ret = 5;
685 else // nothing was done, go to the next state
686 (*agc_state)++;
687 break;
688
689 case 5:
690 if (state->cfg.agc_control)
691 state->cfg.agc_control(&state->demod, 0);
692 (*agc_state)++;
693 break;
694 default:
695 break;
696 }
697 return ret;
698}
699
700static void dib7000p_update_timf(struct dib7000p_state *state)
701{
702 u32 timf = (dib7000p_read_word(state, 427) << 16) | dib7000p_read_word(state, 428);
703 state->timf = timf * 160 / (state->current_bandwidth / 50);
704 dib7000p_write_word(state, 23, (u16) (timf >> 16));
705 dib7000p_write_word(state, 24, (u16) (timf & 0xffff));
706 dprintk( "updated timf_frequency: %d (default: %d)",state->timf, state->cfg.bw->timf);
707
708}
709
710static void dib7000p_set_channel(struct dib7000p_state *state, struct dvb_frontend_parameters *ch, u8 seq)
711{
712 u16 value, est[4];
713
714 dib7000p_set_bandwidth(state, BANDWIDTH_TO_KHZ(ch->u.ofdm.bandwidth));
Patrick Boettchera75763f2006-10-18 08:34:16 -0300715
716 /* nfft, guard, qam, alpha */
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300717 value = 0;
718 switch (ch->u.ofdm.transmission_mode) {
719 case TRANSMISSION_MODE_2K: value |= (0 << 7); break;
720 case /* 4K MODE */ 255: value |= (2 << 7); break;
721 default:
722 case TRANSMISSION_MODE_8K: value |= (1 << 7); break;
723 }
724 switch (ch->u.ofdm.guard_interval) {
725 case GUARD_INTERVAL_1_32: value |= (0 << 5); break;
726 case GUARD_INTERVAL_1_16: value |= (1 << 5); break;
727 case GUARD_INTERVAL_1_4: value |= (3 << 5); break;
728 default:
729 case GUARD_INTERVAL_1_8: value |= (2 << 5); break;
730 }
731 switch (ch->u.ofdm.constellation) {
732 case QPSK: value |= (0 << 3); break;
733 case QAM_16: value |= (1 << 3); break;
734 default:
735 case QAM_64: value |= (2 << 3); break;
736 }
737 switch (HIERARCHY_1) {
738 case HIERARCHY_2: value |= 2; break;
739 case HIERARCHY_4: value |= 4; break;
740 default:
741 case HIERARCHY_1: value |= 1; break;
742 }
743 dib7000p_write_word(state, 0, value);
Patrick Boettchera75763f2006-10-18 08:34:16 -0300744 dib7000p_write_word(state, 5, (seq << 4) | 1); /* do not force tps, search list 0 */
745
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300746 /* P_dintl_native, P_dintlv_inv, P_hrch, P_code_rate, P_select_hp */
747 value = 0;
748 if (1 != 0)
749 value |= (1 << 6);
750 if (ch->u.ofdm.hierarchy_information == 1)
751 value |= (1 << 4);
752 if (1 == 1)
753 value |= 1;
754 switch ((ch->u.ofdm.hierarchy_information == 0 || 1 == 1) ? ch->u.ofdm.code_rate_HP : ch->u.ofdm.code_rate_LP) {
755 case FEC_2_3: value |= (2 << 1); break;
756 case FEC_3_4: value |= (3 << 1); break;
757 case FEC_5_6: value |= (5 << 1); break;
758 case FEC_7_8: value |= (7 << 1); break;
759 default:
760 case FEC_1_2: value |= (1 << 1); break;
761 }
762 dib7000p_write_word(state, 208, value);
763
764 /* offset loop parameters */
765 dib7000p_write_word(state, 26, 0x6680); // timf(6xxx)
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300766 dib7000p_write_word(state, 32, 0x0003); // pha_off_max(xxx3)
Matt Doran8f6956c2007-07-31 07:09:30 -0300767 dib7000p_write_word(state, 29, 0x1273); // isi
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300768 dib7000p_write_word(state, 33, 0x0005); // sfreq(xxx5)
Patrick Boettchera75763f2006-10-18 08:34:16 -0300769
770 /* P_dvsy_sync_wait */
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300771 switch (ch->u.ofdm.transmission_mode) {
772 case TRANSMISSION_MODE_8K: value = 256; break;
773 case /* 4K MODE */ 255: value = 128; break;
774 case TRANSMISSION_MODE_2K:
775 default: value = 64; break;
Patrick Boettchera75763f2006-10-18 08:34:16 -0300776 }
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300777 switch (ch->u.ofdm.guard_interval) {
778 case GUARD_INTERVAL_1_16: value *= 2; break;
779 case GUARD_INTERVAL_1_8: value *= 4; break;
780 case GUARD_INTERVAL_1_4: value *= 8; break;
781 default:
782 case GUARD_INTERVAL_1_32: value *= 1; break;
783 }
Olivier Grenie970d14c2010-09-07 12:50:46 -0300784 if (state->cfg.diversity_delay == 0)
785 state->div_sync_wait = (value * 3) / 2 + 48; // add 50% SFN margin + compensate for one DVSY-fifo
786 else
787 state->div_sync_wait = (value * 3) / 2 + state->cfg.diversity_delay; // add 50% SFN margin + compensate for one DVSY-fifo
Patrick Boettchera75763f2006-10-18 08:34:16 -0300788
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300789 /* deactive the possibility of diversity reception if extended interleaver */
790 state->div_force_off = !1 && ch->u.ofdm.transmission_mode != TRANSMISSION_MODE_8K;
791 dib7000p_set_diversity_in(&state->demod, state->div_state);
Patrick Boettchera75763f2006-10-18 08:34:16 -0300792
793 /* channel estimation fine configuration */
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300794 switch (ch->u.ofdm.constellation) {
795 case QAM_64:
Patrick Boettchera75763f2006-10-18 08:34:16 -0300796 est[0] = 0x0148; /* P_adp_regul_cnt 0.04 */
797 est[1] = 0xfff0; /* P_adp_noise_cnt -0.002 */
798 est[2] = 0x00a4; /* P_adp_regul_ext 0.02 */
799 est[3] = 0xfff8; /* P_adp_noise_ext -0.001 */
800 break;
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300801 case QAM_16:
Patrick Boettchera75763f2006-10-18 08:34:16 -0300802 est[0] = 0x023d; /* P_adp_regul_cnt 0.07 */
803 est[1] = 0xffdf; /* P_adp_noise_cnt -0.004 */
804 est[2] = 0x00a4; /* P_adp_regul_ext 0.02 */
805 est[3] = 0xfff0; /* P_adp_noise_ext -0.002 */
806 break;
807 default:
808 est[0] = 0x099a; /* P_adp_regul_cnt 0.3 */
809 est[1] = 0xffae; /* P_adp_noise_cnt -0.01 */
810 est[2] = 0x0333; /* P_adp_regul_ext 0.1 */
811 est[3] = 0xfff8; /* P_adp_noise_ext -0.002 */
812 break;
813 }
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300814 for (value = 0; value < 4; value++)
815 dib7000p_write_word(state, 187 + value, est[value]);
Patrick Boettchera75763f2006-10-18 08:34:16 -0300816}
817
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300818static int dib7000p_autosearch_start(struct dvb_frontend *demod, struct dvb_frontend_parameters *ch)
Patrick Boettchera75763f2006-10-18 08:34:16 -0300819{
820 struct dib7000p_state *state = demod->demodulator_priv;
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300821 struct dvb_frontend_parameters schan;
822 u32 value, factor;
Patrick Boettchera75763f2006-10-18 08:34:16 -0300823
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300824 schan = *ch;
825 schan.u.ofdm.constellation = QAM_64;
826 schan.u.ofdm.guard_interval = GUARD_INTERVAL_1_32;
827 schan.u.ofdm.transmission_mode = TRANSMISSION_MODE_8K;
828 schan.u.ofdm.code_rate_HP = FEC_2_3;
829 schan.u.ofdm.code_rate_LP = FEC_3_4;
830 schan.u.ofdm.hierarchy_information = 0;
Patrick Boettchera75763f2006-10-18 08:34:16 -0300831
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300832 dib7000p_set_channel(state, &schan, 7);
833
834 factor = BANDWIDTH_TO_KHZ(ch->u.ofdm.bandwidth);
835 if (factor >= 5000)
836 factor = 1;
837 else
838 factor = 6;
Patrick Boettchera75763f2006-10-18 08:34:16 -0300839
840 // always use the setting for 8MHz here lock_time for 7,6 MHz are longer
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300841 value = 30 * state->cfg.bw->internal * factor;
Patrick Boettchera75763f2006-10-18 08:34:16 -0300842 dib7000p_write_word(state, 6, (u16) ((value >> 16) & 0xffff)); // lock0 wait time
843 dib7000p_write_word(state, 7, (u16) (value & 0xffff)); // lock0 wait time
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300844 value = 100 * state->cfg.bw->internal * factor;
Patrick Boettchera75763f2006-10-18 08:34:16 -0300845 dib7000p_write_word(state, 8, (u16) ((value >> 16) & 0xffff)); // lock1 wait time
846 dib7000p_write_word(state, 9, (u16) (value & 0xffff)); // lock1 wait time
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300847 value = 500 * state->cfg.bw->internal * factor;
Patrick Boettchera75763f2006-10-18 08:34:16 -0300848 dib7000p_write_word(state, 10, (u16) ((value >> 16) & 0xffff)); // lock2 wait time
849 dib7000p_write_word(state, 11, (u16) (value & 0xffff)); // lock2 wait time
850
851 value = dib7000p_read_word(state, 0);
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300852 dib7000p_write_word(state, 0, (u16) ((1 << 9) | value));
Patrick Boettchera75763f2006-10-18 08:34:16 -0300853 dib7000p_read_word(state, 1284);
854 dib7000p_write_word(state, 0, (u16) value);
855
856 return 0;
857}
858
859static int dib7000p_autosearch_is_irq(struct dvb_frontend *demod)
860{
861 struct dib7000p_state *state = demod->demodulator_priv;
862 u16 irq_pending = dib7000p_read_word(state, 1284);
863
864 if (irq_pending & 0x1) // failed
865 return 1;
866
867 if (irq_pending & 0x2) // succeeded
868 return 2;
869
870 return 0; // still pending
871}
872
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300873static void dib7000p_spur_protect(struct dib7000p_state *state, u32 rf_khz, u32 bw)
874{
875 static s16 notch[]={16143, 14402, 12238, 9713, 6902, 3888, 759, -2392};
876 static u8 sine [] ={0, 2, 3, 5, 6, 8, 9, 11, 13, 14, 16, 17, 19, 20, 22,
877 24, 25, 27, 28, 30, 31, 33, 34, 36, 38, 39, 41, 42, 44, 45, 47, 48, 50, 51,
878 53, 55, 56, 58, 59, 61, 62, 64, 65, 67, 68, 70, 71, 73, 74, 76, 77, 79, 80,
879 82, 83, 85, 86, 88, 89, 91, 92, 94, 95, 97, 98, 99, 101, 102, 104, 105,
880 107, 108, 109, 111, 112, 114, 115, 117, 118, 119, 121, 122, 123, 125, 126,
881 128, 129, 130, 132, 133, 134, 136, 137, 138, 140, 141, 142, 144, 145, 146,
882 147, 149, 150, 151, 152, 154, 155, 156, 157, 159, 160, 161, 162, 164, 165,
883 166, 167, 168, 170, 171, 172, 173, 174, 175, 177, 178, 179, 180, 181, 182,
884 183, 184, 185, 186, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198,
885 199, 200, 201, 202, 203, 204, 205, 206, 207, 207, 208, 209, 210, 211, 212,
886 213, 214, 215, 215, 216, 217, 218, 219, 220, 220, 221, 222, 223, 224, 224,
887 225, 226, 227, 227, 228, 229, 229, 230, 231, 231, 232, 233, 233, 234, 235,
888 235, 236, 237, 237, 238, 238, 239, 239, 240, 241, 241, 242, 242, 243, 243,
889 244, 244, 245, 245, 245, 246, 246, 247, 247, 248, 248, 248, 249, 249, 249,
890 250, 250, 250, 251, 251, 251, 252, 252, 252, 252, 253, 253, 253, 253, 254,
891 254, 254, 254, 254, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
892 255, 255, 255, 255, 255, 255};
893
894 u32 xtal = state->cfg.bw->xtal_hz / 1000;
Julia Lawall75b697f2009-08-01 16:48:41 -0300895 int f_rel = DIV_ROUND_CLOSEST(rf_khz, xtal) * xtal - rf_khz;
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300896 int k;
897 int coef_re[8],coef_im[8];
898 int bw_khz = bw;
899 u32 pha;
900
901 dprintk( "relative position of the Spur: %dk (RF: %dk, XTAL: %dk)", f_rel, rf_khz, xtal);
902
903
904 if (f_rel < -bw_khz/2 || f_rel > bw_khz/2)
905 return;
906
907 bw_khz /= 100;
908
909 dib7000p_write_word(state, 142 ,0x0610);
910
911 for (k = 0; k < 8; k++) {
912 pha = ((f_rel * (k+1) * 112 * 80/bw_khz) /1000) & 0x3ff;
913
914 if (pha==0) {
915 coef_re[k] = 256;
916 coef_im[k] = 0;
917 } else if(pha < 256) {
918 coef_re[k] = sine[256-(pha&0xff)];
919 coef_im[k] = sine[pha&0xff];
920 } else if (pha == 256) {
921 coef_re[k] = 0;
922 coef_im[k] = 256;
923 } else if (pha < 512) {
924 coef_re[k] = -sine[pha&0xff];
925 coef_im[k] = sine[256 - (pha&0xff)];
926 } else if (pha == 512) {
927 coef_re[k] = -256;
928 coef_im[k] = 0;
929 } else if (pha < 768) {
930 coef_re[k] = -sine[256-(pha&0xff)];
931 coef_im[k] = -sine[pha&0xff];
932 } else if (pha == 768) {
933 coef_re[k] = 0;
934 coef_im[k] = -256;
935 } else {
936 coef_re[k] = sine[pha&0xff];
937 coef_im[k] = -sine[256 - (pha&0xff)];
938 }
939
940 coef_re[k] *= notch[k];
941 coef_re[k] += (1<<14);
942 if (coef_re[k] >= (1<<24))
943 coef_re[k] = (1<<24) - 1;
944 coef_re[k] /= (1<<15);
945
946 coef_im[k] *= notch[k];
947 coef_im[k] += (1<<14);
948 if (coef_im[k] >= (1<<24))
949 coef_im[k] = (1<<24)-1;
950 coef_im[k] /= (1<<15);
951
952 dprintk( "PALF COEF: %d re: %d im: %d", k, coef_re[k], coef_im[k]);
953
954 dib7000p_write_word(state, 143, (0 << 14) | (k << 10) | (coef_re[k] & 0x3ff));
955 dib7000p_write_word(state, 144, coef_im[k] & 0x3ff);
956 dib7000p_write_word(state, 143, (1 << 14) | (k << 10) | (coef_re[k] & 0x3ff));
957 }
958 dib7000p_write_word(state,143 ,0);
959}
960
961static int dib7000p_tune(struct dvb_frontend *demod, struct dvb_frontend_parameters *ch)
Patrick Boettchera75763f2006-10-18 08:34:16 -0300962{
963 struct dib7000p_state *state = demod->demodulator_priv;
964 u16 tmp = 0;
965
966 if (ch != NULL)
967 dib7000p_set_channel(state, ch, 0);
968 else
969 return -EINVAL;
970
971 // restart demod
972 dib7000p_write_word(state, 770, 0x4000);
973 dib7000p_write_word(state, 770, 0x0000);
974 msleep(45);
975
976 /* 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 -0300977 tmp = (0 << 14) | (4 << 10) | (0 << 9) | (3 << 5) | (1 << 4) | (0x3);
978 if (state->sfn_workaround_active) {
979 dprintk( "SFN workaround is active");
980 tmp |= (1 << 9);
981 dib7000p_write_word(state, 166, 0x4000); // P_pha3_force_pha_shift
982 } else {
983 dib7000p_write_word(state, 166, 0x0000); // P_pha3_force_pha_shift
984 }
985 dib7000p_write_word(state, 29, tmp);
Patrick Boettchera75763f2006-10-18 08:34:16 -0300986
987 // never achieved a lock with that bandwidth so far - wait for osc-freq to update
988 if (state->timf == 0)
989 msleep(200);
990
991 /* offset loop parameters */
992
993 /* P_timf_alpha, P_corm_alpha=6, P_corm_thres=0x80 */
994 tmp = (6 << 8) | 0x80;
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300995 switch (ch->u.ofdm.transmission_mode) {
996 case TRANSMISSION_MODE_2K: tmp |= (7 << 12); break;
997 case /* 4K MODE */ 255: tmp |= (8 << 12); break;
998 default:
999 case TRANSMISSION_MODE_8K: tmp |= (9 << 12); break;
Patrick Boettchera75763f2006-10-18 08:34:16 -03001000 }
1001 dib7000p_write_word(state, 26, tmp); /* timf_a(6xxx) */
1002
1003 /* P_ctrl_freeze_pha_shift=0, P_ctrl_pha_off_max */
1004 tmp = (0 << 4);
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001005 switch (ch->u.ofdm.transmission_mode) {
1006 case TRANSMISSION_MODE_2K: tmp |= 0x6; break;
1007 case /* 4K MODE */ 255: tmp |= 0x7; break;
1008 default:
1009 case TRANSMISSION_MODE_8K: tmp |= 0x8; break;
Patrick Boettchera75763f2006-10-18 08:34:16 -03001010 }
1011 dib7000p_write_word(state, 32, tmp);
1012
1013 /* P_ctrl_sfreq_inh=0, P_ctrl_sfreq_step */
1014 tmp = (0 << 4);
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001015 switch (ch->u.ofdm.transmission_mode) {
1016 case TRANSMISSION_MODE_2K: tmp |= 0x6; break;
1017 case /* 4K MODE */ 255: tmp |= 0x7; break;
1018 default:
1019 case TRANSMISSION_MODE_8K: tmp |= 0x8; break;
Patrick Boettchera75763f2006-10-18 08:34:16 -03001020 }
1021 dib7000p_write_word(state, 33, tmp);
1022
1023 tmp = dib7000p_read_word(state,509);
1024 if (!((tmp >> 6) & 0x1)) {
1025 /* restart the fec */
1026 tmp = dib7000p_read_word(state,771);
1027 dib7000p_write_word(state, 771, tmp | (1 << 1));
1028 dib7000p_write_word(state, 771, tmp);
1029 msleep(10);
1030 tmp = dib7000p_read_word(state,509);
1031 }
1032
1033 // we achieved a lock - it's time to update the osc freq
1034 if ((tmp >> 6) & 0x1)
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001035 dib7000p_update_timf(state);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001036
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001037 if (state->cfg.spur_protect)
1038 dib7000p_spur_protect(state, ch->frequency/1000, BANDWIDTH_TO_KHZ(ch->u.ofdm.bandwidth));
1039
1040 dib7000p_set_bandwidth(state, BANDWIDTH_TO_KHZ(ch->u.ofdm.bandwidth));
Patrick Boettchera75763f2006-10-18 08:34:16 -03001041 return 0;
1042}
1043
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001044static int dib7000p_wakeup(struct dvb_frontend *demod)
Patrick Boettchera75763f2006-10-18 08:34:16 -03001045{
Patrick Boettchera75763f2006-10-18 08:34:16 -03001046 struct dib7000p_state *state = demod->demodulator_priv;
Patrick Boettchera75763f2006-10-18 08:34:16 -03001047 dib7000p_set_power_mode(state, DIB7000P_POWER_ALL);
1048 dib7000p_set_adc_state(state, DIBX000_SLOW_ADC_ON);
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001049 return 0;
Patrick Boettchera75763f2006-10-18 08:34:16 -03001050}
1051
1052static int dib7000p_sleep(struct dvb_frontend *demod)
1053{
1054 struct dib7000p_state *state = demod->demodulator_priv;
1055 return dib7000p_set_output_mode(state, OUTMODE_HIGH_Z) | dib7000p_set_power_mode(state, DIB7000P_POWER_INTERFACE_ONLY);
1056}
1057
1058static int dib7000p_identify(struct dib7000p_state *st)
1059{
1060 u16 value;
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001061 dprintk( "checking demod on I2C address: %d (%x)",
Patrick Boettchera75763f2006-10-18 08:34:16 -03001062 st->i2c_addr, st->i2c_addr);
1063
1064 if ((value = dib7000p_read_word(st, 768)) != 0x01b3) {
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001065 dprintk( "wrong Vendor ID (read=0x%x)",value);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001066 return -EREMOTEIO;
1067 }
1068
1069 if ((value = dib7000p_read_word(st, 769)) != 0x4000) {
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001070 dprintk( "wrong Device ID (%x)",value);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001071 return -EREMOTEIO;
1072 }
1073
1074 return 0;
1075}
1076
1077
1078static int dib7000p_get_frontend(struct dvb_frontend* fe,
1079 struct dvb_frontend_parameters *fep)
1080{
1081 struct dib7000p_state *state = fe->demodulator_priv;
1082 u16 tps = dib7000p_read_word(state,463);
1083
1084 fep->inversion = INVERSION_AUTO;
1085
Patrick Boettcher904a82e2008-01-25 07:31:58 -03001086 fep->u.ofdm.bandwidth = BANDWIDTH_TO_INDEX(state->current_bandwidth);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001087
1088 switch ((tps >> 8) & 0x3) {
1089 case 0: fep->u.ofdm.transmission_mode = TRANSMISSION_MODE_2K; break;
1090 case 1: fep->u.ofdm.transmission_mode = TRANSMISSION_MODE_8K; break;
1091 /* case 2: fep->u.ofdm.transmission_mode = TRANSMISSION_MODE_4K; break; */
1092 }
1093
1094 switch (tps & 0x3) {
1095 case 0: fep->u.ofdm.guard_interval = GUARD_INTERVAL_1_32; break;
1096 case 1: fep->u.ofdm.guard_interval = GUARD_INTERVAL_1_16; break;
1097 case 2: fep->u.ofdm.guard_interval = GUARD_INTERVAL_1_8; break;
1098 case 3: fep->u.ofdm.guard_interval = GUARD_INTERVAL_1_4; break;
1099 }
1100
1101 switch ((tps >> 14) & 0x3) {
1102 case 0: fep->u.ofdm.constellation = QPSK; break;
1103 case 1: fep->u.ofdm.constellation = QAM_16; break;
1104 case 2:
1105 default: fep->u.ofdm.constellation = QAM_64; break;
1106 }
1107
1108 /* as long as the frontend_param structure is fixed for hierarchical transmission I refuse to use it */
1109 /* (tps >> 13) & 0x1 == hrch is used, (tps >> 10) & 0x7 == alpha */
1110
1111 fep->u.ofdm.hierarchy_information = HIERARCHY_NONE;
1112 switch ((tps >> 5) & 0x7) {
1113 case 1: fep->u.ofdm.code_rate_HP = FEC_1_2; break;
1114 case 2: fep->u.ofdm.code_rate_HP = FEC_2_3; break;
1115 case 3: fep->u.ofdm.code_rate_HP = FEC_3_4; break;
1116 case 5: fep->u.ofdm.code_rate_HP = FEC_5_6; break;
1117 case 7:
1118 default: fep->u.ofdm.code_rate_HP = FEC_7_8; break;
1119
1120 }
1121
1122 switch ((tps >> 2) & 0x7) {
1123 case 1: fep->u.ofdm.code_rate_LP = FEC_1_2; break;
1124 case 2: fep->u.ofdm.code_rate_LP = FEC_2_3; break;
1125 case 3: fep->u.ofdm.code_rate_LP = FEC_3_4; break;
1126 case 5: fep->u.ofdm.code_rate_LP = FEC_5_6; break;
1127 case 7:
1128 default: fep->u.ofdm.code_rate_LP = FEC_7_8; break;
1129 }
1130
1131 /* native interleaver: (dib7000p_read_word(state, 464) >> 5) & 0x1 */
1132
1133 return 0;
1134}
1135
1136static int dib7000p_set_frontend(struct dvb_frontend* fe,
1137 struct dvb_frontend_parameters *fep)
1138{
1139 struct dib7000p_state *state = fe->demodulator_priv;
Soeren Moch853ea132008-01-25 06:27:06 -03001140 int time, ret;
Patrick Boettchera75763f2006-10-18 08:34:16 -03001141
Soeren Moch853ea132008-01-25 06:27:06 -03001142 dib7000p_set_output_mode(state, OUTMODE_HIGH_Z);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001143
Patrick Boettcher904a82e2008-01-25 07:31:58 -03001144 /* maybe the parameter has been changed */
Matt Doran8f6956c2007-07-31 07:09:30 -03001145 state->sfn_workaround_active = buggy_sfn_workaround;
1146
Patrick Boettchera75763f2006-10-18 08:34:16 -03001147 if (fe->ops.tuner_ops.set_params)
1148 fe->ops.tuner_ops.set_params(fe, fep);
1149
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001150 /* start up the AGC */
1151 state->agc_state = 0;
1152 do {
1153 time = dib7000p_agc_startup(fe, fep);
1154 if (time != -1)
1155 msleep(time);
1156 } while (time != -1);
1157
Patrick Boettchera75763f2006-10-18 08:34:16 -03001158 if (fep->u.ofdm.transmission_mode == TRANSMISSION_MODE_AUTO ||
1159 fep->u.ofdm.guard_interval == GUARD_INTERVAL_AUTO ||
1160 fep->u.ofdm.constellation == QAM_AUTO ||
1161 fep->u.ofdm.code_rate_HP == FEC_AUTO) {
1162 int i = 800, found;
1163
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001164 dib7000p_autosearch_start(fe, fep);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001165 do {
1166 msleep(1);
1167 found = dib7000p_autosearch_is_irq(fe);
1168 } while (found == 0 && i--);
1169
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001170 dprintk("autosearch returns: %d",found);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001171 if (found == 0 || found == 1)
1172 return 0; // no channel found
1173
1174 dib7000p_get_frontend(fe, fep);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001175 }
1176
Soeren Moch853ea132008-01-25 06:27:06 -03001177 ret = dib7000p_tune(fe, fep);
1178
Patrick Boettchera75763f2006-10-18 08:34:16 -03001179 /* make this a config parameter */
Steven Totha38d6e32008-04-22 15:37:01 -03001180 dib7000p_set_output_mode(state, state->cfg.output_mode);
Soeren Moch853ea132008-01-25 06:27:06 -03001181 return ret;
Patrick Boettchera75763f2006-10-18 08:34:16 -03001182}
1183
1184static int dib7000p_read_status(struct dvb_frontend *fe, fe_status_t *stat)
1185{
1186 struct dib7000p_state *state = fe->demodulator_priv;
1187 u16 lock = dib7000p_read_word(state, 509);
1188
1189 *stat = 0;
1190
1191 if (lock & 0x8000)
1192 *stat |= FE_HAS_SIGNAL;
1193 if (lock & 0x3000)
1194 *stat |= FE_HAS_CARRIER;
1195 if (lock & 0x0100)
1196 *stat |= FE_HAS_VITERBI;
1197 if (lock & 0x0010)
1198 *stat |= FE_HAS_SYNC;
Olivier Grenieeac1fe12009-09-23 13:41:27 -03001199 if ((lock & 0x0038) == 0x38)
Patrick Boettchera75763f2006-10-18 08:34:16 -03001200 *stat |= FE_HAS_LOCK;
1201
1202 return 0;
1203}
1204
1205static int dib7000p_read_ber(struct dvb_frontend *fe, u32 *ber)
1206{
1207 struct dib7000p_state *state = fe->demodulator_priv;
1208 *ber = (dib7000p_read_word(state, 500) << 16) | dib7000p_read_word(state, 501);
1209 return 0;
1210}
1211
1212static int dib7000p_read_unc_blocks(struct dvb_frontend *fe, u32 *unc)
1213{
1214 struct dib7000p_state *state = fe->demodulator_priv;
1215 *unc = dib7000p_read_word(state, 506);
1216 return 0;
1217}
1218
1219static int dib7000p_read_signal_strength(struct dvb_frontend *fe, u16 *strength)
1220{
1221 struct dib7000p_state *state = fe->demodulator_priv;
1222 u16 val = dib7000p_read_word(state, 394);
1223 *strength = 65535 - val;
1224 return 0;
1225}
1226
1227static int dib7000p_read_snr(struct dvb_frontend* fe, u16 *snr)
1228{
Olivier Grenieef801962009-09-15 06:46:52 -03001229 struct dib7000p_state *state = fe->demodulator_priv;
1230 u16 val;
1231 s32 signal_mant, signal_exp, noise_mant, noise_exp;
1232 u32 result = 0;
1233
1234 val = dib7000p_read_word(state, 479);
1235 noise_mant = (val >> 4) & 0xff;
1236 noise_exp = ((val & 0xf) << 2);
1237 val = dib7000p_read_word(state, 480);
1238 noise_exp += ((val >> 14) & 0x3);
1239 if ((noise_exp & 0x20) != 0)
1240 noise_exp -= 0x40;
1241
1242 signal_mant = (val >> 6) & 0xFF;
1243 signal_exp = (val & 0x3F);
1244 if ((signal_exp & 0x20) != 0)
1245 signal_exp -= 0x40;
1246
1247 if (signal_mant != 0)
1248 result = intlog10(2) * 10 * signal_exp + 10 *
1249 intlog10(signal_mant);
1250 else
1251 result = intlog10(2) * 10 * signal_exp - 100;
1252
1253 if (noise_mant != 0)
1254 result -= intlog10(2) * 10 * noise_exp + 10 *
1255 intlog10(noise_mant);
1256 else
1257 result -= intlog10(2) * 10 * noise_exp - 100;
1258
1259 *snr = result / ((1 << 24) / 10);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001260 return 0;
1261}
1262
1263static int dib7000p_fe_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings *tune)
1264{
1265 tune->min_delay_ms = 1000;
1266 return 0;
1267}
1268
1269static void dib7000p_release(struct dvb_frontend *demod)
1270{
1271 struct dib7000p_state *st = demod->demodulator_priv;
1272 dibx000_exit_i2c_master(&st->i2c_master);
1273 kfree(st);
1274}
1275
1276int dib7000pc_detection(struct i2c_adapter *i2c_adap)
1277{
1278 u8 tx[2], rx[2];
1279 struct i2c_msg msg[2] = {
1280 { .addr = 18 >> 1, .flags = 0, .buf = tx, .len = 2 },
1281 { .addr = 18 >> 1, .flags = I2C_M_RD, .buf = rx, .len = 2 },
1282 };
1283
1284 tx[0] = 0x03;
1285 tx[1] = 0x00;
1286
1287 if (i2c_transfer(i2c_adap, msg, 2) == 2)
1288 if (rx[0] == 0x01 && rx[1] == 0xb3) {
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001289 dprintk("-D- DiB7000PC detected");
Patrick Boettchera75763f2006-10-18 08:34:16 -03001290 return 1;
1291 }
1292
1293 msg[0].addr = msg[1].addr = 0x40;
1294
1295 if (i2c_transfer(i2c_adap, msg, 2) == 2)
1296 if (rx[0] == 0x01 && rx[1] == 0xb3) {
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001297 dprintk("-D- DiB7000PC detected");
Patrick Boettchera75763f2006-10-18 08:34:16 -03001298 return 1;
1299 }
1300
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001301 dprintk("-D- DiB7000PC not detected");
Patrick Boettchera75763f2006-10-18 08:34:16 -03001302 return 0;
1303}
1304EXPORT_SYMBOL(dib7000pc_detection);
1305
1306struct i2c_adapter * dib7000p_get_i2c_master(struct dvb_frontend *demod, enum dibx000_i2c_interface intf, int gating)
1307{
1308 struct dib7000p_state *st = demod->demodulator_priv;
1309 return dibx000_get_i2c_adapter(&st->i2c_master, intf, gating);
1310}
1311EXPORT_SYMBOL(dib7000p_get_i2c_master);
1312
Olivier Grenief8731f42009-09-18 04:08:43 -03001313int dib7000p_pid_filter_ctrl(struct dvb_frontend *fe, u8 onoff)
1314{
1315 struct dib7000p_state *state = fe->demodulator_priv;
1316 u16 val = dib7000p_read_word(state, 235) & 0xffef;
1317 val |= (onoff & 0x1) << 4;
1318 dprintk("PID filter enabled %d", onoff);
1319 return dib7000p_write_word(state, 235, val);
1320}
1321EXPORT_SYMBOL(dib7000p_pid_filter_ctrl);
1322
1323int dib7000p_pid_filter(struct dvb_frontend *fe, u8 id, u16 pid, u8 onoff)
1324{
1325 struct dib7000p_state *state = fe->demodulator_priv;
1326 dprintk("PID filter: index %x, PID %d, OnOff %d", id, pid, onoff);
1327 return dib7000p_write_word(state, 241 + id, onoff ? (1 << 13) | pid : 0);
1328}
1329EXPORT_SYMBOL(dib7000p_pid_filter);
1330
Patrick Boettchera75763f2006-10-18 08:34:16 -03001331int dib7000p_i2c_enumeration(struct i2c_adapter *i2c, int no_of_demods, u8 default_addr, struct dib7000p_config cfg[])
1332{
Randy Dunlap30d81bb2010-02-08 20:30:44 -03001333 struct dib7000p_state *dpst;
Patrick Boettchera75763f2006-10-18 08:34:16 -03001334 int k = 0;
1335 u8 new_addr = 0;
1336
Randy Dunlap30d81bb2010-02-08 20:30:44 -03001337 dpst = kzalloc(sizeof(struct dib7000p_state), GFP_KERNEL);
1338 if (!dpst)
Andrew Morton0b427602010-04-27 19:09:45 -03001339 return -ENOMEM;
Randy Dunlap30d81bb2010-02-08 20:30:44 -03001340
1341 dpst->i2c_adap = i2c;
1342
Patrick Boettchera75763f2006-10-18 08:34:16 -03001343 for (k = no_of_demods-1; k >= 0; k--) {
Randy Dunlap30d81bb2010-02-08 20:30:44 -03001344 dpst->cfg = cfg[k];
Patrick Boettchera75763f2006-10-18 08:34:16 -03001345
1346 /* designated i2c address */
1347 new_addr = (0x40 + k) << 1;
Randy Dunlap30d81bb2010-02-08 20:30:44 -03001348 dpst->i2c_addr = new_addr;
1349 dib7000p_write_word(dpst, 1287, 0x0003); /* sram lead in, rdy */
1350 if (dib7000p_identify(dpst) != 0) {
1351 dpst->i2c_addr = default_addr;
1352 dib7000p_write_word(dpst, 1287, 0x0003); /* sram lead in, rdy */
1353 if (dib7000p_identify(dpst) != 0) {
Patrick Boettchera75763f2006-10-18 08:34:16 -03001354 dprintk("DiB7000P #%d: not identified\n", k);
Randy Dunlap30d81bb2010-02-08 20:30:44 -03001355 kfree(dpst);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001356 return -EIO;
1357 }
1358 }
1359
1360 /* start diversity to pull_down div_str - just for i2c-enumeration */
Randy Dunlap30d81bb2010-02-08 20:30:44 -03001361 dib7000p_set_output_mode(dpst, OUTMODE_DIVERSITY);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001362
1363 /* set new i2c address and force divstart */
Randy Dunlap30d81bb2010-02-08 20:30:44 -03001364 dib7000p_write_word(dpst, 1285, (new_addr << 2) | 0x2);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001365
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001366 dprintk("IC %d initialized (to i2c_address 0x%x)", k, new_addr);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001367 }
1368
1369 for (k = 0; k < no_of_demods; k++) {
Randy Dunlap30d81bb2010-02-08 20:30:44 -03001370 dpst->cfg = cfg[k];
1371 dpst->i2c_addr = (0x40 + k) << 1;
Patrick Boettchera75763f2006-10-18 08:34:16 -03001372
1373 // unforce divstr
Randy Dunlap30d81bb2010-02-08 20:30:44 -03001374 dib7000p_write_word(dpst, 1285, dpst->i2c_addr << 2);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001375
1376 /* deactivate div - it was just for i2c-enumeration */
Randy Dunlap30d81bb2010-02-08 20:30:44 -03001377 dib7000p_set_output_mode(dpst, OUTMODE_HIGH_Z);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001378 }
1379
Randy Dunlap30d81bb2010-02-08 20:30:44 -03001380 kfree(dpst);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001381 return 0;
1382}
1383EXPORT_SYMBOL(dib7000p_i2c_enumeration);
1384
1385static struct dvb_frontend_ops dib7000p_ops;
1386struct dvb_frontend * dib7000p_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr, struct dib7000p_config *cfg)
1387{
1388 struct dvb_frontend *demod;
1389 struct dib7000p_state *st;
1390 st = kzalloc(sizeof(struct dib7000p_state), GFP_KERNEL);
1391 if (st == NULL)
1392 return NULL;
1393
1394 memcpy(&st->cfg, cfg, sizeof(struct dib7000p_config));
1395 st->i2c_adap = i2c_adap;
1396 st->i2c_addr = i2c_addr;
1397 st->gpio_val = cfg->gpio_val;
1398 st->gpio_dir = cfg->gpio_dir;
1399
Steven Totha38d6e32008-04-22 15:37:01 -03001400 /* Ensure the output mode remains at the previous default if it's
1401 * not specifically set by the caller.
1402 */
Anton Blanchard8d798982008-08-09 12:23:15 -03001403 if ((st->cfg.output_mode != OUTMODE_MPEG2_SERIAL) &&
1404 (st->cfg.output_mode != OUTMODE_MPEG2_PAR_GATED_CLK))
Steven Totha38d6e32008-04-22 15:37:01 -03001405 st->cfg.output_mode = OUTMODE_MPEG2_FIFO;
1406
Patrick Boettchera75763f2006-10-18 08:34:16 -03001407 demod = &st->demod;
1408 demod->demodulator_priv = st;
1409 memcpy(&st->demod.ops, &dib7000p_ops, sizeof(struct dvb_frontend_ops));
1410
Olivier Grenieeac1fe12009-09-23 13:41:27 -03001411 dib7000p_write_word(st, 1287, 0x0003); /* sram lead in, rdy */
1412
Patrick Boettchera75763f2006-10-18 08:34:16 -03001413 if (dib7000p_identify(st) != 0)
1414 goto error;
1415
Martin Samek7646b9d2009-09-30 22:59:09 -03001416 /* FIXME: make sure the dev.parent field is initialized, or else
1417 request_firmware() will hit an OOPS (this should be moved somewhere
1418 more common) */
1419 st->i2c_master.gated_tuner_i2c_adap.dev.parent = i2c_adap->dev.parent;
1420
Patrick Boettchera75763f2006-10-18 08:34:16 -03001421 dibx000_init_i2c_master(&st->i2c_master, DIB7000P, st->i2c_adap, st->i2c_addr);
1422
1423 dib7000p_demod_reset(st);
1424
1425 return demod;
1426
1427error:
1428 kfree(st);
1429 return NULL;
1430}
1431EXPORT_SYMBOL(dib7000p_attach);
1432
1433static struct dvb_frontend_ops dib7000p_ops = {
1434 .info = {
1435 .name = "DiBcom 7000PC",
1436 .type = FE_OFDM,
1437 .frequency_min = 44250000,
1438 .frequency_max = 867250000,
1439 .frequency_stepsize = 62500,
1440 .caps = FE_CAN_INVERSION_AUTO |
1441 FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
1442 FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
1443 FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO |
1444 FE_CAN_TRANSMISSION_MODE_AUTO |
1445 FE_CAN_GUARD_INTERVAL_AUTO |
1446 FE_CAN_RECOVER |
1447 FE_CAN_HIERARCHY_AUTO,
1448 },
1449
1450 .release = dib7000p_release,
1451
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001452 .init = dib7000p_wakeup,
Patrick Boettchera75763f2006-10-18 08:34:16 -03001453 .sleep = dib7000p_sleep,
1454
1455 .set_frontend = dib7000p_set_frontend,
1456 .get_tune_settings = dib7000p_fe_get_tune_settings,
1457 .get_frontend = dib7000p_get_frontend,
1458
1459 .read_status = dib7000p_read_status,
1460 .read_ber = dib7000p_read_ber,
1461 .read_signal_strength = dib7000p_read_signal_strength,
1462 .read_snr = dib7000p_read_snr,
1463 .read_ucblocks = dib7000p_read_unc_blocks,
1464};
1465
1466MODULE_AUTHOR("Patrick Boettcher <pboettcher@dibcom.fr>");
1467MODULE_DESCRIPTION("Driver for the DiBcom 7000PC COFDM demodulator");
1468MODULE_LICENSE("GPL");