blob: 3ab695b0de3d17a2a6d99a80ce6bbc04386c0685 [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>
Patrick Boettcher79fcce32011-08-03 12:08:21 -030013#include <linux/mutex.h>
Patrick Boettchera75763f2006-10-18 08:34:16 -030014
Olivier Grenieef801962009-09-15 06:46:52 -030015#include "dvb_math.h"
Patrick Boettchera75763f2006-10-18 08:34:16 -030016#include "dvb_frontend.h"
17
18#include "dib7000p.h"
19
20static int debug;
21module_param(debug, int, 0644);
22MODULE_PARM_DESC(debug, "turn on debugging (default: 0)");
23
Matt Doran8f6956c2007-07-31 07:09:30 -030024static int buggy_sfn_workaround;
25module_param(buggy_sfn_workaround, int, 0644);
Patrick Boettcher8d999962007-07-31 10:36:06 -030026MODULE_PARM_DESC(buggy_sfn_workaround, "Enable work-around for buggy SFNs (default: 0)");
Matt Doran8f6956c2007-07-31 07:09:30 -030027
Patrick Boettcherb6884a12007-07-27 10:08:51 -030028#define dprintk(args...) do { if (debug) { printk(KERN_DEBUG "DiB7000P: "); printk(args); printk("\n"); } } while (0)
Patrick Boettchera75763f2006-10-18 08:34:16 -030029
Olivier Grenie713d54a2011-01-04 04:54:31 -030030struct i2c_device {
31 struct i2c_adapter *i2c_adap;
32 u8 i2c_addr;
33};
34
Patrick Boettchera75763f2006-10-18 08:34:16 -030035struct dib7000p_state {
36 struct dvb_frontend demod;
Olivier Grenie713d54a2011-01-04 04:54:31 -030037 struct dib7000p_config cfg;
Patrick Boettchera75763f2006-10-18 08:34:16 -030038
39 u8 i2c_addr;
Olivier Grenie713d54a2011-01-04 04:54:31 -030040 struct i2c_adapter *i2c_adap;
Patrick Boettchera75763f2006-10-18 08:34:16 -030041
42 struct dibx000_i2c_master i2c_master;
43
44 u16 wbd_ref;
45
Olivier Grenie713d54a2011-01-04 04:54:31 -030046 u8 current_band;
Patrick Boettcher904a82e2008-01-25 07:31:58 -030047 u32 current_bandwidth;
Patrick Boettchera75763f2006-10-18 08:34:16 -030048 struct dibx000_agc_config *current_agc;
49 u32 timf;
50
Olivier Grenie713d54a2011-01-04 04:54:31 -030051 u8 div_force_off:1;
52 u8 div_state:1;
Patrick Boettcher01373a52007-07-30 12:49:04 -030053 u16 div_sync_wait;
Patrick Boettcherb6884a12007-07-27 10:08:51 -030054
55 u8 agc_state;
56
Patrick Boettchera75763f2006-10-18 08:34:16 -030057 u16 gpio_dir;
58 u16 gpio_val;
Matt Doran8f6956c2007-07-31 07:09:30 -030059
Olivier Grenie713d54a2011-01-04 04:54:31 -030060 u8 sfn_workaround_active:1;
61
62#define SOC7090 0x7090
63 u16 version;
64
65 u16 tuner_enable;
66 struct i2c_adapter dib7090_tuner_adap;
Olivier Grenie5a0deee2011-05-03 12:27:33 -030067
68 /* for the I2C transfer */
69 struct i2c_msg msg[2];
70 u8 i2c_write_buffer[4];
71 u8 i2c_read_buffer[2];
Patrick Boettcher79fcce32011-08-03 12:08:21 -030072 struct mutex i2c_buffer_lock;
Olivier Grenie2e802862011-08-05 10:39:15 -030073
74 u8 input_mode_mpeg;
Patrick Boettchera75763f2006-10-18 08:34:16 -030075};
76
77enum dib7000p_power_mode {
78 DIB7000P_POWER_ALL = 0,
Patrick Boettcherb6884a12007-07-27 10:08:51 -030079 DIB7000P_POWER_ANALOG_ADC,
Patrick Boettchera75763f2006-10-18 08:34:16 -030080 DIB7000P_POWER_INTERFACE_ONLY,
81};
82
Olivier Grenie2e802862011-08-05 10:39:15 -030083/* dib7090 specific fonctions */
84#define MPEG_ON_DIBTX 1
85#define DIV_ON_DIBTX 2
86#define ADC_ON_DIBTX 3
87#define DEMOUT_ON_HOSTBUS 4
88#define DIBTX_ON_HOSTBUS 5
89#define MPEG_ON_HOSTBUS 6
90
Olivier Grenie713d54a2011-01-04 04:54:31 -030091static int dib7090_set_output_mode(struct dvb_frontend *fe, int mode);
92static int dib7090_set_diversity_in(struct dvb_frontend *fe, int onoff);
Olivier Grenie2e802862011-08-05 10:39:15 -030093static void dib7090_setDibTxMux(struct dib7000p_state *state, int mode);
94static void dib7090_setHostBusMux(struct dib7000p_state *state, int mode);
Olivier Grenie713d54a2011-01-04 04:54:31 -030095
Patrick Boettchera75763f2006-10-18 08:34:16 -030096static u16 dib7000p_read_word(struct dib7000p_state *state, u16 reg)
97{
Patrick Boettcher79fcce32011-08-03 12:08:21 -030098 u16 ret;
99
100 if (mutex_lock_interruptible(&state->i2c_buffer_lock) < 0) {
101 dprintk("could not acquire lock");
102 return 0;
103 }
104
Olivier Grenie5a0deee2011-05-03 12:27:33 -0300105 state->i2c_write_buffer[0] = reg >> 8;
106 state->i2c_write_buffer[1] = reg & 0xff;
Patrick Boettchera75763f2006-10-18 08:34:16 -0300107
Olivier Grenie5a0deee2011-05-03 12:27:33 -0300108 memset(state->msg, 0, 2 * sizeof(struct i2c_msg));
109 state->msg[0].addr = state->i2c_addr >> 1;
110 state->msg[0].flags = 0;
111 state->msg[0].buf = state->i2c_write_buffer;
112 state->msg[0].len = 2;
113 state->msg[1].addr = state->i2c_addr >> 1;
114 state->msg[1].flags = I2C_M_RD;
115 state->msg[1].buf = state->i2c_read_buffer;
116 state->msg[1].len = 2;
117
118 if (i2c_transfer(state->i2c_adap, state->msg, 2) != 2)
Olivier Grenie713d54a2011-01-04 04:54:31 -0300119 dprintk("i2c read error on %d", reg);
Patrick Boettchera75763f2006-10-18 08:34:16 -0300120
Patrick Boettcher79fcce32011-08-03 12:08:21 -0300121 ret = (state->i2c_read_buffer[0] << 8) | state->i2c_read_buffer[1];
122 mutex_unlock(&state->i2c_buffer_lock);
123 return ret;
Patrick Boettchera75763f2006-10-18 08:34:16 -0300124}
125
126static int dib7000p_write_word(struct dib7000p_state *state, u16 reg, u16 val)
127{
Patrick Boettcher79fcce32011-08-03 12:08:21 -0300128 int ret;
129
130 if (mutex_lock_interruptible(&state->i2c_buffer_lock) < 0) {
131 dprintk("could not acquire lock");
132 return -EINVAL;
133 }
134
Olivier Grenie5a0deee2011-05-03 12:27:33 -0300135 state->i2c_write_buffer[0] = (reg >> 8) & 0xff;
136 state->i2c_write_buffer[1] = reg & 0xff;
137 state->i2c_write_buffer[2] = (val >> 8) & 0xff;
138 state->i2c_write_buffer[3] = val & 0xff;
139
140 memset(&state->msg[0], 0, sizeof(struct i2c_msg));
141 state->msg[0].addr = state->i2c_addr >> 1;
142 state->msg[0].flags = 0;
143 state->msg[0].buf = state->i2c_write_buffer;
144 state->msg[0].len = 4;
145
Patrick Boettcher79fcce32011-08-03 12:08:21 -0300146 ret = (i2c_transfer(state->i2c_adap, state->msg, 1) != 1 ?
147 -EREMOTEIO : 0);
148 mutex_unlock(&state->i2c_buffer_lock);
149 return ret;
Patrick Boettchera75763f2006-10-18 08:34:16 -0300150}
Olivier Grenie713d54a2011-01-04 04:54:31 -0300151
152static void dib7000p_write_tab(struct dib7000p_state *state, u16 * buf)
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300153{
154 u16 l = 0, r, *n;
155 n = buf;
156 l = *n++;
157 while (l) {
158 r = *n++;
159
160 do {
161 dib7000p_write_word(state, r, *n++);
162 r++;
163 } while (--l);
164 l = *n++;
165 }
166}
167
Patrick Boettchera75763f2006-10-18 08:34:16 -0300168static int dib7000p_set_output_mode(struct dib7000p_state *state, int mode)
169{
Olivier Grenie713d54a2011-01-04 04:54:31 -0300170 int ret = 0;
Patrick Boettchera75763f2006-10-18 08:34:16 -0300171 u16 outreg, fifo_threshold, smo_mode;
172
173 outreg = 0;
174 fifo_threshold = 1792;
Olivier Grenieeac1fe12009-09-23 13:41:27 -0300175 smo_mode = (dib7000p_read_word(state, 235) & 0x0050) | (1 << 1);
Patrick Boettchera75763f2006-10-18 08:34:16 -0300176
Olivier Grenie713d54a2011-01-04 04:54:31 -0300177 dprintk("setting output mode for demod %p to %d", &state->demod, mode);
Patrick Boettchera75763f2006-10-18 08:34:16 -0300178
179 switch (mode) {
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300180 case OUTMODE_MPEG2_PAR_GATED_CLK:
Olivier Grenie713d54a2011-01-04 04:54:31 -0300181 outreg = (1 << 10); /* 0x0400 */
182 break;
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300183 case OUTMODE_MPEG2_PAR_CONT_CLK:
Olivier Grenie713d54a2011-01-04 04:54:31 -0300184 outreg = (1 << 10) | (1 << 6); /* 0x0440 */
185 break;
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300186 case OUTMODE_MPEG2_SERIAL:
Olivier Grenie713d54a2011-01-04 04:54:31 -0300187 outreg = (1 << 10) | (2 << 6) | (0 << 1); /* 0x0480 */
188 break;
189 case OUTMODE_DIVERSITY:
190 if (state->cfg.hostbus_diversity)
191 outreg = (1 << 10) | (4 << 6); /* 0x0500 */
192 else
193 outreg = (1 << 11);
194 break;
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300195 case OUTMODE_MPEG2_FIFO:
Olivier Grenie713d54a2011-01-04 04:54:31 -0300196 smo_mode |= (3 << 1);
197 fifo_threshold = 512;
198 outreg = (1 << 10) | (5 << 6);
199 break;
200 case OUTMODE_ANALOG_ADC:
201 outreg = (1 << 10) | (3 << 6);
202 break;
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300203 case OUTMODE_HIGH_Z:
Olivier Grenie713d54a2011-01-04 04:54:31 -0300204 outreg = 0;
205 break;
206 default:
207 dprintk("Unhandled output_mode passed to be set for demod %p", &state->demod);
208 break;
Patrick Boettchera75763f2006-10-18 08:34:16 -0300209 }
210
211 if (state->cfg.output_mpeg2_in_188_bytes)
Olivier Grenie713d54a2011-01-04 04:54:31 -0300212 smo_mode |= (1 << 5);
Patrick Boettchera75763f2006-10-18 08:34:16 -0300213
Olivier Grenie713d54a2011-01-04 04:54:31 -0300214 ret |= dib7000p_write_word(state, 235, smo_mode);
215 ret |= dib7000p_write_word(state, 236, fifo_threshold); /* synchronous fread */
216 if (state->version != SOC7090)
217 ret |= dib7000p_write_word(state, 1286, outreg); /* P_Div_active */
Patrick Boettchera75763f2006-10-18 08:34:16 -0300218
219 return ret;
220}
221
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300222static int dib7000p_set_diversity_in(struct dvb_frontend *demod, int onoff)
223{
224 struct dib7000p_state *state = demod->demodulator_priv;
225
226 if (state->div_force_off) {
Olivier Grenie713d54a2011-01-04 04:54:31 -0300227 dprintk("diversity combination deactivated - forced by COFDM parameters");
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300228 onoff = 0;
Olivier Grenieeac1fe12009-09-23 13:41:27 -0300229 dib7000p_write_word(state, 207, 0);
230 } else
231 dib7000p_write_word(state, 207, (state->div_sync_wait << 4) | (1 << 2) | (2 << 0));
232
Olivier Grenie713d54a2011-01-04 04:54:31 -0300233 state->div_state = (u8) onoff;
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300234
235 if (onoff) {
236 dib7000p_write_word(state, 204, 6);
237 dib7000p_write_word(state, 205, 16);
238 /* P_dvsy_sync_mode = 0, P_dvsy_sync_enable=1, P_dvcb_comb_mode=2 */
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300239 } else {
240 dib7000p_write_word(state, 204, 1);
241 dib7000p_write_word(state, 205, 0);
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300242 }
243
244 return 0;
245}
246
Patrick Boettchera75763f2006-10-18 08:34:16 -0300247static int dib7000p_set_power_mode(struct dib7000p_state *state, enum dib7000p_power_mode mode)
248{
249 /* by default everything is powered off */
Olivier Grenie713d54a2011-01-04 04:54:31 -0300250 u16 reg_774 = 0x3fff, reg_775 = 0xffff, reg_776 = 0x0007, reg_899 = 0x0003, reg_1280 = (0xfe00) | (dib7000p_read_word(state, 1280) & 0x01ff);
Patrick Boettchera75763f2006-10-18 08:34:16 -0300251
252 /* now, depending on the requested mode, we power on */
253 switch (mode) {
254 /* power up everything in the demod */
Olivier Grenie713d54a2011-01-04 04:54:31 -0300255 case DIB7000P_POWER_ALL:
256 reg_774 = 0x0000;
257 reg_775 = 0x0000;
258 reg_776 = 0x0;
259 reg_899 = 0x0;
260 if (state->version == SOC7090)
261 reg_1280 &= 0x001f;
262 else
263 reg_1280 &= 0x01ff;
264 break;
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300265
Olivier Grenie713d54a2011-01-04 04:54:31 -0300266 case DIB7000P_POWER_ANALOG_ADC:
267 /* dem, cfg, iqc, sad, agc */
268 reg_774 &= ~((1 << 15) | (1 << 14) | (1 << 11) | (1 << 10) | (1 << 9));
269 /* nud */
270 reg_776 &= ~((1 << 0));
271 /* Dout */
272 if (state->version != SOC7090)
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300273 reg_1280 &= ~((1 << 11));
Olivier Grenie713d54a2011-01-04 04:54:31 -0300274 reg_1280 &= ~(1 << 6);
275 /* fall through wanted to enable the interfaces */
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300276
Patrick Boettchera75763f2006-10-18 08:34:16 -0300277 /* just leave power on the control-interfaces: GPIO and (I2C or SDIO) */
Olivier Grenie713d54a2011-01-04 04:54:31 -0300278 case DIB7000P_POWER_INTERFACE_ONLY: /* TODO power up either SDIO or I2C */
279 if (state->version == SOC7090)
280 reg_1280 &= ~((1 << 7) | (1 << 5));
281 else
Patrick Boettchera75763f2006-10-18 08:34:16 -0300282 reg_1280 &= ~((1 << 14) | (1 << 13) | (1 << 12) | (1 << 10));
Olivier Grenie713d54a2011-01-04 04:54:31 -0300283 break;
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300284
Patrick Boettchera75763f2006-10-18 08:34:16 -0300285/* TODO following stuff is just converted from the dib7000-driver - check when is used what */
286 }
287
Olivier Grenie713d54a2011-01-04 04:54:31 -0300288 dib7000p_write_word(state, 774, reg_774);
289 dib7000p_write_word(state, 775, reg_775);
290 dib7000p_write_word(state, 776, reg_776);
Patrick Boettchera75763f2006-10-18 08:34:16 -0300291 dib7000p_write_word(state, 1280, reg_1280);
Olivier Grenie2e802862011-08-05 10:39:15 -0300292 if (state->version != SOC7090)
293 dib7000p_write_word(state, 899, reg_899);
Patrick Boettchera75763f2006-10-18 08:34:16 -0300294
295 return 0;
296}
297
298static void dib7000p_set_adc_state(struct dib7000p_state *state, enum dibx000_adc_states no)
299{
Olivier Grenie2e802862011-08-05 10:39:15 -0300300 u16 reg_908 = 0, reg_909 = 0;
Olivier Grenie713d54a2011-01-04 04:54:31 -0300301 u16 reg;
Patrick Boettchera75763f2006-10-18 08:34:16 -0300302
Olivier Grenie2e802862011-08-05 10:39:15 -0300303 if (state->version != SOC7090) {
304 reg_908 = dib7000p_read_word(state, 908);
305 reg_909 = dib7000p_read_word(state, 909);
306 }
307
Patrick Boettchera75763f2006-10-18 08:34:16 -0300308 switch (no) {
Olivier Grenie713d54a2011-01-04 04:54:31 -0300309 case DIBX000_SLOW_ADC_ON:
310 if (state->version == SOC7090) {
311 reg = dib7000p_read_word(state, 1925);
312
313 dib7000p_write_word(state, 1925, reg | (1 << 4) | (1 << 2)); /* en_slowAdc = 1 & reset_sladc = 1 */
314
315 reg = dib7000p_read_word(state, 1925); /* read acces to make it works... strange ... */
316 msleep(200);
317 dib7000p_write_word(state, 1925, reg & ~(1 << 4)); /* en_slowAdc = 1 & reset_sladc = 0 */
318
319 reg = dib7000p_read_word(state, 72) & ~((0x3 << 14) | (0x3 << 12));
320 dib7000p_write_word(state, 72, reg | (1 << 14) | (3 << 12) | 524); /* ref = Vin1 => Vbg ; sel = Vin0 or Vin3 ; (Vin2 = Vcm) */
321 } else {
Patrick Boettchera75763f2006-10-18 08:34:16 -0300322 reg_909 |= (1 << 1) | (1 << 0);
323 dib7000p_write_word(state, 909, reg_909);
324 reg_909 &= ~(1 << 1);
Olivier Grenie713d54a2011-01-04 04:54:31 -0300325 }
326 break;
Patrick Boettchera75763f2006-10-18 08:34:16 -0300327
Olivier Grenie713d54a2011-01-04 04:54:31 -0300328 case DIBX000_SLOW_ADC_OFF:
329 if (state->version == SOC7090) {
330 reg = dib7000p_read_word(state, 1925);
331 dib7000p_write_word(state, 1925, (reg & ~(1 << 2)) | (1 << 4)); /* reset_sladc = 1 en_slowAdc = 0 */
332 } else
333 reg_909 |= (1 << 1) | (1 << 0);
334 break;
Patrick Boettchera75763f2006-10-18 08:34:16 -0300335
Olivier Grenie713d54a2011-01-04 04:54:31 -0300336 case DIBX000_ADC_ON:
337 reg_908 &= 0x0fff;
338 reg_909 &= 0x0003;
339 break;
Patrick Boettchera75763f2006-10-18 08:34:16 -0300340
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300341 case DIBX000_ADC_OFF:
Olivier Grenie713d54a2011-01-04 04:54:31 -0300342 reg_908 |= (1 << 14) | (1 << 13) | (1 << 12);
343 reg_909 |= (1 << 5) | (1 << 4) | (1 << 3) | (1 << 2);
344 break;
Patrick Boettchera75763f2006-10-18 08:34:16 -0300345
Olivier Grenie713d54a2011-01-04 04:54:31 -0300346 case DIBX000_VBG_ENABLE:
347 reg_908 &= ~(1 << 15);
348 break;
Patrick Boettchera75763f2006-10-18 08:34:16 -0300349
Olivier Grenie713d54a2011-01-04 04:54:31 -0300350 case DIBX000_VBG_DISABLE:
351 reg_908 |= (1 << 15);
352 break;
Patrick Boettchera75763f2006-10-18 08:34:16 -0300353
Olivier Grenie713d54a2011-01-04 04:54:31 -0300354 default:
355 break;
Patrick Boettchera75763f2006-10-18 08:34:16 -0300356 }
357
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300358// dprintk( "908: %x, 909: %x\n", reg_908, reg_909);
Patrick Boettchera75763f2006-10-18 08:34:16 -0300359
Olivier Grenie970d14c2010-09-07 12:50:46 -0300360 reg_909 |= (state->cfg.disable_sample_and_hold & 1) << 4;
Olivier Grenie90e12ce2010-09-07 12:50:45 -0300361 reg_908 |= (state->cfg.enable_current_mirror & 1) << 7;
362
Olivier Grenie2e802862011-08-05 10:39:15 -0300363 if (state->version != SOC7090) {
364 dib7000p_write_word(state, 908, reg_908);
365 dib7000p_write_word(state, 909, reg_909);
366 }
Patrick Boettchera75763f2006-10-18 08:34:16 -0300367}
368
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300369static int dib7000p_set_bandwidth(struct dib7000p_state *state, u32 bw)
Patrick Boettchera75763f2006-10-18 08:34:16 -0300370{
Patrick Boettchera75763f2006-10-18 08:34:16 -0300371 u32 timf;
372
373 // store the current bandwidth for later use
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300374 state->current_bandwidth = bw;
Patrick Boettchera75763f2006-10-18 08:34:16 -0300375
376 if (state->timf == 0) {
Olivier Grenie713d54a2011-01-04 04:54:31 -0300377 dprintk("using default timf");
Patrick Boettchera75763f2006-10-18 08:34:16 -0300378 timf = state->cfg.bw->timf;
379 } else {
Olivier Grenie713d54a2011-01-04 04:54:31 -0300380 dprintk("using updated timf");
Patrick Boettchera75763f2006-10-18 08:34:16 -0300381 timf = state->timf;
382 }
383
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300384 timf = timf * (bw / 50) / 160;
Patrick Boettchera75763f2006-10-18 08:34:16 -0300385
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300386 dib7000p_write_word(state, 23, (u16) ((timf >> 16) & 0xffff));
Olivier Grenie713d54a2011-01-04 04:54:31 -0300387 dib7000p_write_word(state, 24, (u16) ((timf) & 0xffff));
Patrick Boettchera75763f2006-10-18 08:34:16 -0300388
389 return 0;
390}
391
392static int dib7000p_sad_calib(struct dib7000p_state *state)
393{
394/* internal */
Patrick Boettchera75763f2006-10-18 08:34:16 -0300395 dib7000p_write_word(state, 73, (0 << 1) | (0 << 0));
Olivier Grenie713d54a2011-01-04 04:54:31 -0300396
397 if (state->version == SOC7090)
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300398 dib7000p_write_word(state, 74, 2048);
Olivier Grenie713d54a2011-01-04 04:54:31 -0300399 else
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300400 dib7000p_write_word(state, 74, 776);
Patrick Boettchera75763f2006-10-18 08:34:16 -0300401
402 /* do the calibration */
403 dib7000p_write_word(state, 73, (1 << 0));
404 dib7000p_write_word(state, 73, (0 << 0));
405
406 msleep(1);
407
408 return 0;
409}
410
Patrick Boettcher01373a52007-07-30 12:49:04 -0300411int dib7000p_set_wbd_ref(struct dvb_frontend *demod, u16 value)
412{
413 struct dib7000p_state *state = demod->demodulator_priv;
414 if (value > 4095)
415 value = 4095;
416 state->wbd_ref = value;
417 return dib7000p_write_word(state, 105, (dib7000p_read_word(state, 105) & 0xf000) | value);
418}
Patrick Boettcher01373a52007-07-30 12:49:04 -0300419EXPORT_SYMBOL(dib7000p_set_wbd_ref);
Olivier Grenie713d54a2011-01-04 04:54:31 -0300420
Olivier Grenie6724a2f2011-08-05 13:49:33 -0300421int dib7000p_get_agc_values(struct dvb_frontend *fe,
422 u16 *agc_global, u16 *agc1, u16 *agc2, u16 *wbd)
423{
424 struct dib7000p_state *state = fe->demodulator_priv;
425
426 if (agc_global != NULL)
427 *agc_global = dib7000p_read_word(state, 394);
428 if (agc1 != NULL)
429 *agc1 = dib7000p_read_word(state, 392);
430 if (agc2 != NULL)
431 *agc2 = dib7000p_read_word(state, 393);
432 if (wbd != NULL)
433 *wbd = dib7000p_read_word(state, 397);
434
435 return 0;
436}
437EXPORT_SYMBOL(dib7000p_get_agc_values);
438
Patrick Boettchera75763f2006-10-18 08:34:16 -0300439static void dib7000p_reset_pll(struct dib7000p_state *state)
440{
441 struct dibx000_bandwidth_config *bw = &state->cfg.bw[0];
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300442 u16 clk_cfg0;
Patrick Boettchera75763f2006-10-18 08:34:16 -0300443
Olivier Grenie713d54a2011-01-04 04:54:31 -0300444 if (state->version == SOC7090) {
445 dib7000p_write_word(state, 1856, (!bw->pll_reset << 13) | (bw->pll_range << 12) | (bw->pll_ratio << 6) | (bw->pll_prediv));
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300446
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300447 while (((dib7000p_read_word(state, 1856) >> 15) & 0x1) != 1)
448 ;
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300449
Olivier Grenie713d54a2011-01-04 04:54:31 -0300450 dib7000p_write_word(state, 1857, dib7000p_read_word(state, 1857) | (!bw->pll_bypass << 15));
451 } else {
452 /* force PLL bypass */
453 clk_cfg0 = (1 << 15) | ((bw->pll_ratio & 0x3f) << 9) |
454 (bw->modulo << 7) | (bw->ADClkSrc << 6) | (bw->IO_CLK_en_core << 5) | (bw->bypclk_div << 2) | (bw->enable_refdiv << 1) | (0 << 0);
Patrick Boettchera75763f2006-10-18 08:34:16 -0300455
Olivier Grenie713d54a2011-01-04 04:54:31 -0300456 dib7000p_write_word(state, 900, clk_cfg0);
457
458 /* P_pll_cfg */
459 dib7000p_write_word(state, 903, (bw->pll_prediv << 5) | (((bw->pll_ratio >> 6) & 0x3) << 3) | (bw->pll_range << 1) | bw->pll_reset);
460 clk_cfg0 = (bw->pll_bypass << 15) | (clk_cfg0 & 0x7fff);
461 dib7000p_write_word(state, 900, clk_cfg0);
462 }
463
464 dib7000p_write_word(state, 18, (u16) (((bw->internal * 1000) >> 16) & 0xffff));
465 dib7000p_write_word(state, 19, (u16) ((bw->internal * 1000) & 0xffff));
466 dib7000p_write_word(state, 21, (u16) ((bw->ifreq >> 16) & 0xffff));
467 dib7000p_write_word(state, 22, (u16) ((bw->ifreq) & 0xffff));
Patrick Boettchera75763f2006-10-18 08:34:16 -0300468
469 dib7000p_write_word(state, 72, bw->sad_cfg);
470}
471
Olivier Grenie713d54a2011-01-04 04:54:31 -0300472static u32 dib7000p_get_internal_freq(struct dib7000p_state *state)
473{
474 u32 internal = (u32) dib7000p_read_word(state, 18) << 16;
475 internal |= (u32) dib7000p_read_word(state, 19);
476 internal /= 1000;
477
478 return internal;
479}
480
481int dib7000p_update_pll(struct dvb_frontend *fe, struct dibx000_bandwidth_config *bw)
482{
483 struct dib7000p_state *state = fe->demodulator_priv;
484 u16 reg_1857, reg_1856 = dib7000p_read_word(state, 1856);
485 u8 loopdiv, prediv;
486 u32 internal, xtal;
487
488 /* get back old values */
489 prediv = reg_1856 & 0x3f;
490 loopdiv = (reg_1856 >> 6) & 0x3f;
491
492 if ((bw != NULL) && (bw->pll_prediv != prediv || bw->pll_ratio != loopdiv)) {
493 dprintk("Updating pll (prediv: old = %d new = %d ; loopdiv : old = %d new = %d)", prediv, bw->pll_prediv, loopdiv, bw->pll_ratio);
494 reg_1856 &= 0xf000;
495 reg_1857 = dib7000p_read_word(state, 1857);
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300496 dib7000p_write_word(state, 1857, reg_1857 & ~(1 << 15));
Olivier Grenie713d54a2011-01-04 04:54:31 -0300497
498 dib7000p_write_word(state, 1856, reg_1856 | ((bw->pll_ratio & 0x3f) << 6) | (bw->pll_prediv & 0x3f));
499
500 /* write new system clk into P_sec_len */
501 internal = dib7000p_get_internal_freq(state);
502 xtal = (internal / loopdiv) * prediv;
503 internal = 1000 * (xtal / bw->pll_prediv) * bw->pll_ratio; /* new internal */
504 dib7000p_write_word(state, 18, (u16) ((internal >> 16) & 0xffff));
505 dib7000p_write_word(state, 19, (u16) (internal & 0xffff));
506
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300507 dib7000p_write_word(state, 1857, reg_1857 | (1 << 15));
Olivier Grenie713d54a2011-01-04 04:54:31 -0300508
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300509 while (((dib7000p_read_word(state, 1856) >> 15) & 0x1) != 1)
Olivier Grenie713d54a2011-01-04 04:54:31 -0300510 dprintk("Waiting for PLL to lock");
Olivier Grenie713d54a2011-01-04 04:54:31 -0300511
512 return 0;
513 }
514 return -EIO;
515}
516EXPORT_SYMBOL(dib7000p_update_pll);
517
Patrick Boettchera75763f2006-10-18 08:34:16 -0300518static int dib7000p_reset_gpio(struct dib7000p_state *st)
519{
520 /* reset the GPIOs */
Olivier Grenie713d54a2011-01-04 04:54:31 -0300521 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 -0300522
523 dib7000p_write_word(st, 1029, st->gpio_dir);
524 dib7000p_write_word(st, 1030, st->gpio_val);
525
526 /* TODO 1031 is P_gpio_od */
527
528 dib7000p_write_word(st, 1032, st->cfg.gpio_pwm_pos);
529
530 dib7000p_write_word(st, 1037, st->cfg.pwm_freq_div);
531 return 0;
532}
533
Patrick Boettcher01373a52007-07-30 12:49:04 -0300534static int dib7000p_cfg_gpio(struct dib7000p_state *st, u8 num, u8 dir, u8 val)
535{
536 st->gpio_dir = dib7000p_read_word(st, 1029);
Olivier Grenie713d54a2011-01-04 04:54:31 -0300537 st->gpio_dir &= ~(1 << num); /* reset the direction bit */
538 st->gpio_dir |= (dir & 0x1) << num; /* set the new direction */
Patrick Boettcher01373a52007-07-30 12:49:04 -0300539 dib7000p_write_word(st, 1029, st->gpio_dir);
540
541 st->gpio_val = dib7000p_read_word(st, 1030);
Olivier Grenie713d54a2011-01-04 04:54:31 -0300542 st->gpio_val &= ~(1 << num); /* reset the direction bit */
543 st->gpio_val |= (val & 0x01) << num; /* set the new value */
Patrick Boettcher01373a52007-07-30 12:49:04 -0300544 dib7000p_write_word(st, 1030, st->gpio_val);
545
546 return 0;
547}
548
549int dib7000p_set_gpio(struct dvb_frontend *demod, u8 num, u8 dir, u8 val)
550{
551 struct dib7000p_state *state = demod->demodulator_priv;
552 return dib7000p_cfg_gpio(state, num, dir, val);
553}
Patrick Boettcher01373a52007-07-30 12:49:04 -0300554EXPORT_SYMBOL(dib7000p_set_gpio);
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300555
Olivier Grenie713d54a2011-01-04 04:54:31 -0300556static u16 dib7000p_defaults[] = {
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300557 // auto search configuration
558 3, 2,
Olivier Grenie713d54a2011-01-04 04:54:31 -0300559 0x0004,
Olivier Grenie2e802862011-08-05 10:39:15 -0300560 (1<<3)|(1<<11)|(1<<12)|(1<<13),
Olivier Grenie713d54a2011-01-04 04:54:31 -0300561 0x0814, /* Equal Lock */
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300562
563 12, 6,
Olivier Grenie713d54a2011-01-04 04:54:31 -0300564 0x001b,
565 0x7740,
566 0x005b,
567 0x8d80,
568 0x01c9,
569 0xc380,
570 0x0000,
571 0x0080,
572 0x0000,
573 0x0090,
574 0x0001,
575 0xd4c0,
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300576
577 1, 26,
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300578 0x6680,
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300579
580 /* set ADC level to -16 */
581 11, 79,
Olivier Grenie713d54a2011-01-04 04:54:31 -0300582 (1 << 13) - 825 - 117,
583 (1 << 13) - 837 - 117,
584 (1 << 13) - 811 - 117,
585 (1 << 13) - 766 - 117,
586 (1 << 13) - 737 - 117,
587 (1 << 13) - 693 - 117,
588 (1 << 13) - 648 - 117,
589 (1 << 13) - 619 - 117,
590 (1 << 13) - 575 - 117,
591 (1 << 13) - 531 - 117,
592 (1 << 13) - 501 - 117,
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300593
594 1, 142,
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300595 0x0410,
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300596
597 /* disable power smoothing */
598 8, 145,
Olivier Grenie713d54a2011-01-04 04:54:31 -0300599 0,
600 0,
601 0,
602 0,
603 0,
604 0,
605 0,
606 0,
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300607
608 1, 154,
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300609 1 << 13,
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300610
611 1, 168,
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300612 0x0ccd,
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300613
614 1, 183,
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300615 0x200f,
Olivier Grenie713d54a2011-01-04 04:54:31 -0300616
617 1, 212,
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300618 0x169,
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300619
620 5, 187,
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300621 0x023d,
622 0x00a4,
623 0x00a4,
624 0x7ff0,
625 0x3ccc,
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300626
627 1, 198,
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300628 0x800,
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300629
630 1, 222,
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300631 0x0010,
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300632
633 1, 235,
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300634 0x0062,
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300635
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300636 0,
637};
638
Patrick Boettchera75763f2006-10-18 08:34:16 -0300639static int dib7000p_demod_reset(struct dib7000p_state *state)
640{
641 dib7000p_set_power_mode(state, DIB7000P_POWER_ALL);
642
Olivier Grenie713d54a2011-01-04 04:54:31 -0300643 if (state->version == SOC7090)
644 dibx000_reset_i2c_master(&state->i2c_master);
645
Patrick Boettchera75763f2006-10-18 08:34:16 -0300646 dib7000p_set_adc_state(state, DIBX000_VBG_ENABLE);
647
648 /* restart all parts */
Olivier Grenie713d54a2011-01-04 04:54:31 -0300649 dib7000p_write_word(state, 770, 0xffff);
650 dib7000p_write_word(state, 771, 0xffff);
651 dib7000p_write_word(state, 772, 0x001f);
Olivier Grenie713d54a2011-01-04 04:54:31 -0300652 dib7000p_write_word(state, 1280, 0x001f - ((1 << 4) | (1 << 3)));
Patrick Boettchera75763f2006-10-18 08:34:16 -0300653
Olivier Grenie713d54a2011-01-04 04:54:31 -0300654 dib7000p_write_word(state, 770, 0);
655 dib7000p_write_word(state, 771, 0);
656 dib7000p_write_word(state, 772, 0);
Patrick Boettchera75763f2006-10-18 08:34:16 -0300657 dib7000p_write_word(state, 1280, 0);
658
Olivier Grenie2e802862011-08-05 10:39:15 -0300659 if (state->version != SOC7090) {
660 dib7000p_write_word(state, 898, 0x0003);
661 dib7000p_write_word(state, 898, 0);
662 }
663
Patrick Boettchera75763f2006-10-18 08:34:16 -0300664 /* default */
665 dib7000p_reset_pll(state);
666
667 if (dib7000p_reset_gpio(state) != 0)
Olivier Grenie713d54a2011-01-04 04:54:31 -0300668 dprintk("GPIO reset was not successful.");
Patrick Boettchera75763f2006-10-18 08:34:16 -0300669
Olivier Grenie713d54a2011-01-04 04:54:31 -0300670 if (state->version == SOC7090) {
671 dib7000p_write_word(state, 899, 0);
672
673 /* impulse noise */
674 dib7000p_write_word(state, 42, (1<<5) | 3); /* P_iqc_thsat_ipc = 1 ; P_iqc_win2 = 3 */
675 dib7000p_write_word(state, 43, 0x2d4); /*-300 fag P_iqc_dect_min = -280 */
676 dib7000p_write_word(state, 44, 300); /* 300 fag P_iqc_dect_min = +280 */
Olivier Grenie2e802862011-08-05 10:39:15 -0300677 dib7000p_write_word(state, 273, (0<<6) | 30);
Olivier Grenie713d54a2011-01-04 04:54:31 -0300678 }
Patrick Boettchera75763f2006-10-18 08:34:16 -0300679 if (dib7000p_set_output_mode(state, OUTMODE_HIGH_Z) != 0)
Olivier Grenie713d54a2011-01-04 04:54:31 -0300680 dprintk("OUTPUT_MODE could not be reset.");
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300681
682 dib7000p_set_adc_state(state, DIBX000_SLOW_ADC_ON);
683 dib7000p_sad_calib(state);
684 dib7000p_set_adc_state(state, DIBX000_SLOW_ADC_OFF);
685
Olivier Grenie713d54a2011-01-04 04:54:31 -0300686 /* unforce divstr regardless whether i2c enumeration was done or not */
687 dib7000p_write_word(state, 1285, dib7000p_read_word(state, 1285) & ~(1 << 1));
688
689 dib7000p_set_bandwidth(state, 8000);
690
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300691 if (state->version == SOC7090) {
Olivier Grenie2e802862011-08-05 10:39:15 -0300692 dib7000p_write_word(state, 36, 0x0755);/* P_iqc_impnc_on =1 & P_iqc_corr_inh = 1 for impulsive noise */
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300693 } else {
Olivier Grenie713d54a2011-01-04 04:54:31 -0300694 if (state->cfg.tuner_is_baseband)
695 dib7000p_write_word(state, 36, 0x0755);
696 else
697 dib7000p_write_word(state, 36, 0x1f55);
698 }
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300699
700 dib7000p_write_tab(state, dib7000p_defaults);
Olivier Grenie2e802862011-08-05 10:39:15 -0300701 if (state->version != SOC7090) {
702 dib7000p_write_word(state, 901, 0x0006);
703 dib7000p_write_word(state, 902, (3 << 10) | (1 << 6));
704 dib7000p_write_word(state, 905, 0x2c8e);
705 }
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300706
Patrick Boettchera75763f2006-10-18 08:34:16 -0300707 dib7000p_set_power_mode(state, DIB7000P_POWER_INTERFACE_ONLY);
708
709 return 0;
710}
711
Patrick Boettchera75763f2006-10-18 08:34:16 -0300712static void dib7000p_pll_clk_cfg(struct dib7000p_state *state)
713{
714 u16 tmp = 0;
715 tmp = dib7000p_read_word(state, 903);
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300716 dib7000p_write_word(state, 903, (tmp | 0x1));
Patrick Boettchera75763f2006-10-18 08:34:16 -0300717 tmp = dib7000p_read_word(state, 900);
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300718 dib7000p_write_word(state, 900, (tmp & 0x7fff) | (1 << 6));
Patrick Boettchera75763f2006-10-18 08:34:16 -0300719}
720
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300721static void dib7000p_restart_agc(struct dib7000p_state *state)
Patrick Boettchera75763f2006-10-18 08:34:16 -0300722{
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300723 // P_restart_iqc & P_restart_agc
724 dib7000p_write_word(state, 770, (1 << 11) | (1 << 9));
725 dib7000p_write_word(state, 770, 0x0000);
Patrick Boettchera75763f2006-10-18 08:34:16 -0300726}
727
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300728static int dib7000p_update_lna(struct dib7000p_state *state)
Patrick Boettchera75763f2006-10-18 08:34:16 -0300729{
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300730 u16 dyn_gain;
731
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300732 if (state->cfg.update_lna) {
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300733 dyn_gain = dib7000p_read_word(state, 394);
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300734 if (state->cfg.update_lna(&state->demod, dyn_gain)) {
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300735 dib7000p_restart_agc(state);
736 return 1;
737 }
738 }
739
740 return 0;
741}
742
743static int dib7000p_set_agc_config(struct dib7000p_state *state, u8 band)
744{
745 struct dibx000_agc_config *agc = NULL;
746 int i;
747 if (state->current_band == band && state->current_agc != NULL)
748 return 0;
749 state->current_band = band;
750
751 for (i = 0; i < state->cfg.agc_config_count; i++)
752 if (state->cfg.agc[i].band_caps & band) {
753 agc = &state->cfg.agc[i];
754 break;
755 }
756
757 if (agc == NULL) {
Olivier Grenie713d54a2011-01-04 04:54:31 -0300758 dprintk("no valid AGC configuration found for band 0x%02x", band);
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300759 return -EINVAL;
760 }
761
762 state->current_agc = agc;
763
764 /* AGC */
Olivier Grenie713d54a2011-01-04 04:54:31 -0300765 dib7000p_write_word(state, 75, agc->setup);
766 dib7000p_write_word(state, 76, agc->inv_gain);
767 dib7000p_write_word(state, 77, agc->time_stabiliz);
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300768 dib7000p_write_word(state, 100, (agc->alpha_level << 12) | agc->thlock);
769
770 // Demod AGC loop configuration
771 dib7000p_write_word(state, 101, (agc->alpha_mant << 5) | agc->alpha_exp);
Olivier Grenie713d54a2011-01-04 04:54:31 -0300772 dib7000p_write_word(state, 102, (agc->beta_mant << 6) | agc->beta_exp);
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300773
774 /* AGC continued */
Olivier Grenie713d54a2011-01-04 04:54:31 -0300775 dprintk("WBD: ref: %d, sel: %d, active: %d, alpha: %d",
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300776 state->wbd_ref != 0 ? state->wbd_ref : agc->wbd_ref, agc->wbd_sel, !agc->perform_agc_softsplit, agc->wbd_sel);
777
778 if (state->wbd_ref != 0)
779 dib7000p_write_word(state, 105, (agc->wbd_inv << 12) | state->wbd_ref);
780 else
781 dib7000p_write_word(state, 105, (agc->wbd_inv << 12) | agc->wbd_ref);
782
783 dib7000p_write_word(state, 106, (agc->wbd_sel << 13) | (agc->wbd_alpha << 9) | (agc->perform_agc_softsplit << 8));
784
Olivier Grenie713d54a2011-01-04 04:54:31 -0300785 dib7000p_write_word(state, 107, agc->agc1_max);
786 dib7000p_write_word(state, 108, agc->agc1_min);
787 dib7000p_write_word(state, 109, agc->agc2_max);
788 dib7000p_write_word(state, 110, agc->agc2_min);
789 dib7000p_write_word(state, 111, (agc->agc1_pt1 << 8) | agc->agc1_pt2);
790 dib7000p_write_word(state, 112, agc->agc1_pt3);
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300791 dib7000p_write_word(state, 113, (agc->agc1_slope1 << 8) | agc->agc1_slope2);
Olivier Grenie713d54a2011-01-04 04:54:31 -0300792 dib7000p_write_word(state, 114, (agc->agc2_pt1 << 8) | agc->agc2_pt2);
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300793 dib7000p_write_word(state, 115, (agc->agc2_slope1 << 8) | agc->agc2_slope2);
794 return 0;
795}
796
Olivier Grenie713d54a2011-01-04 04:54:31 -0300797static void dib7000p_set_dds(struct dib7000p_state *state, s32 offset_khz)
798{
799 u32 internal = dib7000p_get_internal_freq(state);
800 s32 unit_khz_dds_val = 67108864 / (internal); /* 2**26 / Fsampling is the unit 1KHz offset */
801 u32 abs_offset_khz = ABS(offset_khz);
802 u32 dds = state->cfg.bw->ifreq & 0x1ffffff;
803 u8 invert = !!(state->cfg.bw->ifreq & (1 << 25));
804
805 dprintk("setting a frequency offset of %dkHz internal freq = %d invert = %d", offset_khz, internal, invert);
806
807 if (offset_khz < 0)
808 unit_khz_dds_val *= -1;
809
810 /* IF tuner */
811 if (invert)
812 dds -= (abs_offset_khz * unit_khz_dds_val); /* /100 because of /100 on the unit_khz_dds_val line calc for better accuracy */
813 else
814 dds += (abs_offset_khz * unit_khz_dds_val);
815
816 if (abs_offset_khz <= (internal / 2)) { /* Max dds offset is the half of the demod freq */
817 dib7000p_write_word(state, 21, (u16) (((dds >> 16) & 0x1ff) | (0 << 10) | (invert << 9)));
818 dib7000p_write_word(state, 22, (u16) (dds & 0xffff));
819 }
820}
821
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300822static int dib7000p_agc_startup(struct dvb_frontend *demod, struct dvb_frontend_parameters *ch)
823{
824 struct dib7000p_state *state = demod->demodulator_priv;
825 int ret = -1;
826 u8 *agc_state = &state->agc_state;
827 u8 agc_split;
Olivier Grenie713d54a2011-01-04 04:54:31 -0300828 u16 reg;
829 u32 upd_demod_gain_period = 0x1000;
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300830
831 switch (state->agc_state) {
Olivier Grenie713d54a2011-01-04 04:54:31 -0300832 case 0:
Olivier Grenie713d54a2011-01-04 04:54:31 -0300833 dib7000p_set_power_mode(state, DIB7000P_POWER_ALL);
834 if (state->version == SOC7090) {
835 reg = dib7000p_read_word(state, 0x79b) & 0xff00;
836 dib7000p_write_word(state, 0x79a, upd_demod_gain_period & 0xFFFF); /* lsb */
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300837 dib7000p_write_word(state, 0x79b, reg | (1 << 14) | ((upd_demod_gain_period >> 16) & 0xFF));
Olivier Grenie713d54a2011-01-04 04:54:31 -0300838
839 /* enable adc i & q */
840 reg = dib7000p_read_word(state, 0x780);
841 dib7000p_write_word(state, 0x780, (reg | (0x3)) & (~(1 << 7)));
842 } else {
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300843 dib7000p_set_adc_state(state, DIBX000_ADC_ON);
844 dib7000p_pll_clk_cfg(state);
Olivier Grenie713d54a2011-01-04 04:54:31 -0300845 }
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300846
Olivier Grenie713d54a2011-01-04 04:54:31 -0300847 if (dib7000p_set_agc_config(state, BAND_OF_FREQUENCY(ch->frequency / 1000)) != 0)
848 return -1;
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300849
Olivier Grenie713d54a2011-01-04 04:54:31 -0300850 dib7000p_set_dds(state, 0);
851 ret = 7;
852 (*agc_state)++;
853 break;
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300854
Olivier Grenie713d54a2011-01-04 04:54:31 -0300855 case 1:
Olivier Grenie713d54a2011-01-04 04:54:31 -0300856 if (state->cfg.agc_control)
857 state->cfg.agc_control(&state->demod, 1);
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300858
Olivier Grenie713d54a2011-01-04 04:54:31 -0300859 dib7000p_write_word(state, 78, 32768);
860 if (!state->current_agc->perform_agc_softsplit) {
861 /* we are using the wbd - so slow AGC startup */
862 /* force 0 split on WBD and restart AGC */
863 dib7000p_write_word(state, 106, (state->current_agc->wbd_sel << 13) | (state->current_agc->wbd_alpha << 9) | (1 << 8));
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300864 (*agc_state)++;
865 ret = 5;
Olivier Grenie713d54a2011-01-04 04:54:31 -0300866 } else {
867 /* default AGC startup */
868 (*agc_state) = 4;
869 /* wait AGC rough lock time */
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300870 ret = 7;
Olivier Grenie713d54a2011-01-04 04:54:31 -0300871 }
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300872
Olivier Grenie713d54a2011-01-04 04:54:31 -0300873 dib7000p_restart_agc(state);
874 break;
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300875
Olivier Grenie713d54a2011-01-04 04:54:31 -0300876 case 2: /* fast split search path after 5sec */
877 dib7000p_write_word(state, 75, state->current_agc->setup | (1 << 4)); /* freeze AGC loop */
878 dib7000p_write_word(state, 106, (state->current_agc->wbd_sel << 13) | (2 << 9) | (0 << 8)); /* fast split search 0.25kHz */
879 (*agc_state)++;
880 ret = 14;
881 break;
882
883 case 3: /* split search ended */
884 agc_split = (u8) dib7000p_read_word(state, 396); /* store the split value for the next time */
885 dib7000p_write_word(state, 78, dib7000p_read_word(state, 394)); /* set AGC gain start value */
886
887 dib7000p_write_word(state, 75, state->current_agc->setup); /* std AGC loop */
888 dib7000p_write_word(state, 106, (state->current_agc->wbd_sel << 13) | (state->current_agc->wbd_alpha << 9) | agc_split); /* standard split search */
889
890 dib7000p_restart_agc(state);
891
892 dprintk("SPLIT %p: %hd", demod, agc_split);
893
894 (*agc_state)++;
895 ret = 5;
896 break;
897
898 case 4: /* LNA startup */
Olivier Grenie713d54a2011-01-04 04:54:31 -0300899 ret = 7;
900
901 if (dib7000p_update_lna(state))
Olivier Grenie713d54a2011-01-04 04:54:31 -0300902 ret = 5;
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300903 else
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300904 (*agc_state)++;
Olivier Grenie713d54a2011-01-04 04:54:31 -0300905 break;
906
907 case 5:
908 if (state->cfg.agc_control)
909 state->cfg.agc_control(&state->demod, 0);
910 (*agc_state)++;
911 break;
912 default:
913 break;
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300914 }
915 return ret;
916}
917
918static void dib7000p_update_timf(struct dib7000p_state *state)
919{
920 u32 timf = (dib7000p_read_word(state, 427) << 16) | dib7000p_read_word(state, 428);
921 state->timf = timf * 160 / (state->current_bandwidth / 50);
922 dib7000p_write_word(state, 23, (u16) (timf >> 16));
923 dib7000p_write_word(state, 24, (u16) (timf & 0xffff));
Olivier Grenie713d54a2011-01-04 04:54:31 -0300924 dprintk("updated timf_frequency: %d (default: %d)", state->timf, state->cfg.bw->timf);
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300925
926}
927
Olivier Grenie713d54a2011-01-04 04:54:31 -0300928u32 dib7000p_ctrl_timf(struct dvb_frontend *fe, u8 op, u32 timf)
929{
930 struct dib7000p_state *state = fe->demodulator_priv;
931 switch (op) {
932 case DEMOD_TIMF_SET:
933 state->timf = timf;
934 break;
935 case DEMOD_TIMF_UPDATE:
936 dib7000p_update_timf(state);
937 break;
938 case DEMOD_TIMF_GET:
939 break;
940 }
941 dib7000p_set_bandwidth(state, state->current_bandwidth);
942 return state->timf;
943}
944EXPORT_SYMBOL(dib7000p_ctrl_timf);
945
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300946static void dib7000p_set_channel(struct dib7000p_state *state, struct dvb_frontend_parameters *ch, u8 seq)
947{
948 u16 value, est[4];
949
Olivier Grenie713d54a2011-01-04 04:54:31 -0300950 dib7000p_set_bandwidth(state, BANDWIDTH_TO_KHZ(ch->u.ofdm.bandwidth));
Patrick Boettchera75763f2006-10-18 08:34:16 -0300951
952 /* nfft, guard, qam, alpha */
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300953 value = 0;
954 switch (ch->u.ofdm.transmission_mode) {
Olivier Grenie713d54a2011-01-04 04:54:31 -0300955 case TRANSMISSION_MODE_2K:
956 value |= (0 << 7);
957 break;
Mauro Carvalho Chehab46f72962011-01-16 13:01:20 -0200958 case TRANSMISSION_MODE_4K:
Olivier Grenie713d54a2011-01-04 04:54:31 -0300959 value |= (2 << 7);
960 break;
961 default:
962 case TRANSMISSION_MODE_8K:
963 value |= (1 << 7);
964 break;
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300965 }
966 switch (ch->u.ofdm.guard_interval) {
Olivier Grenie713d54a2011-01-04 04:54:31 -0300967 case GUARD_INTERVAL_1_32:
968 value |= (0 << 5);
969 break;
970 case GUARD_INTERVAL_1_16:
971 value |= (1 << 5);
972 break;
973 case GUARD_INTERVAL_1_4:
974 value |= (3 << 5);
975 break;
976 default:
977 case GUARD_INTERVAL_1_8:
978 value |= (2 << 5);
979 break;
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300980 }
981 switch (ch->u.ofdm.constellation) {
Olivier Grenie713d54a2011-01-04 04:54:31 -0300982 case QPSK:
983 value |= (0 << 3);
984 break;
985 case QAM_16:
986 value |= (1 << 3);
987 break;
988 default:
989 case QAM_64:
990 value |= (2 << 3);
991 break;
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300992 }
993 switch (HIERARCHY_1) {
Olivier Grenie713d54a2011-01-04 04:54:31 -0300994 case HIERARCHY_2:
995 value |= 2;
996 break;
997 case HIERARCHY_4:
998 value |= 4;
999 break;
1000 default:
1001 case HIERARCHY_1:
1002 value |= 1;
1003 break;
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001004 }
1005 dib7000p_write_word(state, 0, value);
Olivier Grenie713d54a2011-01-04 04:54:31 -03001006 dib7000p_write_word(state, 5, (seq << 4) | 1); /* do not force tps, search list 0 */
Patrick Boettchera75763f2006-10-18 08:34:16 -03001007
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001008 /* P_dintl_native, P_dintlv_inv, P_hrch, P_code_rate, P_select_hp */
1009 value = 0;
1010 if (1 != 0)
1011 value |= (1 << 6);
1012 if (ch->u.ofdm.hierarchy_information == 1)
1013 value |= (1 << 4);
1014 if (1 == 1)
1015 value |= 1;
1016 switch ((ch->u.ofdm.hierarchy_information == 0 || 1 == 1) ? ch->u.ofdm.code_rate_HP : ch->u.ofdm.code_rate_LP) {
Olivier Grenie713d54a2011-01-04 04:54:31 -03001017 case FEC_2_3:
1018 value |= (2 << 1);
1019 break;
1020 case FEC_3_4:
1021 value |= (3 << 1);
1022 break;
1023 case FEC_5_6:
1024 value |= (5 << 1);
1025 break;
1026 case FEC_7_8:
1027 value |= (7 << 1);
1028 break;
1029 default:
1030 case FEC_1_2:
1031 value |= (1 << 1);
1032 break;
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001033 }
1034 dib7000p_write_word(state, 208, value);
1035
1036 /* offset loop parameters */
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001037 dib7000p_write_word(state, 26, 0x6680);
1038 dib7000p_write_word(state, 32, 0x0003);
1039 dib7000p_write_word(state, 29, 0x1273);
1040 dib7000p_write_word(state, 33, 0x0005);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001041
1042 /* P_dvsy_sync_wait */
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001043 switch (ch->u.ofdm.transmission_mode) {
Olivier Grenie713d54a2011-01-04 04:54:31 -03001044 case TRANSMISSION_MODE_8K:
1045 value = 256;
1046 break;
1047 case TRANSMISSION_MODE_4K:
1048 value = 128;
1049 break;
1050 case TRANSMISSION_MODE_2K:
1051 default:
1052 value = 64;
1053 break;
Patrick Boettchera75763f2006-10-18 08:34:16 -03001054 }
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001055 switch (ch->u.ofdm.guard_interval) {
Olivier Grenie713d54a2011-01-04 04:54:31 -03001056 case GUARD_INTERVAL_1_16:
1057 value *= 2;
1058 break;
1059 case GUARD_INTERVAL_1_8:
1060 value *= 4;
1061 break;
1062 case GUARD_INTERVAL_1_4:
1063 value *= 8;
1064 break;
1065 default:
1066 case GUARD_INTERVAL_1_32:
1067 value *= 1;
1068 break;
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001069 }
Olivier Grenie970d14c2010-09-07 12:50:46 -03001070 if (state->cfg.diversity_delay == 0)
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001071 state->div_sync_wait = (value * 3) / 2 + 48;
Olivier Grenie970d14c2010-09-07 12:50:46 -03001072 else
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001073 state->div_sync_wait = (value * 3) / 2 + state->cfg.diversity_delay;
Patrick Boettchera75763f2006-10-18 08:34:16 -03001074
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001075 /* deactive the possibility of diversity reception if extended interleaver */
1076 state->div_force_off = !1 && ch->u.ofdm.transmission_mode != TRANSMISSION_MODE_8K;
1077 dib7000p_set_diversity_in(&state->demod, state->div_state);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001078
1079 /* channel estimation fine configuration */
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001080 switch (ch->u.ofdm.constellation) {
Olivier Grenie713d54a2011-01-04 04:54:31 -03001081 case QAM_64:
1082 est[0] = 0x0148; /* P_adp_regul_cnt 0.04 */
1083 est[1] = 0xfff0; /* P_adp_noise_cnt -0.002 */
1084 est[2] = 0x00a4; /* P_adp_regul_ext 0.02 */
1085 est[3] = 0xfff8; /* P_adp_noise_ext -0.001 */
1086 break;
1087 case QAM_16:
1088 est[0] = 0x023d; /* P_adp_regul_cnt 0.07 */
1089 est[1] = 0xffdf; /* P_adp_noise_cnt -0.004 */
1090 est[2] = 0x00a4; /* P_adp_regul_ext 0.02 */
1091 est[3] = 0xfff0; /* P_adp_noise_ext -0.002 */
1092 break;
1093 default:
1094 est[0] = 0x099a; /* P_adp_regul_cnt 0.3 */
1095 est[1] = 0xffae; /* P_adp_noise_cnt -0.01 */
1096 est[2] = 0x0333; /* P_adp_regul_ext 0.1 */
1097 est[3] = 0xfff8; /* P_adp_noise_ext -0.002 */
1098 break;
Patrick Boettchera75763f2006-10-18 08:34:16 -03001099 }
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001100 for (value = 0; value < 4; value++)
1101 dib7000p_write_word(state, 187 + value, est[value]);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001102}
1103
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001104static int dib7000p_autosearch_start(struct dvb_frontend *demod, struct dvb_frontend_parameters *ch)
Patrick Boettchera75763f2006-10-18 08:34:16 -03001105{
1106 struct dib7000p_state *state = demod->demodulator_priv;
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001107 struct dvb_frontend_parameters schan;
1108 u32 value, factor;
Olivier Grenie713d54a2011-01-04 04:54:31 -03001109 u32 internal = dib7000p_get_internal_freq(state);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001110
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001111 schan = *ch;
1112 schan.u.ofdm.constellation = QAM_64;
Olivier Grenie713d54a2011-01-04 04:54:31 -03001113 schan.u.ofdm.guard_interval = GUARD_INTERVAL_1_32;
1114 schan.u.ofdm.transmission_mode = TRANSMISSION_MODE_8K;
1115 schan.u.ofdm.code_rate_HP = FEC_2_3;
1116 schan.u.ofdm.code_rate_LP = FEC_3_4;
1117 schan.u.ofdm.hierarchy_information = 0;
Patrick Boettchera75763f2006-10-18 08:34:16 -03001118
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001119 dib7000p_set_channel(state, &schan, 7);
1120
1121 factor = BANDWIDTH_TO_KHZ(ch->u.ofdm.bandwidth);
Olivier Grenie2e802862011-08-05 10:39:15 -03001122 if (factor >= 5000) {
1123 if (state->version == SOC7090)
1124 factor = 2;
1125 else
1126 factor = 1;
1127 } else
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001128 factor = 6;
Patrick Boettchera75763f2006-10-18 08:34:16 -03001129
Olivier Grenie713d54a2011-01-04 04:54:31 -03001130 value = 30 * internal * factor;
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001131 dib7000p_write_word(state, 6, (u16) ((value >> 16) & 0xffff));
1132 dib7000p_write_word(state, 7, (u16) (value & 0xffff));
Olivier Grenie713d54a2011-01-04 04:54:31 -03001133 value = 100 * internal * factor;
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001134 dib7000p_write_word(state, 8, (u16) ((value >> 16) & 0xffff));
1135 dib7000p_write_word(state, 9, (u16) (value & 0xffff));
Olivier Grenie713d54a2011-01-04 04:54:31 -03001136 value = 500 * internal * factor;
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001137 dib7000p_write_word(state, 10, (u16) ((value >> 16) & 0xffff));
1138 dib7000p_write_word(state, 11, (u16) (value & 0xffff));
Patrick Boettchera75763f2006-10-18 08:34:16 -03001139
1140 value = dib7000p_read_word(state, 0);
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001141 dib7000p_write_word(state, 0, (u16) ((1 << 9) | value));
Patrick Boettchera75763f2006-10-18 08:34:16 -03001142 dib7000p_read_word(state, 1284);
1143 dib7000p_write_word(state, 0, (u16) value);
1144
1145 return 0;
1146}
1147
1148static int dib7000p_autosearch_is_irq(struct dvb_frontend *demod)
1149{
1150 struct dib7000p_state *state = demod->demodulator_priv;
1151 u16 irq_pending = dib7000p_read_word(state, 1284);
1152
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001153 if (irq_pending & 0x1)
Patrick Boettchera75763f2006-10-18 08:34:16 -03001154 return 1;
1155
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001156 if (irq_pending & 0x2)
Patrick Boettchera75763f2006-10-18 08:34:16 -03001157 return 2;
1158
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001159 return 0;
Patrick Boettchera75763f2006-10-18 08:34:16 -03001160}
1161
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001162static void dib7000p_spur_protect(struct dib7000p_state *state, u32 rf_khz, u32 bw)
1163{
Olivier Grenie713d54a2011-01-04 04:54:31 -03001164 static s16 notch[] = { 16143, 14402, 12238, 9713, 6902, 3888, 759, -2392 };
1165 static u8 sine[] = { 0, 2, 3, 5, 6, 8, 9, 11, 13, 14, 16, 17, 19, 20, 22,
1166 24, 25, 27, 28, 30, 31, 33, 34, 36, 38, 39, 41, 42, 44, 45, 47, 48, 50, 51,
1167 53, 55, 56, 58, 59, 61, 62, 64, 65, 67, 68, 70, 71, 73, 74, 76, 77, 79, 80,
1168 82, 83, 85, 86, 88, 89, 91, 92, 94, 95, 97, 98, 99, 101, 102, 104, 105,
1169 107, 108, 109, 111, 112, 114, 115, 117, 118, 119, 121, 122, 123, 125, 126,
1170 128, 129, 130, 132, 133, 134, 136, 137, 138, 140, 141, 142, 144, 145, 146,
1171 147, 149, 150, 151, 152, 154, 155, 156, 157, 159, 160, 161, 162, 164, 165,
1172 166, 167, 168, 170, 171, 172, 173, 174, 175, 177, 178, 179, 180, 181, 182,
1173 183, 184, 185, 186, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198,
1174 199, 200, 201, 202, 203, 204, 205, 206, 207, 207, 208, 209, 210, 211, 212,
1175 213, 214, 215, 215, 216, 217, 218, 219, 220, 220, 221, 222, 223, 224, 224,
1176 225, 226, 227, 227, 228, 229, 229, 230, 231, 231, 232, 233, 233, 234, 235,
1177 235, 236, 237, 237, 238, 238, 239, 239, 240, 241, 241, 242, 242, 243, 243,
1178 244, 244, 245, 245, 245, 246, 246, 247, 247, 248, 248, 248, 249, 249, 249,
1179 250, 250, 250, 251, 251, 251, 252, 252, 252, 252, 253, 253, 253, 253, 254,
1180 254, 254, 254, 254, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
1181 255, 255, 255, 255, 255, 255
1182 };
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001183
1184 u32 xtal = state->cfg.bw->xtal_hz / 1000;
Julia Lawall75b697f2009-08-01 16:48:41 -03001185 int f_rel = DIV_ROUND_CLOSEST(rf_khz, xtal) * xtal - rf_khz;
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001186 int k;
Olivier Grenie713d54a2011-01-04 04:54:31 -03001187 int coef_re[8], coef_im[8];
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001188 int bw_khz = bw;
1189 u32 pha;
1190
Olivier Grenie713d54a2011-01-04 04:54:31 -03001191 dprintk("relative position of the Spur: %dk (RF: %dk, XTAL: %dk)", f_rel, rf_khz, xtal);
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001192
Olivier Grenie713d54a2011-01-04 04:54:31 -03001193 if (f_rel < -bw_khz / 2 || f_rel > bw_khz / 2)
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001194 return;
1195
1196 bw_khz /= 100;
1197
Olivier Grenie713d54a2011-01-04 04:54:31 -03001198 dib7000p_write_word(state, 142, 0x0610);
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001199
1200 for (k = 0; k < 8; k++) {
Olivier Grenie713d54a2011-01-04 04:54:31 -03001201 pha = ((f_rel * (k + 1) * 112 * 80 / bw_khz) / 1000) & 0x3ff;
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001202
Olivier Grenie713d54a2011-01-04 04:54:31 -03001203 if (pha == 0) {
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001204 coef_re[k] = 256;
1205 coef_im[k] = 0;
Olivier Grenie713d54a2011-01-04 04:54:31 -03001206 } else if (pha < 256) {
1207 coef_re[k] = sine[256 - (pha & 0xff)];
1208 coef_im[k] = sine[pha & 0xff];
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001209 } else if (pha == 256) {
1210 coef_re[k] = 0;
1211 coef_im[k] = 256;
1212 } else if (pha < 512) {
Olivier Grenie713d54a2011-01-04 04:54:31 -03001213 coef_re[k] = -sine[pha & 0xff];
1214 coef_im[k] = sine[256 - (pha & 0xff)];
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001215 } else if (pha == 512) {
1216 coef_re[k] = -256;
1217 coef_im[k] = 0;
1218 } else if (pha < 768) {
Olivier Grenie713d54a2011-01-04 04:54:31 -03001219 coef_re[k] = -sine[256 - (pha & 0xff)];
1220 coef_im[k] = -sine[pha & 0xff];
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001221 } else if (pha == 768) {
1222 coef_re[k] = 0;
1223 coef_im[k] = -256;
1224 } else {
Olivier Grenie713d54a2011-01-04 04:54:31 -03001225 coef_re[k] = sine[pha & 0xff];
1226 coef_im[k] = -sine[256 - (pha & 0xff)];
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001227 }
1228
1229 coef_re[k] *= notch[k];
Olivier Grenie713d54a2011-01-04 04:54:31 -03001230 coef_re[k] += (1 << 14);
1231 if (coef_re[k] >= (1 << 24))
1232 coef_re[k] = (1 << 24) - 1;
1233 coef_re[k] /= (1 << 15);
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001234
1235 coef_im[k] *= notch[k];
Olivier Grenie713d54a2011-01-04 04:54:31 -03001236 coef_im[k] += (1 << 14);
1237 if (coef_im[k] >= (1 << 24))
1238 coef_im[k] = (1 << 24) - 1;
1239 coef_im[k] /= (1 << 15);
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001240
Olivier Grenie713d54a2011-01-04 04:54:31 -03001241 dprintk("PALF COEF: %d re: %d im: %d", k, coef_re[k], coef_im[k]);
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001242
1243 dib7000p_write_word(state, 143, (0 << 14) | (k << 10) | (coef_re[k] & 0x3ff));
1244 dib7000p_write_word(state, 144, coef_im[k] & 0x3ff);
1245 dib7000p_write_word(state, 143, (1 << 14) | (k << 10) | (coef_re[k] & 0x3ff));
1246 }
Olivier Grenie713d54a2011-01-04 04:54:31 -03001247 dib7000p_write_word(state, 143, 0);
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001248}
1249
1250static int dib7000p_tune(struct dvb_frontend *demod, struct dvb_frontend_parameters *ch)
Patrick Boettchera75763f2006-10-18 08:34:16 -03001251{
1252 struct dib7000p_state *state = demod->demodulator_priv;
1253 u16 tmp = 0;
1254
1255 if (ch != NULL)
1256 dib7000p_set_channel(state, ch, 0);
1257 else
1258 return -EINVAL;
1259
1260 // restart demod
1261 dib7000p_write_word(state, 770, 0x4000);
1262 dib7000p_write_word(state, 770, 0x0000);
1263 msleep(45);
1264
1265 /* 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 -03001266 tmp = (0 << 14) | (4 << 10) | (0 << 9) | (3 << 5) | (1 << 4) | (0x3);
1267 if (state->sfn_workaround_active) {
Olivier Grenie713d54a2011-01-04 04:54:31 -03001268 dprintk("SFN workaround is active");
Matt Doran8f6956c2007-07-31 07:09:30 -03001269 tmp |= (1 << 9);
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001270 dib7000p_write_word(state, 166, 0x4000);
Matt Doran8f6956c2007-07-31 07:09:30 -03001271 } else {
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001272 dib7000p_write_word(state, 166, 0x0000);
Matt Doran8f6956c2007-07-31 07:09:30 -03001273 }
1274 dib7000p_write_word(state, 29, tmp);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001275
1276 // never achieved a lock with that bandwidth so far - wait for osc-freq to update
1277 if (state->timf == 0)
1278 msleep(200);
1279
1280 /* offset loop parameters */
1281
1282 /* P_timf_alpha, P_corm_alpha=6, P_corm_thres=0x80 */
1283 tmp = (6 << 8) | 0x80;
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001284 switch (ch->u.ofdm.transmission_mode) {
Olivier Grenie713d54a2011-01-04 04:54:31 -03001285 case TRANSMISSION_MODE_2K:
1286 tmp |= (2 << 12);
1287 break;
Mauro Carvalho Chehab46f72962011-01-16 13:01:20 -02001288 case TRANSMISSION_MODE_4K:
Olivier Grenie713d54a2011-01-04 04:54:31 -03001289 tmp |= (3 << 12);
1290 break;
1291 default:
1292 case TRANSMISSION_MODE_8K:
1293 tmp |= (4 << 12);
1294 break;
Patrick Boettchera75763f2006-10-18 08:34:16 -03001295 }
Olivier Grenie713d54a2011-01-04 04:54:31 -03001296 dib7000p_write_word(state, 26, tmp); /* timf_a(6xxx) */
Patrick Boettchera75763f2006-10-18 08:34:16 -03001297
1298 /* P_ctrl_freeze_pha_shift=0, P_ctrl_pha_off_max */
1299 tmp = (0 << 4);
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001300 switch (ch->u.ofdm.transmission_mode) {
Olivier Grenie713d54a2011-01-04 04:54:31 -03001301 case TRANSMISSION_MODE_2K:
1302 tmp |= 0x6;
1303 break;
Mauro Carvalho Chehab46f72962011-01-16 13:01:20 -02001304 case TRANSMISSION_MODE_4K:
Olivier Grenie713d54a2011-01-04 04:54:31 -03001305 tmp |= 0x7;
1306 break;
1307 default:
1308 case TRANSMISSION_MODE_8K:
1309 tmp |= 0x8;
1310 break;
Patrick Boettchera75763f2006-10-18 08:34:16 -03001311 }
Olivier Grenie713d54a2011-01-04 04:54:31 -03001312 dib7000p_write_word(state, 32, tmp);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001313
1314 /* P_ctrl_sfreq_inh=0, P_ctrl_sfreq_step */
1315 tmp = (0 << 4);
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001316 switch (ch->u.ofdm.transmission_mode) {
Olivier Grenie713d54a2011-01-04 04:54:31 -03001317 case TRANSMISSION_MODE_2K:
1318 tmp |= 0x6;
1319 break;
1320 case TRANSMISSION_MODE_4K:
1321 tmp |= 0x7;
1322 break;
1323 default:
1324 case TRANSMISSION_MODE_8K:
1325 tmp |= 0x8;
1326 break;
Patrick Boettchera75763f2006-10-18 08:34:16 -03001327 }
Olivier Grenie713d54a2011-01-04 04:54:31 -03001328 dib7000p_write_word(state, 33, tmp);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001329
Olivier Grenie713d54a2011-01-04 04:54:31 -03001330 tmp = dib7000p_read_word(state, 509);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001331 if (!((tmp >> 6) & 0x1)) {
1332 /* restart the fec */
Olivier Grenie713d54a2011-01-04 04:54:31 -03001333 tmp = dib7000p_read_word(state, 771);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001334 dib7000p_write_word(state, 771, tmp | (1 << 1));
1335 dib7000p_write_word(state, 771, tmp);
Olivier Grenie713d54a2011-01-04 04:54:31 -03001336 msleep(40);
1337 tmp = dib7000p_read_word(state, 509);
1338 }
1339 // we achieved a lock - it's time to update the osc freq
1340 if ((tmp >> 6) & 0x1) {
1341 dib7000p_update_timf(state);
1342 /* P_timf_alpha += 2 */
1343 tmp = dib7000p_read_word(state, 26);
1344 dib7000p_write_word(state, 26, (tmp & ~(0xf << 12)) | ((((tmp >> 12) & 0xf) + 5) << 12));
Patrick Boettchera75763f2006-10-18 08:34:16 -03001345 }
1346
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001347 if (state->cfg.spur_protect)
Olivier Grenie713d54a2011-01-04 04:54:31 -03001348 dib7000p_spur_protect(state, ch->frequency / 1000, BANDWIDTH_TO_KHZ(ch->u.ofdm.bandwidth));
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001349
Olivier Grenie713d54a2011-01-04 04:54:31 -03001350 dib7000p_set_bandwidth(state, BANDWIDTH_TO_KHZ(ch->u.ofdm.bandwidth));
Patrick Boettchera75763f2006-10-18 08:34:16 -03001351 return 0;
1352}
1353
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001354static int dib7000p_wakeup(struct dvb_frontend *demod)
Patrick Boettchera75763f2006-10-18 08:34:16 -03001355{
Patrick Boettchera75763f2006-10-18 08:34:16 -03001356 struct dib7000p_state *state = demod->demodulator_priv;
Patrick Boettchera75763f2006-10-18 08:34:16 -03001357 dib7000p_set_power_mode(state, DIB7000P_POWER_ALL);
1358 dib7000p_set_adc_state(state, DIBX000_SLOW_ADC_ON);
Olivier Grenie713d54a2011-01-04 04:54:31 -03001359 if (state->version == SOC7090)
1360 dib7000p_sad_calib(state);
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001361 return 0;
Patrick Boettchera75763f2006-10-18 08:34:16 -03001362}
1363
1364static int dib7000p_sleep(struct dvb_frontend *demod)
1365{
1366 struct dib7000p_state *state = demod->demodulator_priv;
Olivier Grenie713d54a2011-01-04 04:54:31 -03001367 if (state->version == SOC7090)
Olivier Grenie2e802862011-08-05 10:39:15 -03001368 return dib7000p_set_power_mode(state, DIB7000P_POWER_INTERFACE_ONLY);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001369 return dib7000p_set_output_mode(state, OUTMODE_HIGH_Z) | dib7000p_set_power_mode(state, DIB7000P_POWER_INTERFACE_ONLY);
1370}
1371
1372static int dib7000p_identify(struct dib7000p_state *st)
1373{
1374 u16 value;
Olivier Grenie713d54a2011-01-04 04:54:31 -03001375 dprintk("checking demod on I2C address: %d (%x)", st->i2c_addr, st->i2c_addr);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001376
1377 if ((value = dib7000p_read_word(st, 768)) != 0x01b3) {
Olivier Grenie713d54a2011-01-04 04:54:31 -03001378 dprintk("wrong Vendor ID (read=0x%x)", value);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001379 return -EREMOTEIO;
1380 }
1381
1382 if ((value = dib7000p_read_word(st, 769)) != 0x4000) {
Olivier Grenie713d54a2011-01-04 04:54:31 -03001383 dprintk("wrong Device ID (%x)", value);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001384 return -EREMOTEIO;
1385 }
1386
1387 return 0;
1388}
1389
Olivier Grenie713d54a2011-01-04 04:54:31 -03001390static int dib7000p_get_frontend(struct dvb_frontend *fe, struct dvb_frontend_parameters *fep)
Patrick Boettchera75763f2006-10-18 08:34:16 -03001391{
1392 struct dib7000p_state *state = fe->demodulator_priv;
Olivier Grenie713d54a2011-01-04 04:54:31 -03001393 u16 tps = dib7000p_read_word(state, 463);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001394
1395 fep->inversion = INVERSION_AUTO;
1396
Patrick Boettcher904a82e2008-01-25 07:31:58 -03001397 fep->u.ofdm.bandwidth = BANDWIDTH_TO_INDEX(state->current_bandwidth);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001398
1399 switch ((tps >> 8) & 0x3) {
Olivier Grenie713d54a2011-01-04 04:54:31 -03001400 case 0:
1401 fep->u.ofdm.transmission_mode = TRANSMISSION_MODE_2K;
1402 break;
1403 case 1:
1404 fep->u.ofdm.transmission_mode = TRANSMISSION_MODE_8K;
1405 break;
Mauro Carvalho Chehab46f72962011-01-16 13:01:20 -02001406 /* case 2: fep->u.ofdm.transmission_mode = TRANSMISSION_MODE_4K; break; */
Patrick Boettchera75763f2006-10-18 08:34:16 -03001407 }
1408
1409 switch (tps & 0x3) {
Olivier Grenie713d54a2011-01-04 04:54:31 -03001410 case 0:
1411 fep->u.ofdm.guard_interval = GUARD_INTERVAL_1_32;
1412 break;
1413 case 1:
1414 fep->u.ofdm.guard_interval = GUARD_INTERVAL_1_16;
1415 break;
1416 case 2:
1417 fep->u.ofdm.guard_interval = GUARD_INTERVAL_1_8;
1418 break;
1419 case 3:
1420 fep->u.ofdm.guard_interval = GUARD_INTERVAL_1_4;
1421 break;
Patrick Boettchera75763f2006-10-18 08:34:16 -03001422 }
1423
1424 switch ((tps >> 14) & 0x3) {
Olivier Grenie713d54a2011-01-04 04:54:31 -03001425 case 0:
1426 fep->u.ofdm.constellation = QPSK;
1427 break;
1428 case 1:
1429 fep->u.ofdm.constellation = QAM_16;
1430 break;
1431 case 2:
1432 default:
1433 fep->u.ofdm.constellation = QAM_64;
1434 break;
Patrick Boettchera75763f2006-10-18 08:34:16 -03001435 }
1436
1437 /* as long as the frontend_param structure is fixed for hierarchical transmission I refuse to use it */
1438 /* (tps >> 13) & 0x1 == hrch is used, (tps >> 10) & 0x7 == alpha */
1439
1440 fep->u.ofdm.hierarchy_information = HIERARCHY_NONE;
1441 switch ((tps >> 5) & 0x7) {
Olivier Grenie713d54a2011-01-04 04:54:31 -03001442 case 1:
1443 fep->u.ofdm.code_rate_HP = FEC_1_2;
1444 break;
1445 case 2:
1446 fep->u.ofdm.code_rate_HP = FEC_2_3;
1447 break;
1448 case 3:
1449 fep->u.ofdm.code_rate_HP = FEC_3_4;
1450 break;
1451 case 5:
1452 fep->u.ofdm.code_rate_HP = FEC_5_6;
1453 break;
1454 case 7:
1455 default:
1456 fep->u.ofdm.code_rate_HP = FEC_7_8;
1457 break;
Patrick Boettchera75763f2006-10-18 08:34:16 -03001458
1459 }
1460
1461 switch ((tps >> 2) & 0x7) {
Olivier Grenie713d54a2011-01-04 04:54:31 -03001462 case 1:
1463 fep->u.ofdm.code_rate_LP = FEC_1_2;
1464 break;
1465 case 2:
1466 fep->u.ofdm.code_rate_LP = FEC_2_3;
1467 break;
1468 case 3:
1469 fep->u.ofdm.code_rate_LP = FEC_3_4;
1470 break;
1471 case 5:
1472 fep->u.ofdm.code_rate_LP = FEC_5_6;
1473 break;
1474 case 7:
1475 default:
1476 fep->u.ofdm.code_rate_LP = FEC_7_8;
1477 break;
Patrick Boettchera75763f2006-10-18 08:34:16 -03001478 }
1479
1480 /* native interleaver: (dib7000p_read_word(state, 464) >> 5) & 0x1 */
1481
1482 return 0;
1483}
1484
Olivier Grenie713d54a2011-01-04 04:54:31 -03001485static int dib7000p_set_frontend(struct dvb_frontend *fe, struct dvb_frontend_parameters *fep)
Patrick Boettchera75763f2006-10-18 08:34:16 -03001486{
1487 struct dib7000p_state *state = fe->demodulator_priv;
Soeren Moch853ea132008-01-25 06:27:06 -03001488 int time, ret;
Patrick Boettchera75763f2006-10-18 08:34:16 -03001489
Olivier Grenie2e802862011-08-05 10:39:15 -03001490 if (state->version == SOC7090)
Olivier Grenie713d54a2011-01-04 04:54:31 -03001491 dib7090_set_diversity_in(fe, 0);
Olivier Grenie2e802862011-08-05 10:39:15 -03001492 else
Olivier Grenie713d54a2011-01-04 04:54:31 -03001493 dib7000p_set_output_mode(state, OUTMODE_HIGH_Z);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001494
Olivier Grenie713d54a2011-01-04 04:54:31 -03001495 /* maybe the parameter has been changed */
Matt Doran8f6956c2007-07-31 07:09:30 -03001496 state->sfn_workaround_active = buggy_sfn_workaround;
1497
Patrick Boettchera75763f2006-10-18 08:34:16 -03001498 if (fe->ops.tuner_ops.set_params)
1499 fe->ops.tuner_ops.set_params(fe, fep);
1500
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001501 /* start up the AGC */
1502 state->agc_state = 0;
1503 do {
1504 time = dib7000p_agc_startup(fe, fep);
1505 if (time != -1)
1506 msleep(time);
1507 } while (time != -1);
1508
Patrick Boettchera75763f2006-10-18 08:34:16 -03001509 if (fep->u.ofdm.transmission_mode == TRANSMISSION_MODE_AUTO ||
Olivier Grenie713d54a2011-01-04 04:54:31 -03001510 fep->u.ofdm.guard_interval == GUARD_INTERVAL_AUTO || fep->u.ofdm.constellation == QAM_AUTO || fep->u.ofdm.code_rate_HP == FEC_AUTO) {
Patrick Boettchera75763f2006-10-18 08:34:16 -03001511 int i = 800, found;
1512
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001513 dib7000p_autosearch_start(fe, fep);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001514 do {
1515 msleep(1);
1516 found = dib7000p_autosearch_is_irq(fe);
1517 } while (found == 0 && i--);
1518
Olivier Grenie713d54a2011-01-04 04:54:31 -03001519 dprintk("autosearch returns: %d", found);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001520 if (found == 0 || found == 1)
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001521 return 0;
Patrick Boettchera75763f2006-10-18 08:34:16 -03001522
1523 dib7000p_get_frontend(fe, fep);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001524 }
1525
Soeren Moch853ea132008-01-25 06:27:06 -03001526 ret = dib7000p_tune(fe, fep);
1527
Patrick Boettchera75763f2006-10-18 08:34:16 -03001528 /* make this a config parameter */
Olivier Grenie2e802862011-08-05 10:39:15 -03001529 if (state->version == SOC7090) {
Olivier Grenie713d54a2011-01-04 04:54:31 -03001530 dib7090_set_output_mode(fe, state->cfg.output_mode);
Olivier Grenie2e802862011-08-05 10:39:15 -03001531 if (state->cfg.enMpegOutput == 0) {
1532 dib7090_setDibTxMux(state, MPEG_ON_DIBTX);
1533 dib7090_setHostBusMux(state, DIBTX_ON_HOSTBUS);
1534 }
1535 } else
Olivier Grenie713d54a2011-01-04 04:54:31 -03001536 dib7000p_set_output_mode(state, state->cfg.output_mode);
1537
1538 return ret;
Patrick Boettchera75763f2006-10-18 08:34:16 -03001539}
1540
Olivier Grenie713d54a2011-01-04 04:54:31 -03001541static int dib7000p_read_status(struct dvb_frontend *fe, fe_status_t * stat)
Patrick Boettchera75763f2006-10-18 08:34:16 -03001542{
1543 struct dib7000p_state *state = fe->demodulator_priv;
1544 u16 lock = dib7000p_read_word(state, 509);
1545
1546 *stat = 0;
1547
1548 if (lock & 0x8000)
1549 *stat |= FE_HAS_SIGNAL;
1550 if (lock & 0x3000)
1551 *stat |= FE_HAS_CARRIER;
1552 if (lock & 0x0100)
1553 *stat |= FE_HAS_VITERBI;
1554 if (lock & 0x0010)
1555 *stat |= FE_HAS_SYNC;
Olivier Grenie713d54a2011-01-04 04:54:31 -03001556 if ((lock & 0x0038) == 0x38)
Patrick Boettchera75763f2006-10-18 08:34:16 -03001557 *stat |= FE_HAS_LOCK;
1558
1559 return 0;
1560}
1561
Olivier Grenie713d54a2011-01-04 04:54:31 -03001562static int dib7000p_read_ber(struct dvb_frontend *fe, u32 * ber)
Patrick Boettchera75763f2006-10-18 08:34:16 -03001563{
1564 struct dib7000p_state *state = fe->demodulator_priv;
1565 *ber = (dib7000p_read_word(state, 500) << 16) | dib7000p_read_word(state, 501);
1566 return 0;
1567}
1568
Olivier Grenie713d54a2011-01-04 04:54:31 -03001569static int dib7000p_read_unc_blocks(struct dvb_frontend *fe, u32 * unc)
Patrick Boettchera75763f2006-10-18 08:34:16 -03001570{
1571 struct dib7000p_state *state = fe->demodulator_priv;
1572 *unc = dib7000p_read_word(state, 506);
1573 return 0;
1574}
1575
Olivier Grenie713d54a2011-01-04 04:54:31 -03001576static int dib7000p_read_signal_strength(struct dvb_frontend *fe, u16 * strength)
Patrick Boettchera75763f2006-10-18 08:34:16 -03001577{
1578 struct dib7000p_state *state = fe->demodulator_priv;
1579 u16 val = dib7000p_read_word(state, 394);
1580 *strength = 65535 - val;
1581 return 0;
1582}
1583
Olivier Grenie713d54a2011-01-04 04:54:31 -03001584static int dib7000p_read_snr(struct dvb_frontend *fe, u16 * snr)
Patrick Boettchera75763f2006-10-18 08:34:16 -03001585{
Olivier Grenieef801962009-09-15 06:46:52 -03001586 struct dib7000p_state *state = fe->demodulator_priv;
1587 u16 val;
1588 s32 signal_mant, signal_exp, noise_mant, noise_exp;
1589 u32 result = 0;
1590
1591 val = dib7000p_read_word(state, 479);
1592 noise_mant = (val >> 4) & 0xff;
1593 noise_exp = ((val & 0xf) << 2);
1594 val = dib7000p_read_word(state, 480);
1595 noise_exp += ((val >> 14) & 0x3);
1596 if ((noise_exp & 0x20) != 0)
1597 noise_exp -= 0x40;
1598
1599 signal_mant = (val >> 6) & 0xFF;
Olivier Grenie713d54a2011-01-04 04:54:31 -03001600 signal_exp = (val & 0x3F);
Olivier Grenieef801962009-09-15 06:46:52 -03001601 if ((signal_exp & 0x20) != 0)
1602 signal_exp -= 0x40;
1603
1604 if (signal_mant != 0)
Olivier Grenie713d54a2011-01-04 04:54:31 -03001605 result = intlog10(2) * 10 * signal_exp + 10 * intlog10(signal_mant);
Olivier Grenieef801962009-09-15 06:46:52 -03001606 else
1607 result = intlog10(2) * 10 * signal_exp - 100;
1608
1609 if (noise_mant != 0)
Olivier Grenie713d54a2011-01-04 04:54:31 -03001610 result -= intlog10(2) * 10 * noise_exp + 10 * intlog10(noise_mant);
Olivier Grenieef801962009-09-15 06:46:52 -03001611 else
1612 result -= intlog10(2) * 10 * noise_exp - 100;
1613
1614 *snr = result / ((1 << 24) / 10);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001615 return 0;
1616}
1617
Olivier Grenie713d54a2011-01-04 04:54:31 -03001618static int dib7000p_fe_get_tune_settings(struct dvb_frontend *fe, struct dvb_frontend_tune_settings *tune)
Patrick Boettchera75763f2006-10-18 08:34:16 -03001619{
1620 tune->min_delay_ms = 1000;
1621 return 0;
1622}
1623
1624static void dib7000p_release(struct dvb_frontend *demod)
1625{
1626 struct dib7000p_state *st = demod->demodulator_priv;
1627 dibx000_exit_i2c_master(&st->i2c_master);
Olivier Grenie713d54a2011-01-04 04:54:31 -03001628 i2c_del_adapter(&st->dib7090_tuner_adap);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001629 kfree(st);
1630}
1631
1632int dib7000pc_detection(struct i2c_adapter *i2c_adap)
1633{
Olivier Grenie5a0deee2011-05-03 12:27:33 -03001634 u8 *tx, *rx;
Patrick Boettchera75763f2006-10-18 08:34:16 -03001635 struct i2c_msg msg[2] = {
Olivier Grenie5a0deee2011-05-03 12:27:33 -03001636 {.addr = 18 >> 1, .flags = 0, .len = 2},
1637 {.addr = 18 >> 1, .flags = I2C_M_RD, .len = 2},
Patrick Boettchera75763f2006-10-18 08:34:16 -03001638 };
Olivier Grenie5a0deee2011-05-03 12:27:33 -03001639 int ret = 0;
1640
1641 tx = kzalloc(2*sizeof(u8), GFP_KERNEL);
1642 if (!tx)
1643 return -ENOMEM;
1644 rx = kzalloc(2*sizeof(u8), GFP_KERNEL);
1645 if (!rx) {
Olivier Grenie5a0deee2011-05-03 12:27:33 -03001646 ret = -ENOMEM;
Dan Carpenter0c61cc3b2011-08-06 05:00:34 -03001647 goto rx_memory_error;
Olivier Grenie5a0deee2011-05-03 12:27:33 -03001648 }
1649
1650 msg[0].buf = tx;
1651 msg[1].buf = rx;
Patrick Boettchera75763f2006-10-18 08:34:16 -03001652
1653 tx[0] = 0x03;
1654 tx[1] = 0x00;
1655
1656 if (i2c_transfer(i2c_adap, msg, 2) == 2)
1657 if (rx[0] == 0x01 && rx[1] == 0xb3) {
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001658 dprintk("-D- DiB7000PC detected");
Patrick Boettchera75763f2006-10-18 08:34:16 -03001659 return 1;
1660 }
1661
1662 msg[0].addr = msg[1].addr = 0x40;
1663
1664 if (i2c_transfer(i2c_adap, msg, 2) == 2)
1665 if (rx[0] == 0x01 && rx[1] == 0xb3) {
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001666 dprintk("-D- DiB7000PC detected");
Patrick Boettchera75763f2006-10-18 08:34:16 -03001667 return 1;
1668 }
1669
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001670 dprintk("-D- DiB7000PC not detected");
Olivier Grenie5a0deee2011-05-03 12:27:33 -03001671
1672 kfree(rx);
1673rx_memory_error:
1674 kfree(tx);
1675 return ret;
Patrick Boettchera75763f2006-10-18 08:34:16 -03001676}
1677EXPORT_SYMBOL(dib7000pc_detection);
1678
Olivier Grenie713d54a2011-01-04 04:54:31 -03001679struct i2c_adapter *dib7000p_get_i2c_master(struct dvb_frontend *demod, enum dibx000_i2c_interface intf, int gating)
Patrick Boettchera75763f2006-10-18 08:34:16 -03001680{
1681 struct dib7000p_state *st = demod->demodulator_priv;
1682 return dibx000_get_i2c_adapter(&st->i2c_master, intf, gating);
1683}
1684EXPORT_SYMBOL(dib7000p_get_i2c_master);
1685
Olivier Grenief8731f42009-09-18 04:08:43 -03001686int dib7000p_pid_filter_ctrl(struct dvb_frontend *fe, u8 onoff)
1687{
Olivier Grenie713d54a2011-01-04 04:54:31 -03001688 struct dib7000p_state *state = fe->demodulator_priv;
1689 u16 val = dib7000p_read_word(state, 235) & 0xffef;
1690 val |= (onoff & 0x1) << 4;
1691 dprintk("PID filter enabled %d", onoff);
1692 return dib7000p_write_word(state, 235, val);
Olivier Grenief8731f42009-09-18 04:08:43 -03001693}
1694EXPORT_SYMBOL(dib7000p_pid_filter_ctrl);
1695
1696int dib7000p_pid_filter(struct dvb_frontend *fe, u8 id, u16 pid, u8 onoff)
1697{
Olivier Grenie713d54a2011-01-04 04:54:31 -03001698 struct dib7000p_state *state = fe->demodulator_priv;
1699 dprintk("PID filter: index %x, PID %d, OnOff %d", id, pid, onoff);
1700 return dib7000p_write_word(state, 241 + id, onoff ? (1 << 13) | pid : 0);
Olivier Grenief8731f42009-09-18 04:08:43 -03001701}
1702EXPORT_SYMBOL(dib7000p_pid_filter);
1703
Patrick Boettchera75763f2006-10-18 08:34:16 -03001704int dib7000p_i2c_enumeration(struct i2c_adapter *i2c, int no_of_demods, u8 default_addr, struct dib7000p_config cfg[])
1705{
Randy Dunlap30d81bb2010-02-08 20:30:44 -03001706 struct dib7000p_state *dpst;
Patrick Boettchera75763f2006-10-18 08:34:16 -03001707 int k = 0;
1708 u8 new_addr = 0;
1709
Randy Dunlap30d81bb2010-02-08 20:30:44 -03001710 dpst = kzalloc(sizeof(struct dib7000p_state), GFP_KERNEL);
1711 if (!dpst)
Andrew Morton0b427602010-04-27 19:09:45 -03001712 return -ENOMEM;
Randy Dunlap30d81bb2010-02-08 20:30:44 -03001713
1714 dpst->i2c_adap = i2c;
Patrick Boettcher79fcce32011-08-03 12:08:21 -03001715 mutex_init(&dpst->i2c_buffer_lock);
Randy Dunlap30d81bb2010-02-08 20:30:44 -03001716
Olivier Grenie713d54a2011-01-04 04:54:31 -03001717 for (k = no_of_demods - 1; k >= 0; k--) {
Randy Dunlap30d81bb2010-02-08 20:30:44 -03001718 dpst->cfg = cfg[k];
Patrick Boettchera75763f2006-10-18 08:34:16 -03001719
1720 /* designated i2c address */
Olivier Grenie713d54a2011-01-04 04:54:31 -03001721 if (cfg[k].default_i2c_addr != 0)
1722 new_addr = cfg[k].default_i2c_addr + (k << 1);
1723 else
1724 new_addr = (0x40 + k) << 1;
Randy Dunlap30d81bb2010-02-08 20:30:44 -03001725 dpst->i2c_addr = new_addr;
Olivier Grenie713d54a2011-01-04 04:54:31 -03001726 dib7000p_write_word(dpst, 1287, 0x0003); /* sram lead in, rdy */
Randy Dunlap30d81bb2010-02-08 20:30:44 -03001727 if (dib7000p_identify(dpst) != 0) {
1728 dpst->i2c_addr = default_addr;
Olivier Grenie713d54a2011-01-04 04:54:31 -03001729 dib7000p_write_word(dpst, 1287, 0x0003); /* sram lead in, rdy */
Randy Dunlap30d81bb2010-02-08 20:30:44 -03001730 if (dib7000p_identify(dpst) != 0) {
Patrick Boettchera75763f2006-10-18 08:34:16 -03001731 dprintk("DiB7000P #%d: not identified\n", k);
Randy Dunlap30d81bb2010-02-08 20:30:44 -03001732 kfree(dpst);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001733 return -EIO;
1734 }
1735 }
1736
1737 /* start diversity to pull_down div_str - just for i2c-enumeration */
Randy Dunlap30d81bb2010-02-08 20:30:44 -03001738 dib7000p_set_output_mode(dpst, OUTMODE_DIVERSITY);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001739
1740 /* set new i2c address and force divstart */
Randy Dunlap30d81bb2010-02-08 20:30:44 -03001741 dib7000p_write_word(dpst, 1285, (new_addr << 2) | 0x2);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001742
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001743 dprintk("IC %d initialized (to i2c_address 0x%x)", k, new_addr);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001744 }
1745
1746 for (k = 0; k < no_of_demods; k++) {
Randy Dunlap30d81bb2010-02-08 20:30:44 -03001747 dpst->cfg = cfg[k];
Olivier Grenie713d54a2011-01-04 04:54:31 -03001748 if (cfg[k].default_i2c_addr != 0)
1749 dpst->i2c_addr = (cfg[k].default_i2c_addr + k) << 1;
1750 else
1751 dpst->i2c_addr = (0x40 + k) << 1;
Patrick Boettchera75763f2006-10-18 08:34:16 -03001752
1753 // unforce divstr
Randy Dunlap30d81bb2010-02-08 20:30:44 -03001754 dib7000p_write_word(dpst, 1285, dpst->i2c_addr << 2);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001755
1756 /* deactivate div - it was just for i2c-enumeration */
Randy Dunlap30d81bb2010-02-08 20:30:44 -03001757 dib7000p_set_output_mode(dpst, OUTMODE_HIGH_Z);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001758 }
1759
Randy Dunlap30d81bb2010-02-08 20:30:44 -03001760 kfree(dpst);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001761 return 0;
1762}
1763EXPORT_SYMBOL(dib7000p_i2c_enumeration);
1764
Olivier Grenie713d54a2011-01-04 04:54:31 -03001765static const s32 lut_1000ln_mant[] = {
1766 6908, 6956, 7003, 7047, 7090, 7131, 7170, 7208, 7244, 7279, 7313, 7346, 7377, 7408, 7438, 7467, 7495, 7523, 7549, 7575, 7600
1767};
1768
1769static s32 dib7000p_get_adc_power(struct dvb_frontend *fe)
1770{
1771 struct dib7000p_state *state = fe->demodulator_priv;
1772 u32 tmp_val = 0, exp = 0, mant = 0;
1773 s32 pow_i;
1774 u16 buf[2];
1775 u8 ix = 0;
1776
1777 buf[0] = dib7000p_read_word(state, 0x184);
1778 buf[1] = dib7000p_read_word(state, 0x185);
1779 pow_i = (buf[0] << 16) | buf[1];
1780 dprintk("raw pow_i = %d", pow_i);
1781
1782 tmp_val = pow_i;
1783 while (tmp_val >>= 1)
1784 exp++;
1785
1786 mant = (pow_i * 1000 / (1 << exp));
1787 dprintk(" mant = %d exp = %d", mant / 1000, exp);
1788
1789 ix = (u8) ((mant - 1000) / 100); /* index of the LUT */
1790 dprintk(" ix = %d", ix);
1791
1792 pow_i = (lut_1000ln_mant[ix] + 693 * (exp - 20) - 6908);
1793 pow_i = (pow_i << 8) / 1000;
1794 dprintk(" pow_i = %d", pow_i);
1795
1796 return pow_i;
1797}
1798
1799static int map_addr_to_serpar_number(struct i2c_msg *msg)
1800{
1801 if ((msg->buf[0] <= 15))
1802 msg->buf[0] -= 1;
1803 else if (msg->buf[0] == 17)
1804 msg->buf[0] = 15;
1805 else if (msg->buf[0] == 16)
1806 msg->buf[0] = 17;
1807 else if (msg->buf[0] == 19)
1808 msg->buf[0] = 16;
1809 else if (msg->buf[0] >= 21 && msg->buf[0] <= 25)
1810 msg->buf[0] -= 3;
1811 else if (msg->buf[0] == 28)
1812 msg->buf[0] = 23;
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001813 else
Olivier Grenie713d54a2011-01-04 04:54:31 -03001814 return -EINVAL;
Olivier Grenie713d54a2011-01-04 04:54:31 -03001815 return 0;
1816}
1817
1818static int w7090p_tuner_write_serpar(struct i2c_adapter *i2c_adap, struct i2c_msg msg[], int num)
1819{
1820 struct dib7000p_state *state = i2c_get_adapdata(i2c_adap);
1821 u8 n_overflow = 1;
1822 u16 i = 1000;
1823 u16 serpar_num = msg[0].buf[0];
1824
1825 while (n_overflow == 1 && i) {
1826 n_overflow = (dib7000p_read_word(state, 1984) >> 1) & 0x1;
1827 i--;
1828 if (i == 0)
1829 dprintk("Tuner ITF: write busy (overflow)");
1830 }
1831 dib7000p_write_word(state, 1985, (1 << 6) | (serpar_num & 0x3f));
1832 dib7000p_write_word(state, 1986, (msg[0].buf[1] << 8) | msg[0].buf[2]);
1833
1834 return num;
1835}
1836
1837static int w7090p_tuner_read_serpar(struct i2c_adapter *i2c_adap, struct i2c_msg msg[], int num)
1838{
1839 struct dib7000p_state *state = i2c_get_adapdata(i2c_adap);
1840 u8 n_overflow = 1, n_empty = 1;
1841 u16 i = 1000;
1842 u16 serpar_num = msg[0].buf[0];
1843 u16 read_word;
1844
1845 while (n_overflow == 1 && i) {
1846 n_overflow = (dib7000p_read_word(state, 1984) >> 1) & 0x1;
1847 i--;
1848 if (i == 0)
1849 dprintk("TunerITF: read busy (overflow)");
1850 }
1851 dib7000p_write_word(state, 1985, (0 << 6) | (serpar_num & 0x3f));
1852
1853 i = 1000;
1854 while (n_empty == 1 && i) {
1855 n_empty = dib7000p_read_word(state, 1984) & 0x1;
1856 i--;
1857 if (i == 0)
1858 dprintk("TunerITF: read busy (empty)");
1859 }
1860 read_word = dib7000p_read_word(state, 1987);
1861 msg[1].buf[0] = (read_word >> 8) & 0xff;
1862 msg[1].buf[1] = (read_word) & 0xff;
1863
1864 return num;
1865}
1866
1867static int w7090p_tuner_rw_serpar(struct i2c_adapter *i2c_adap, struct i2c_msg msg[], int num)
1868{
1869 if (map_addr_to_serpar_number(&msg[0]) == 0) { /* else = Tuner regs to ignore : DIG_CFG, CTRL_RF_LT, PLL_CFG, PWM1_REG, ADCCLK, DIG_CFG_3; SLEEP_EN... */
1870 if (num == 1) { /* write */
1871 return w7090p_tuner_write_serpar(i2c_adap, msg, 1);
1872 } else { /* read */
1873 return w7090p_tuner_read_serpar(i2c_adap, msg, 2);
1874 }
1875 }
1876 return num;
1877}
1878
Olivier Greniea685dbb2011-08-05 14:10:40 -03001879static int dib7090p_rw_on_apb(struct i2c_adapter *i2c_adap,
1880 struct i2c_msg msg[], int num, u16 apb_address)
Olivier Grenie713d54a2011-01-04 04:54:31 -03001881{
1882 struct dib7000p_state *state = i2c_get_adapdata(i2c_adap);
1883 u16 word;
1884
1885 if (num == 1) { /* write */
1886 dib7000p_write_word(state, apb_address, ((msg[0].buf[1] << 8) | (msg[0].buf[2])));
1887 } else {
1888 word = dib7000p_read_word(state, apb_address);
1889 msg[1].buf[0] = (word >> 8) & 0xff;
1890 msg[1].buf[1] = (word) & 0xff;
1891 }
1892
1893 return num;
1894}
1895
1896static int dib7090_tuner_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg msg[], int num)
1897{
1898 struct dib7000p_state *state = i2c_get_adapdata(i2c_adap);
1899
1900 u16 apb_address = 0, word;
1901 int i = 0;
1902 switch (msg[0].buf[0]) {
1903 case 0x12:
1904 apb_address = 1920;
1905 break;
1906 case 0x14:
1907 apb_address = 1921;
1908 break;
1909 case 0x24:
1910 apb_address = 1922;
1911 break;
1912 case 0x1a:
1913 apb_address = 1923;
1914 break;
1915 case 0x22:
1916 apb_address = 1924;
1917 break;
1918 case 0x33:
1919 apb_address = 1926;
1920 break;
1921 case 0x34:
1922 apb_address = 1927;
1923 break;
1924 case 0x35:
1925 apb_address = 1928;
1926 break;
1927 case 0x36:
1928 apb_address = 1929;
1929 break;
1930 case 0x37:
1931 apb_address = 1930;
1932 break;
1933 case 0x38:
1934 apb_address = 1931;
1935 break;
1936 case 0x39:
1937 apb_address = 1932;
1938 break;
1939 case 0x2a:
1940 apb_address = 1935;
1941 break;
1942 case 0x2b:
1943 apb_address = 1936;
1944 break;
1945 case 0x2c:
1946 apb_address = 1937;
1947 break;
1948 case 0x2d:
1949 apb_address = 1938;
1950 break;
1951 case 0x2e:
1952 apb_address = 1939;
1953 break;
1954 case 0x2f:
1955 apb_address = 1940;
1956 break;
1957 case 0x30:
1958 apb_address = 1941;
1959 break;
1960 case 0x31:
1961 apb_address = 1942;
1962 break;
1963 case 0x32:
1964 apb_address = 1943;
1965 break;
1966 case 0x3e:
1967 apb_address = 1944;
1968 break;
1969 case 0x3f:
1970 apb_address = 1945;
1971 break;
1972 case 0x40:
1973 apb_address = 1948;
1974 break;
1975 case 0x25:
1976 apb_address = 914;
1977 break;
1978 case 0x26:
1979 apb_address = 915;
1980 break;
1981 case 0x27:
Olivier Grenie2e802862011-08-05 10:39:15 -03001982 apb_address = 917;
Olivier Grenie713d54a2011-01-04 04:54:31 -03001983 break;
1984 case 0x28:
Olivier Grenie2e802862011-08-05 10:39:15 -03001985 apb_address = 916;
Olivier Grenie713d54a2011-01-04 04:54:31 -03001986 break;
1987 case 0x1d:
1988 i = ((dib7000p_read_word(state, 72) >> 12) & 0x3);
1989 word = dib7000p_read_word(state, 384 + i);
1990 msg[1].buf[0] = (word >> 8) & 0xff;
1991 msg[1].buf[1] = (word) & 0xff;
1992 return num;
1993 case 0x1f:
1994 if (num == 1) { /* write */
1995 word = (u16) ((msg[0].buf[1] << 8) | msg[0].buf[2]);
1996 word &= 0x3;
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001997 word = (dib7000p_read_word(state, 72) & ~(3 << 12)) | (word << 12);
Olivier Grenie713d54a2011-01-04 04:54:31 -03001998 dib7000p_write_word(state, 72, word); /* Set the proper input */
1999 return num;
2000 }
2001 }
2002
2003 if (apb_address != 0) /* R/W acces via APB */
2004 return dib7090p_rw_on_apb(i2c_adap, msg, num, apb_address);
2005 else /* R/W access via SERPAR */
2006 return w7090p_tuner_rw_serpar(i2c_adap, msg, num);
2007
2008 return 0;
2009}
2010
2011static u32 dib7000p_i2c_func(struct i2c_adapter *adapter)
2012{
2013 return I2C_FUNC_I2C;
2014}
2015
2016static struct i2c_algorithm dib7090_tuner_xfer_algo = {
2017 .master_xfer = dib7090_tuner_xfer,
2018 .functionality = dib7000p_i2c_func,
2019};
2020
2021struct i2c_adapter *dib7090_get_i2c_tuner(struct dvb_frontend *fe)
2022{
2023 struct dib7000p_state *st = fe->demodulator_priv;
2024 return &st->dib7090_tuner_adap;
2025}
2026EXPORT_SYMBOL(dib7090_get_i2c_tuner);
2027
2028static int dib7090_host_bus_drive(struct dib7000p_state *state, u8 drive)
2029{
2030 u16 reg;
2031
2032 /* drive host bus 2, 3, 4 */
2033 reg = dib7000p_read_word(state, 1798) & ~((0x7) | (0x7 << 6) | (0x7 << 12));
2034 reg |= (drive << 12) | (drive << 6) | drive;
2035 dib7000p_write_word(state, 1798, reg);
2036
2037 /* drive host bus 5,6 */
2038 reg = dib7000p_read_word(state, 1799) & ~((0x7 << 2) | (0x7 << 8));
2039 reg |= (drive << 8) | (drive << 2);
2040 dib7000p_write_word(state, 1799, reg);
2041
2042 /* drive host bus 7, 8, 9 */
2043 reg = dib7000p_read_word(state, 1800) & ~((0x7) | (0x7 << 6) | (0x7 << 12));
2044 reg |= (drive << 12) | (drive << 6) | drive;
2045 dib7000p_write_word(state, 1800, reg);
2046
2047 /* drive host bus 10, 11 */
2048 reg = dib7000p_read_word(state, 1801) & ~((0x7 << 2) | (0x7 << 8));
2049 reg |= (drive << 8) | (drive << 2);
2050 dib7000p_write_word(state, 1801, reg);
2051
2052 /* drive host bus 12, 13, 14 */
2053 reg = dib7000p_read_word(state, 1802) & ~((0x7) | (0x7 << 6) | (0x7 << 12));
2054 reg |= (drive << 12) | (drive << 6) | drive;
2055 dib7000p_write_word(state, 1802, reg);
2056
2057 return 0;
2058}
2059
2060static u32 dib7090_calcSyncFreq(u32 P_Kin, u32 P_Kout, u32 insertExtSynchro, u32 syncSize)
2061{
2062 u32 quantif = 3;
2063 u32 nom = (insertExtSynchro * P_Kin + syncSize);
2064 u32 denom = P_Kout;
2065 u32 syncFreq = ((nom << quantif) / denom);
2066
2067 if ((syncFreq & ((1 << quantif) - 1)) != 0)
2068 syncFreq = (syncFreq >> quantif) + 1;
2069 else
2070 syncFreq = (syncFreq >> quantif);
2071
2072 if (syncFreq != 0)
2073 syncFreq = syncFreq - 1;
2074
2075 return syncFreq;
2076}
2077
2078static int dib7090_cfg_DibTx(struct dib7000p_state *state, u32 P_Kin, u32 P_Kout, u32 insertExtSynchro, u32 synchroMode, u32 syncWord, u32 syncSize)
2079{
Olivier Grenie713d54a2011-01-04 04:54:31 -03002080 dprintk("Configure DibStream Tx");
Olivier Grenie713d54a2011-01-04 04:54:31 -03002081
2082 dib7000p_write_word(state, 1615, 1);
2083 dib7000p_write_word(state, 1603, P_Kin);
2084 dib7000p_write_word(state, 1605, P_Kout);
2085 dib7000p_write_word(state, 1606, insertExtSynchro);
2086 dib7000p_write_word(state, 1608, synchroMode);
2087 dib7000p_write_word(state, 1609, (syncWord >> 16) & 0xffff);
2088 dib7000p_write_word(state, 1610, syncWord & 0xffff);
2089 dib7000p_write_word(state, 1612, syncSize);
2090 dib7000p_write_word(state, 1615, 0);
2091
Olivier Grenie713d54a2011-01-04 04:54:31 -03002092 return 0;
2093}
2094
2095static int dib7090_cfg_DibRx(struct dib7000p_state *state, u32 P_Kin, u32 P_Kout, u32 synchroMode, u32 insertExtSynchro, u32 syncWord, u32 syncSize,
2096 u32 dataOutRate)
2097{
2098 u32 syncFreq;
2099
2100 dprintk("Configure DibStream Rx");
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002101 if ((P_Kin != 0) && (P_Kout != 0)) {
Olivier Grenie713d54a2011-01-04 04:54:31 -03002102 syncFreq = dib7090_calcSyncFreq(P_Kin, P_Kout, insertExtSynchro, syncSize);
2103 dib7000p_write_word(state, 1542, syncFreq);
2104 }
2105 dib7000p_write_word(state, 1554, 1);
2106 dib7000p_write_word(state, 1536, P_Kin);
2107 dib7000p_write_word(state, 1537, P_Kout);
2108 dib7000p_write_word(state, 1539, synchroMode);
2109 dib7000p_write_word(state, 1540, (syncWord >> 16) & 0xffff);
2110 dib7000p_write_word(state, 1541, syncWord & 0xffff);
2111 dib7000p_write_word(state, 1543, syncSize);
2112 dib7000p_write_word(state, 1544, dataOutRate);
2113 dib7000p_write_word(state, 1554, 0);
2114
2115 return 0;
2116}
2117
Olivier Grenie2e802862011-08-05 10:39:15 -03002118static void dib7090_enMpegMux(struct dib7000p_state *state, int onoff)
Olivier Grenie713d54a2011-01-04 04:54:31 -03002119{
Olivier Grenie2e802862011-08-05 10:39:15 -03002120 u16 reg_1287 = dib7000p_read_word(state, 1287);
Olivier Grenie713d54a2011-01-04 04:54:31 -03002121
Olivier Grenie2e802862011-08-05 10:39:15 -03002122 switch (onoff) {
2123 case 1:
2124 reg_1287 &= ~(1<<7);
2125 break;
2126 case 0:
2127 reg_1287 |= (1<<7);
2128 break;
2129 }
Olivier Grenie713d54a2011-01-04 04:54:31 -03002130
Olivier Grenie2e802862011-08-05 10:39:15 -03002131 dib7000p_write_word(state, 1287, reg_1287);
Olivier Grenie713d54a2011-01-04 04:54:31 -03002132}
2133
Olivier Grenie2e802862011-08-05 10:39:15 -03002134static void dib7090_configMpegMux(struct dib7000p_state *state,
2135 u16 pulseWidth, u16 enSerialMode, u16 enSerialClkDiv2)
Olivier Grenie713d54a2011-01-04 04:54:31 -03002136{
Olivier Grenie713d54a2011-01-04 04:54:31 -03002137 dprintk("Enable Mpeg mux");
Olivier Grenie713d54a2011-01-04 04:54:31 -03002138
Olivier Grenie2e802862011-08-05 10:39:15 -03002139 dib7090_enMpegMux(state, 0);
Olivier Grenie713d54a2011-01-04 04:54:31 -03002140
Olivier Grenie2e802862011-08-05 10:39:15 -03002141 /* If the input mode is MPEG do not divide the serial clock */
2142 if ((enSerialMode == 1) && (state->input_mode_mpeg == 1))
2143 enSerialClkDiv2 = 0;
Olivier Grenie713d54a2011-01-04 04:54:31 -03002144
Olivier Grenie2e802862011-08-05 10:39:15 -03002145 dib7000p_write_word(state, 1287, ((pulseWidth & 0x1f) << 2)
2146 | ((enSerialMode & 0x1) << 1)
2147 | (enSerialClkDiv2 & 0x1));
2148
2149 dib7090_enMpegMux(state, 1);
Olivier Grenie713d54a2011-01-04 04:54:31 -03002150}
2151
Olivier Grenie2e802862011-08-05 10:39:15 -03002152static void dib7090_setDibTxMux(struct dib7000p_state *state, int mode)
Olivier Grenie713d54a2011-01-04 04:54:31 -03002153{
Olivier Grenie2e802862011-08-05 10:39:15 -03002154 u16 reg_1288 = dib7000p_read_word(state, 1288) & ~(0x7 << 7);
Olivier Grenie713d54a2011-01-04 04:54:31 -03002155
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002156 switch (mode) {
Olivier Grenie2e802862011-08-05 10:39:15 -03002157 case MPEG_ON_DIBTX:
2158 dprintk("SET MPEG ON DIBSTREAM TX");
2159 dib7090_cfg_DibTx(state, 8, 5, 0, 0, 0, 0);
2160 reg_1288 |= (1<<9);
Olivier Grenie713d54a2011-01-04 04:54:31 -03002161 break;
Olivier Grenie2e802862011-08-05 10:39:15 -03002162 case DIV_ON_DIBTX:
2163 dprintk("SET DIV_OUT ON DIBSTREAM TX");
2164 dib7090_cfg_DibTx(state, 5, 5, 0, 0, 0, 0);
2165 reg_1288 |= (1<<8);
Olivier Grenie713d54a2011-01-04 04:54:31 -03002166 break;
Olivier Grenie2e802862011-08-05 10:39:15 -03002167 case ADC_ON_DIBTX:
2168 dprintk("SET ADC_OUT ON DIBSTREAM TX");
2169 dib7090_cfg_DibTx(state, 20, 5, 10, 0, 0, 0);
2170 reg_1288 |= (1<<7);
2171 break;
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002172 default:
Olivier Grenie713d54a2011-01-04 04:54:31 -03002173 break;
2174 }
Olivier Grenie2e802862011-08-05 10:39:15 -03002175 dib7000p_write_word(state, 1288, reg_1288);
Olivier Grenie713d54a2011-01-04 04:54:31 -03002176}
2177
Olivier Grenie2e802862011-08-05 10:39:15 -03002178static void dib7090_setHostBusMux(struct dib7000p_state *state, int mode)
Olivier Grenie713d54a2011-01-04 04:54:31 -03002179{
Olivier Grenie2e802862011-08-05 10:39:15 -03002180 u16 reg_1288 = dib7000p_read_word(state, 1288) & ~(0x7 << 4);
2181
2182 switch (mode) {
2183 case DEMOUT_ON_HOSTBUS:
2184 dprintk("SET DEM OUT OLD INTERF ON HOST BUS");
2185 dib7090_enMpegMux(state, 0);
2186 reg_1288 |= (1<<6);
2187 break;
2188 case DIBTX_ON_HOSTBUS:
2189 dprintk("SET DIBSTREAM TX ON HOST BUS");
2190 dib7090_enMpegMux(state, 0);
2191 reg_1288 |= (1<<5);
2192 break;
2193 case MPEG_ON_HOSTBUS:
2194 dprintk("SET MPEG MUX ON HOST BUS");
2195 reg_1288 |= (1<<4);
2196 break;
2197 default:
2198 break;
2199 }
2200 dib7000p_write_word(state, 1288, reg_1288);
2201}
2202
2203int dib7090_set_diversity_in(struct dvb_frontend *fe, int onoff)
2204{
2205 struct dib7000p_state *state = fe->demodulator_priv;
2206 u16 reg_1287;
2207
Olivier Grenie713d54a2011-01-04 04:54:31 -03002208 switch (onoff) {
Olivier Grenie2e802862011-08-05 10:39:15 -03002209 case 0: /* only use the internal way - not the diversity input */
2210 dprintk("%s mode OFF : by default Enable Mpeg INPUT", __func__);
2211 dib7090_cfg_DibRx(state, 8, 5, 0, 0, 0, 8, 0);
2212
2213 /* Do not divide the serial clock of MPEG MUX */
2214 /* in SERIAL MODE in case input mode MPEG is used */
2215 reg_1287 = dib7000p_read_word(state, 1287);
2216 /* enSerialClkDiv2 == 1 ? */
2217 if ((reg_1287 & 0x1) == 1) {
2218 /* force enSerialClkDiv2 = 0 */
2219 reg_1287 &= ~0x1;
2220 dib7000p_write_word(state, 1287, reg_1287);
2221 }
2222 state->input_mode_mpeg = 1;
2223 break;
2224 case 1: /* both ways */
2225 case 2: /* only the diversity input */
2226 dprintk("%s ON : Enable diversity INPUT", __func__);
2227 dib7090_cfg_DibRx(state, 5, 5, 0, 0, 0, 0, 0);
2228 state->input_mode_mpeg = 0;
2229 break;
Olivier Grenie713d54a2011-01-04 04:54:31 -03002230 }
2231
Olivier Grenie2e802862011-08-05 10:39:15 -03002232 dib7000p_set_diversity_in(&state->demod, onoff);
Olivier Grenie713d54a2011-01-04 04:54:31 -03002233 return 0;
2234}
2235
2236static int dib7090_set_output_mode(struct dvb_frontend *fe, int mode)
2237{
2238 struct dib7000p_state *state = fe->demodulator_priv;
2239
2240 u16 outreg, smo_mode, fifo_threshold;
2241 u8 prefer_mpeg_mux_use = 1;
2242 int ret = 0;
2243
2244 dib7090_host_bus_drive(state, 1);
2245
2246 fifo_threshold = 1792;
2247 smo_mode = (dib7000p_read_word(state, 235) & 0x0050) | (1 << 1);
2248 outreg = dib7000p_read_word(state, 1286) & ~((1 << 10) | (0x7 << 6) | (1 << 1));
2249
2250 switch (mode) {
2251 case OUTMODE_HIGH_Z:
2252 outreg = 0;
2253 break;
2254
2255 case OUTMODE_MPEG2_SERIAL:
2256 if (prefer_mpeg_mux_use) {
Olivier Grenie2e802862011-08-05 10:39:15 -03002257 dprintk("setting output mode TS_SERIAL using Mpeg Mux");
2258 dib7090_configMpegMux(state, 3, 1, 1);
2259 dib7090_setHostBusMux(state, MPEG_ON_HOSTBUS);
2260 } else {/* Use Smooth block */
2261 dprintk("setting output mode TS_SERIAL using Smooth bloc");
2262 dib7090_setHostBusMux(state, DEMOUT_ON_HOSTBUS);
2263 outreg |= (2<<6) | (0 << 1);
Olivier Grenie713d54a2011-01-04 04:54:31 -03002264 }
2265 break;
2266
2267 case OUTMODE_MPEG2_PAR_GATED_CLK:
2268 if (prefer_mpeg_mux_use) {
Olivier Grenie2e802862011-08-05 10:39:15 -03002269 dprintk("setting output mode TS_PARALLEL_GATED using Mpeg Mux");
2270 dib7090_configMpegMux(state, 2, 0, 0);
2271 dib7090_setHostBusMux(state, MPEG_ON_HOSTBUS);
2272 } else { /* Use Smooth block */
2273 dprintk("setting output mode TS_PARALLEL_GATED using Smooth block");
2274 dib7090_setHostBusMux(state, DEMOUT_ON_HOSTBUS);
2275 outreg |= (0<<6);
Olivier Grenie713d54a2011-01-04 04:54:31 -03002276 }
2277 break;
2278
2279 case OUTMODE_MPEG2_PAR_CONT_CLK: /* Using Smooth block only */
Olivier Grenie2e802862011-08-05 10:39:15 -03002280 dprintk("setting output mode TS_PARALLEL_CONT using Smooth block");
2281 dib7090_setHostBusMux(state, DEMOUT_ON_HOSTBUS);
2282 outreg |= (1<<6);
Olivier Grenie713d54a2011-01-04 04:54:31 -03002283 break;
2284
2285 case OUTMODE_MPEG2_FIFO: /* Using Smooth block because not supported by new Mpeg Mux bloc */
Olivier Grenie2e802862011-08-05 10:39:15 -03002286 dprintk("setting output mode TS_FIFO using Smooth block");
2287 dib7090_setHostBusMux(state, DEMOUT_ON_HOSTBUS);
2288 outreg |= (5<<6);
Olivier Grenie713d54a2011-01-04 04:54:31 -03002289 smo_mode |= (3 << 1);
2290 fifo_threshold = 512;
2291 break;
2292
2293 case OUTMODE_DIVERSITY:
Olivier Grenie2e802862011-08-05 10:39:15 -03002294 dprintk("setting output mode MODE_DIVERSITY");
2295 dib7090_setDibTxMux(state, DIV_ON_DIBTX);
2296 dib7090_setHostBusMux(state, DIBTX_ON_HOSTBUS);
Olivier Grenie713d54a2011-01-04 04:54:31 -03002297 break;
2298
2299 case OUTMODE_ANALOG_ADC:
Olivier Grenie2e802862011-08-05 10:39:15 -03002300 dprintk("setting output mode MODE_ANALOG_ADC");
2301 dib7090_setDibTxMux(state, ADC_ON_DIBTX);
2302 dib7090_setHostBusMux(state, DIBTX_ON_HOSTBUS);
Olivier Grenie713d54a2011-01-04 04:54:31 -03002303 break;
2304 }
Olivier Grenie2e802862011-08-05 10:39:15 -03002305 if (mode != OUTMODE_HIGH_Z)
2306 outreg |= (1 << 10);
Olivier Grenie713d54a2011-01-04 04:54:31 -03002307
2308 if (state->cfg.output_mpeg2_in_188_bytes)
2309 smo_mode |= (1 << 5);
2310
2311 ret |= dib7000p_write_word(state, 235, smo_mode);
2312 ret |= dib7000p_write_word(state, 236, fifo_threshold); /* synchronous fread */
Olivier Grenie2e802862011-08-05 10:39:15 -03002313 ret |= dib7000p_write_word(state, 1286, outreg);
Olivier Grenie713d54a2011-01-04 04:54:31 -03002314
2315 return ret;
2316}
2317
2318int dib7090_tuner_sleep(struct dvb_frontend *fe, int onoff)
2319{
2320 struct dib7000p_state *state = fe->demodulator_priv;
2321 u16 en_cur_state;
2322
2323 dprintk("sleep dib7090: %d", onoff);
2324
2325 en_cur_state = dib7000p_read_word(state, 1922);
2326
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002327 if (en_cur_state > 0xff)
Olivier Grenie713d54a2011-01-04 04:54:31 -03002328 state->tuner_enable = en_cur_state;
Olivier Grenie713d54a2011-01-04 04:54:31 -03002329
2330 if (onoff)
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002331 en_cur_state &= 0x00ff;
Olivier Grenie713d54a2011-01-04 04:54:31 -03002332 else {
2333 if (state->tuner_enable != 0)
2334 en_cur_state = state->tuner_enable;
2335 }
2336
2337 dib7000p_write_word(state, 1922, en_cur_state);
2338
2339 return 0;
2340}
2341EXPORT_SYMBOL(dib7090_tuner_sleep);
2342
Olivier Grenie713d54a2011-01-04 04:54:31 -03002343int dib7090_get_adc_power(struct dvb_frontend *fe)
2344{
2345 return dib7000p_get_adc_power(fe);
2346}
2347EXPORT_SYMBOL(dib7090_get_adc_power);
2348
2349int dib7090_slave_reset(struct dvb_frontend *fe)
2350{
2351 struct dib7000p_state *state = fe->demodulator_priv;
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002352 u16 reg;
Olivier Grenie713d54a2011-01-04 04:54:31 -03002353
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002354 reg = dib7000p_read_word(state, 1794);
2355 dib7000p_write_word(state, 1794, reg | (4 << 12));
Olivier Grenie713d54a2011-01-04 04:54:31 -03002356
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002357 dib7000p_write_word(state, 1032, 0xffff);
2358 return 0;
Olivier Grenie713d54a2011-01-04 04:54:31 -03002359}
2360EXPORT_SYMBOL(dib7090_slave_reset);
2361
Patrick Boettchera75763f2006-10-18 08:34:16 -03002362static struct dvb_frontend_ops dib7000p_ops;
Olivier Grenie713d54a2011-01-04 04:54:31 -03002363struct dvb_frontend *dib7000p_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr, struct dib7000p_config *cfg)
Patrick Boettchera75763f2006-10-18 08:34:16 -03002364{
2365 struct dvb_frontend *demod;
2366 struct dib7000p_state *st;
2367 st = kzalloc(sizeof(struct dib7000p_state), GFP_KERNEL);
2368 if (st == NULL)
2369 return NULL;
2370
2371 memcpy(&st->cfg, cfg, sizeof(struct dib7000p_config));
2372 st->i2c_adap = i2c_adap;
2373 st->i2c_addr = i2c_addr;
2374 st->gpio_val = cfg->gpio_val;
2375 st->gpio_dir = cfg->gpio_dir;
2376
Steven Totha38d6e32008-04-22 15:37:01 -03002377 /* Ensure the output mode remains at the previous default if it's
2378 * not specifically set by the caller.
2379 */
Olivier Grenie713d54a2011-01-04 04:54:31 -03002380 if ((st->cfg.output_mode != OUTMODE_MPEG2_SERIAL) && (st->cfg.output_mode != OUTMODE_MPEG2_PAR_GATED_CLK))
Steven Totha38d6e32008-04-22 15:37:01 -03002381 st->cfg.output_mode = OUTMODE_MPEG2_FIFO;
2382
Olivier Grenie713d54a2011-01-04 04:54:31 -03002383 demod = &st->demod;
Patrick Boettchera75763f2006-10-18 08:34:16 -03002384 demod->demodulator_priv = st;
2385 memcpy(&st->demod.ops, &dib7000p_ops, sizeof(struct dvb_frontend_ops));
Patrick Boettcher79fcce32011-08-03 12:08:21 -03002386 mutex_init(&st->i2c_buffer_lock);
Patrick Boettchera75763f2006-10-18 08:34:16 -03002387
Olivier Grenie713d54a2011-01-04 04:54:31 -03002388 dib7000p_write_word(st, 1287, 0x0003); /* sram lead in, rdy */
Olivier Grenieeac1fe12009-09-23 13:41:27 -03002389
Patrick Boettchera75763f2006-10-18 08:34:16 -03002390 if (dib7000p_identify(st) != 0)
2391 goto error;
2392
Olivier Grenie713d54a2011-01-04 04:54:31 -03002393 st->version = dib7000p_read_word(st, 897);
2394
Martin Samek7646b9d2009-09-30 22:59:09 -03002395 /* FIXME: make sure the dev.parent field is initialized, or else
Patrick Boettcher79fcce32011-08-03 12:08:21 -03002396 request_firmware() will hit an OOPS (this should be moved somewhere
2397 more common) */
2398 st->i2c_master.gated_tuner_i2c_adap.dev.parent = i2c_adap->dev.parent;
Martin Samek7646b9d2009-09-30 22:59:09 -03002399
Devin Heitmueller85ec9d72009-07-20 00:45:25 -03002400 /* FIXME: make sure the dev.parent field is initialized, or else
2401 request_firmware() will hit an OOPS (this should be moved somewhere
2402 more common) */
2403 st->i2c_master.gated_tuner_i2c_adap.dev.parent = i2c_adap->dev.parent;
2404
Patrick Boettchera75763f2006-10-18 08:34:16 -03002405 dibx000_init_i2c_master(&st->i2c_master, DIB7000P, st->i2c_adap, st->i2c_addr);
2406
Olivier Grenie713d54a2011-01-04 04:54:31 -03002407 /* init 7090 tuner adapter */
2408 strncpy(st->dib7090_tuner_adap.name, "DiB7090 tuner interface", sizeof(st->dib7090_tuner_adap.name));
2409 st->dib7090_tuner_adap.algo = &dib7090_tuner_xfer_algo;
2410 st->dib7090_tuner_adap.algo_data = NULL;
2411 st->dib7090_tuner_adap.dev.parent = st->i2c_adap->dev.parent;
2412 i2c_set_adapdata(&st->dib7090_tuner_adap, st);
2413 i2c_add_adapter(&st->dib7090_tuner_adap);
2414
Patrick Boettchera75763f2006-10-18 08:34:16 -03002415 dib7000p_demod_reset(st);
2416
Olivier Grenie713d54a2011-01-04 04:54:31 -03002417 if (st->version == SOC7090) {
2418 dib7090_set_output_mode(demod, st->cfg.output_mode);
2419 dib7090_set_diversity_in(demod, 0);
2420 }
2421
Patrick Boettchera75763f2006-10-18 08:34:16 -03002422 return demod;
2423
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002424error:
Patrick Boettchera75763f2006-10-18 08:34:16 -03002425 kfree(st);
2426 return NULL;
2427}
2428EXPORT_SYMBOL(dib7000p_attach);
2429
2430static struct dvb_frontend_ops dib7000p_ops = {
2431 .info = {
Olivier Grenie713d54a2011-01-04 04:54:31 -03002432 .name = "DiBcom 7000PC",
2433 .type = FE_OFDM,
2434 .frequency_min = 44250000,
2435 .frequency_max = 867250000,
2436 .frequency_stepsize = 62500,
2437 .caps = FE_CAN_INVERSION_AUTO |
2438 FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
2439 FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
2440 FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO |
2441 FE_CAN_TRANSMISSION_MODE_AUTO | FE_CAN_GUARD_INTERVAL_AUTO | FE_CAN_RECOVER | FE_CAN_HIERARCHY_AUTO,
2442 },
Patrick Boettchera75763f2006-10-18 08:34:16 -03002443
Olivier Grenie713d54a2011-01-04 04:54:31 -03002444 .release = dib7000p_release,
Patrick Boettchera75763f2006-10-18 08:34:16 -03002445
Olivier Grenie713d54a2011-01-04 04:54:31 -03002446 .init = dib7000p_wakeup,
2447 .sleep = dib7000p_sleep,
Patrick Boettchera75763f2006-10-18 08:34:16 -03002448
Olivier Grenie713d54a2011-01-04 04:54:31 -03002449 .set_frontend = dib7000p_set_frontend,
2450 .get_tune_settings = dib7000p_fe_get_tune_settings,
2451 .get_frontend = dib7000p_get_frontend,
Patrick Boettchera75763f2006-10-18 08:34:16 -03002452
Olivier Grenie713d54a2011-01-04 04:54:31 -03002453 .read_status = dib7000p_read_status,
2454 .read_ber = dib7000p_read_ber,
Patrick Boettchera75763f2006-10-18 08:34:16 -03002455 .read_signal_strength = dib7000p_read_signal_strength,
Olivier Grenie713d54a2011-01-04 04:54:31 -03002456 .read_snr = dib7000p_read_snr,
2457 .read_ucblocks = dib7000p_read_unc_blocks,
Patrick Boettchera75763f2006-10-18 08:34:16 -03002458};
2459
Olivier Grenie713d54a2011-01-04 04:54:31 -03002460MODULE_AUTHOR("Olivier Grenie <ogrenie@dibcom.fr>");
Patrick Boettchera75763f2006-10-18 08:34:16 -03002461MODULE_AUTHOR("Patrick Boettcher <pboettcher@dibcom.fr>");
2462MODULE_DESCRIPTION("Driver for the DiBcom 7000PC COFDM demodulator");
2463MODULE_LICENSE("GPL");