blob: 99832078b6a0e70a7c376fcf0cc8331052db19a0 [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 */
Olivier Grenie713d54a2011-01-04 04:54:31 -030084static int dib7090_set_output_mode(struct dvb_frontend *fe, int mode);
85static int dib7090_set_diversity_in(struct dvb_frontend *fe, int onoff);
Olivier Grenie2e802862011-08-05 10:39:15 -030086static void dib7090_setDibTxMux(struct dib7000p_state *state, int mode);
87static void dib7090_setHostBusMux(struct dib7000p_state *state, int mode);
Olivier Grenie713d54a2011-01-04 04:54:31 -030088
Patrick Boettchera75763f2006-10-18 08:34:16 -030089static u16 dib7000p_read_word(struct dib7000p_state *state, u16 reg)
90{
Patrick Boettcher79fcce32011-08-03 12:08:21 -030091 u16 ret;
92
93 if (mutex_lock_interruptible(&state->i2c_buffer_lock) < 0) {
94 dprintk("could not acquire lock");
95 return 0;
96 }
97
Olivier Grenie5a0deee2011-05-03 12:27:33 -030098 state->i2c_write_buffer[0] = reg >> 8;
99 state->i2c_write_buffer[1] = reg & 0xff;
Patrick Boettchera75763f2006-10-18 08:34:16 -0300100
Olivier Grenie5a0deee2011-05-03 12:27:33 -0300101 memset(state->msg, 0, 2 * sizeof(struct i2c_msg));
102 state->msg[0].addr = state->i2c_addr >> 1;
103 state->msg[0].flags = 0;
104 state->msg[0].buf = state->i2c_write_buffer;
105 state->msg[0].len = 2;
106 state->msg[1].addr = state->i2c_addr >> 1;
107 state->msg[1].flags = I2C_M_RD;
108 state->msg[1].buf = state->i2c_read_buffer;
109 state->msg[1].len = 2;
110
111 if (i2c_transfer(state->i2c_adap, state->msg, 2) != 2)
Olivier Grenie713d54a2011-01-04 04:54:31 -0300112 dprintk("i2c read error on %d", reg);
Patrick Boettchera75763f2006-10-18 08:34:16 -0300113
Patrick Boettcher79fcce32011-08-03 12:08:21 -0300114 ret = (state->i2c_read_buffer[0] << 8) | state->i2c_read_buffer[1];
115 mutex_unlock(&state->i2c_buffer_lock);
116 return ret;
Patrick Boettchera75763f2006-10-18 08:34:16 -0300117}
118
119static int dib7000p_write_word(struct dib7000p_state *state, u16 reg, u16 val)
120{
Patrick Boettcher79fcce32011-08-03 12:08:21 -0300121 int ret;
122
123 if (mutex_lock_interruptible(&state->i2c_buffer_lock) < 0) {
124 dprintk("could not acquire lock");
125 return -EINVAL;
126 }
127
Olivier Grenie5a0deee2011-05-03 12:27:33 -0300128 state->i2c_write_buffer[0] = (reg >> 8) & 0xff;
129 state->i2c_write_buffer[1] = reg & 0xff;
130 state->i2c_write_buffer[2] = (val >> 8) & 0xff;
131 state->i2c_write_buffer[3] = val & 0xff;
132
133 memset(&state->msg[0], 0, sizeof(struct i2c_msg));
134 state->msg[0].addr = state->i2c_addr >> 1;
135 state->msg[0].flags = 0;
136 state->msg[0].buf = state->i2c_write_buffer;
137 state->msg[0].len = 4;
138
Patrick Boettcher79fcce32011-08-03 12:08:21 -0300139 ret = (i2c_transfer(state->i2c_adap, state->msg, 1) != 1 ?
140 -EREMOTEIO : 0);
141 mutex_unlock(&state->i2c_buffer_lock);
142 return ret;
Patrick Boettchera75763f2006-10-18 08:34:16 -0300143}
Olivier Grenie713d54a2011-01-04 04:54:31 -0300144
145static void dib7000p_write_tab(struct dib7000p_state *state, u16 * buf)
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300146{
147 u16 l = 0, r, *n;
148 n = buf;
149 l = *n++;
150 while (l) {
151 r = *n++;
152
153 do {
154 dib7000p_write_word(state, r, *n++);
155 r++;
156 } while (--l);
157 l = *n++;
158 }
159}
160
Patrick Boettchera75763f2006-10-18 08:34:16 -0300161static int dib7000p_set_output_mode(struct dib7000p_state *state, int mode)
162{
Olivier Grenie713d54a2011-01-04 04:54:31 -0300163 int ret = 0;
Patrick Boettchera75763f2006-10-18 08:34:16 -0300164 u16 outreg, fifo_threshold, smo_mode;
165
166 outreg = 0;
167 fifo_threshold = 1792;
Olivier Grenieeac1fe12009-09-23 13:41:27 -0300168 smo_mode = (dib7000p_read_word(state, 235) & 0x0050) | (1 << 1);
Patrick Boettchera75763f2006-10-18 08:34:16 -0300169
Olivier Grenie713d54a2011-01-04 04:54:31 -0300170 dprintk("setting output mode for demod %p to %d", &state->demod, mode);
Patrick Boettchera75763f2006-10-18 08:34:16 -0300171
172 switch (mode) {
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300173 case OUTMODE_MPEG2_PAR_GATED_CLK:
Olivier Grenie713d54a2011-01-04 04:54:31 -0300174 outreg = (1 << 10); /* 0x0400 */
175 break;
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300176 case OUTMODE_MPEG2_PAR_CONT_CLK:
Olivier Grenie713d54a2011-01-04 04:54:31 -0300177 outreg = (1 << 10) | (1 << 6); /* 0x0440 */
178 break;
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300179 case OUTMODE_MPEG2_SERIAL:
Olivier Grenie713d54a2011-01-04 04:54:31 -0300180 outreg = (1 << 10) | (2 << 6) | (0 << 1); /* 0x0480 */
181 break;
182 case OUTMODE_DIVERSITY:
183 if (state->cfg.hostbus_diversity)
184 outreg = (1 << 10) | (4 << 6); /* 0x0500 */
185 else
186 outreg = (1 << 11);
187 break;
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300188 case OUTMODE_MPEG2_FIFO:
Olivier Grenie713d54a2011-01-04 04:54:31 -0300189 smo_mode |= (3 << 1);
190 fifo_threshold = 512;
191 outreg = (1 << 10) | (5 << 6);
192 break;
193 case OUTMODE_ANALOG_ADC:
194 outreg = (1 << 10) | (3 << 6);
195 break;
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300196 case OUTMODE_HIGH_Z:
Olivier Grenie713d54a2011-01-04 04:54:31 -0300197 outreg = 0;
198 break;
199 default:
200 dprintk("Unhandled output_mode passed to be set for demod %p", &state->demod);
201 break;
Patrick Boettchera75763f2006-10-18 08:34:16 -0300202 }
203
204 if (state->cfg.output_mpeg2_in_188_bytes)
Olivier Grenie713d54a2011-01-04 04:54:31 -0300205 smo_mode |= (1 << 5);
Patrick Boettchera75763f2006-10-18 08:34:16 -0300206
Olivier Grenie713d54a2011-01-04 04:54:31 -0300207 ret |= dib7000p_write_word(state, 235, smo_mode);
208 ret |= dib7000p_write_word(state, 236, fifo_threshold); /* synchronous fread */
209 if (state->version != SOC7090)
210 ret |= dib7000p_write_word(state, 1286, outreg); /* P_Div_active */
Patrick Boettchera75763f2006-10-18 08:34:16 -0300211
212 return ret;
213}
214
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300215static int dib7000p_set_diversity_in(struct dvb_frontend *demod, int onoff)
216{
217 struct dib7000p_state *state = demod->demodulator_priv;
218
219 if (state->div_force_off) {
Olivier Grenie713d54a2011-01-04 04:54:31 -0300220 dprintk("diversity combination deactivated - forced by COFDM parameters");
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300221 onoff = 0;
Olivier Grenieeac1fe12009-09-23 13:41:27 -0300222 dib7000p_write_word(state, 207, 0);
223 } else
224 dib7000p_write_word(state, 207, (state->div_sync_wait << 4) | (1 << 2) | (2 << 0));
225
Olivier Grenie713d54a2011-01-04 04:54:31 -0300226 state->div_state = (u8) onoff;
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300227
228 if (onoff) {
229 dib7000p_write_word(state, 204, 6);
230 dib7000p_write_word(state, 205, 16);
231 /* P_dvsy_sync_mode = 0, P_dvsy_sync_enable=1, P_dvcb_comb_mode=2 */
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300232 } else {
233 dib7000p_write_word(state, 204, 1);
234 dib7000p_write_word(state, 205, 0);
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300235 }
236
237 return 0;
238}
239
Patrick Boettchera75763f2006-10-18 08:34:16 -0300240static int dib7000p_set_power_mode(struct dib7000p_state *state, enum dib7000p_power_mode mode)
241{
242 /* by default everything is powered off */
Olivier Grenie713d54a2011-01-04 04:54:31 -0300243 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 -0300244
245 /* now, depending on the requested mode, we power on */
246 switch (mode) {
247 /* power up everything in the demod */
Olivier Grenie713d54a2011-01-04 04:54:31 -0300248 case DIB7000P_POWER_ALL:
249 reg_774 = 0x0000;
250 reg_775 = 0x0000;
251 reg_776 = 0x0;
252 reg_899 = 0x0;
253 if (state->version == SOC7090)
254 reg_1280 &= 0x001f;
255 else
256 reg_1280 &= 0x01ff;
257 break;
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300258
Olivier Grenie713d54a2011-01-04 04:54:31 -0300259 case DIB7000P_POWER_ANALOG_ADC:
260 /* dem, cfg, iqc, sad, agc */
261 reg_774 &= ~((1 << 15) | (1 << 14) | (1 << 11) | (1 << 10) | (1 << 9));
262 /* nud */
263 reg_776 &= ~((1 << 0));
264 /* Dout */
265 if (state->version != SOC7090)
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300266 reg_1280 &= ~((1 << 11));
Olivier Grenie713d54a2011-01-04 04:54:31 -0300267 reg_1280 &= ~(1 << 6);
268 /* fall through wanted to enable the interfaces */
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300269
Patrick Boettchera75763f2006-10-18 08:34:16 -0300270 /* just leave power on the control-interfaces: GPIO and (I2C or SDIO) */
Olivier Grenie713d54a2011-01-04 04:54:31 -0300271 case DIB7000P_POWER_INTERFACE_ONLY: /* TODO power up either SDIO or I2C */
272 if (state->version == SOC7090)
273 reg_1280 &= ~((1 << 7) | (1 << 5));
274 else
Patrick Boettchera75763f2006-10-18 08:34:16 -0300275 reg_1280 &= ~((1 << 14) | (1 << 13) | (1 << 12) | (1 << 10));
Olivier Grenie713d54a2011-01-04 04:54:31 -0300276 break;
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300277
Patrick Boettchera75763f2006-10-18 08:34:16 -0300278/* TODO following stuff is just converted from the dib7000-driver - check when is used what */
279 }
280
Olivier Grenie713d54a2011-01-04 04:54:31 -0300281 dib7000p_write_word(state, 774, reg_774);
282 dib7000p_write_word(state, 775, reg_775);
283 dib7000p_write_word(state, 776, reg_776);
Patrick Boettchera75763f2006-10-18 08:34:16 -0300284 dib7000p_write_word(state, 1280, reg_1280);
Olivier Grenie2e802862011-08-05 10:39:15 -0300285 if (state->version != SOC7090)
286 dib7000p_write_word(state, 899, reg_899);
Patrick Boettchera75763f2006-10-18 08:34:16 -0300287
288 return 0;
289}
290
291static void dib7000p_set_adc_state(struct dib7000p_state *state, enum dibx000_adc_states no)
292{
Olivier Grenie2e802862011-08-05 10:39:15 -0300293 u16 reg_908 = 0, reg_909 = 0;
Olivier Grenie713d54a2011-01-04 04:54:31 -0300294 u16 reg;
Patrick Boettchera75763f2006-10-18 08:34:16 -0300295
Olivier Grenie2e802862011-08-05 10:39:15 -0300296 if (state->version != SOC7090) {
297 reg_908 = dib7000p_read_word(state, 908);
298 reg_909 = dib7000p_read_word(state, 909);
299 }
300
Patrick Boettchera75763f2006-10-18 08:34:16 -0300301 switch (no) {
Olivier Grenie713d54a2011-01-04 04:54:31 -0300302 case DIBX000_SLOW_ADC_ON:
303 if (state->version == SOC7090) {
304 reg = dib7000p_read_word(state, 1925);
305
306 dib7000p_write_word(state, 1925, reg | (1 << 4) | (1 << 2)); /* en_slowAdc = 1 & reset_sladc = 1 */
307
308 reg = dib7000p_read_word(state, 1925); /* read acces to make it works... strange ... */
309 msleep(200);
310 dib7000p_write_word(state, 1925, reg & ~(1 << 4)); /* en_slowAdc = 1 & reset_sladc = 0 */
311
312 reg = dib7000p_read_word(state, 72) & ~((0x3 << 14) | (0x3 << 12));
313 dib7000p_write_word(state, 72, reg | (1 << 14) | (3 << 12) | 524); /* ref = Vin1 => Vbg ; sel = Vin0 or Vin3 ; (Vin2 = Vcm) */
314 } else {
Patrick Boettchera75763f2006-10-18 08:34:16 -0300315 reg_909 |= (1 << 1) | (1 << 0);
316 dib7000p_write_word(state, 909, reg_909);
317 reg_909 &= ~(1 << 1);
Olivier Grenie713d54a2011-01-04 04:54:31 -0300318 }
319 break;
Patrick Boettchera75763f2006-10-18 08:34:16 -0300320
Olivier Grenie713d54a2011-01-04 04:54:31 -0300321 case DIBX000_SLOW_ADC_OFF:
322 if (state->version == SOC7090) {
323 reg = dib7000p_read_word(state, 1925);
324 dib7000p_write_word(state, 1925, (reg & ~(1 << 2)) | (1 << 4)); /* reset_sladc = 1 en_slowAdc = 0 */
325 } else
326 reg_909 |= (1 << 1) | (1 << 0);
327 break;
Patrick Boettchera75763f2006-10-18 08:34:16 -0300328
Olivier Grenie713d54a2011-01-04 04:54:31 -0300329 case DIBX000_ADC_ON:
330 reg_908 &= 0x0fff;
331 reg_909 &= 0x0003;
332 break;
Patrick Boettchera75763f2006-10-18 08:34:16 -0300333
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300334 case DIBX000_ADC_OFF:
Olivier Grenie713d54a2011-01-04 04:54:31 -0300335 reg_908 |= (1 << 14) | (1 << 13) | (1 << 12);
336 reg_909 |= (1 << 5) | (1 << 4) | (1 << 3) | (1 << 2);
337 break;
Patrick Boettchera75763f2006-10-18 08:34:16 -0300338
Olivier Grenie713d54a2011-01-04 04:54:31 -0300339 case DIBX000_VBG_ENABLE:
340 reg_908 &= ~(1 << 15);
341 break;
Patrick Boettchera75763f2006-10-18 08:34:16 -0300342
Olivier Grenie713d54a2011-01-04 04:54:31 -0300343 case DIBX000_VBG_DISABLE:
344 reg_908 |= (1 << 15);
345 break;
Patrick Boettchera75763f2006-10-18 08:34:16 -0300346
Olivier Grenie713d54a2011-01-04 04:54:31 -0300347 default:
348 break;
Patrick Boettchera75763f2006-10-18 08:34:16 -0300349 }
350
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300351// dprintk( "908: %x, 909: %x\n", reg_908, reg_909);
Patrick Boettchera75763f2006-10-18 08:34:16 -0300352
Olivier Grenie970d14c2010-09-07 12:50:46 -0300353 reg_909 |= (state->cfg.disable_sample_and_hold & 1) << 4;
Olivier Grenie90e12ce2010-09-07 12:50:45 -0300354 reg_908 |= (state->cfg.enable_current_mirror & 1) << 7;
355
Olivier Grenie2e802862011-08-05 10:39:15 -0300356 if (state->version != SOC7090) {
357 dib7000p_write_word(state, 908, reg_908);
358 dib7000p_write_word(state, 909, reg_909);
359 }
Patrick Boettchera75763f2006-10-18 08:34:16 -0300360}
361
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300362static int dib7000p_set_bandwidth(struct dib7000p_state *state, u32 bw)
Patrick Boettchera75763f2006-10-18 08:34:16 -0300363{
Patrick Boettchera75763f2006-10-18 08:34:16 -0300364 u32 timf;
365
366 // store the current bandwidth for later use
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300367 state->current_bandwidth = bw;
Patrick Boettchera75763f2006-10-18 08:34:16 -0300368
369 if (state->timf == 0) {
Olivier Grenie713d54a2011-01-04 04:54:31 -0300370 dprintk("using default timf");
Patrick Boettchera75763f2006-10-18 08:34:16 -0300371 timf = state->cfg.bw->timf;
372 } else {
Olivier Grenie713d54a2011-01-04 04:54:31 -0300373 dprintk("using updated timf");
Patrick Boettchera75763f2006-10-18 08:34:16 -0300374 timf = state->timf;
375 }
376
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300377 timf = timf * (bw / 50) / 160;
Patrick Boettchera75763f2006-10-18 08:34:16 -0300378
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300379 dib7000p_write_word(state, 23, (u16) ((timf >> 16) & 0xffff));
Olivier Grenie713d54a2011-01-04 04:54:31 -0300380 dib7000p_write_word(state, 24, (u16) ((timf) & 0xffff));
Patrick Boettchera75763f2006-10-18 08:34:16 -0300381
382 return 0;
383}
384
385static int dib7000p_sad_calib(struct dib7000p_state *state)
386{
387/* internal */
Patrick Boettchera75763f2006-10-18 08:34:16 -0300388 dib7000p_write_word(state, 73, (0 << 1) | (0 << 0));
Olivier Grenie713d54a2011-01-04 04:54:31 -0300389
390 if (state->version == SOC7090)
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300391 dib7000p_write_word(state, 74, 2048);
Olivier Grenie713d54a2011-01-04 04:54:31 -0300392 else
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300393 dib7000p_write_word(state, 74, 776);
Patrick Boettchera75763f2006-10-18 08:34:16 -0300394
395 /* do the calibration */
396 dib7000p_write_word(state, 73, (1 << 0));
397 dib7000p_write_word(state, 73, (0 << 0));
398
399 msleep(1);
400
401 return 0;
402}
403
Patrick Boettcher01373a52007-07-30 12:49:04 -0300404int dib7000p_set_wbd_ref(struct dvb_frontend *demod, u16 value)
405{
406 struct dib7000p_state *state = demod->demodulator_priv;
407 if (value > 4095)
408 value = 4095;
409 state->wbd_ref = value;
410 return dib7000p_write_word(state, 105, (dib7000p_read_word(state, 105) & 0xf000) | value);
411}
Patrick Boettcher01373a52007-07-30 12:49:04 -0300412EXPORT_SYMBOL(dib7000p_set_wbd_ref);
Olivier Grenie713d54a2011-01-04 04:54:31 -0300413
Olivier Grenie6724a2f2011-08-05 13:49:33 -0300414int dib7000p_get_agc_values(struct dvb_frontend *fe,
415 u16 *agc_global, u16 *agc1, u16 *agc2, u16 *wbd)
416{
417 struct dib7000p_state *state = fe->demodulator_priv;
418
419 if (agc_global != NULL)
420 *agc_global = dib7000p_read_word(state, 394);
421 if (agc1 != NULL)
422 *agc1 = dib7000p_read_word(state, 392);
423 if (agc2 != NULL)
424 *agc2 = dib7000p_read_word(state, 393);
425 if (wbd != NULL)
426 *wbd = dib7000p_read_word(state, 397);
427
428 return 0;
429}
430EXPORT_SYMBOL(dib7000p_get_agc_values);
431
Patrick Boettchera75763f2006-10-18 08:34:16 -0300432static void dib7000p_reset_pll(struct dib7000p_state *state)
433{
434 struct dibx000_bandwidth_config *bw = &state->cfg.bw[0];
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300435 u16 clk_cfg0;
Patrick Boettchera75763f2006-10-18 08:34:16 -0300436
Olivier Grenie713d54a2011-01-04 04:54:31 -0300437 if (state->version == SOC7090) {
438 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 -0300439
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300440 while (((dib7000p_read_word(state, 1856) >> 15) & 0x1) != 1)
441 ;
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300442
Olivier Grenie713d54a2011-01-04 04:54:31 -0300443 dib7000p_write_word(state, 1857, dib7000p_read_word(state, 1857) | (!bw->pll_bypass << 15));
444 } else {
445 /* force PLL bypass */
446 clk_cfg0 = (1 << 15) | ((bw->pll_ratio & 0x3f) << 9) |
447 (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 -0300448
Olivier Grenie713d54a2011-01-04 04:54:31 -0300449 dib7000p_write_word(state, 900, clk_cfg0);
450
451 /* P_pll_cfg */
452 dib7000p_write_word(state, 903, (bw->pll_prediv << 5) | (((bw->pll_ratio >> 6) & 0x3) << 3) | (bw->pll_range << 1) | bw->pll_reset);
453 clk_cfg0 = (bw->pll_bypass << 15) | (clk_cfg0 & 0x7fff);
454 dib7000p_write_word(state, 900, clk_cfg0);
455 }
456
457 dib7000p_write_word(state, 18, (u16) (((bw->internal * 1000) >> 16) & 0xffff));
458 dib7000p_write_word(state, 19, (u16) ((bw->internal * 1000) & 0xffff));
459 dib7000p_write_word(state, 21, (u16) ((bw->ifreq >> 16) & 0xffff));
460 dib7000p_write_word(state, 22, (u16) ((bw->ifreq) & 0xffff));
Patrick Boettchera75763f2006-10-18 08:34:16 -0300461
462 dib7000p_write_word(state, 72, bw->sad_cfg);
463}
464
Olivier Grenie713d54a2011-01-04 04:54:31 -0300465static u32 dib7000p_get_internal_freq(struct dib7000p_state *state)
466{
467 u32 internal = (u32) dib7000p_read_word(state, 18) << 16;
468 internal |= (u32) dib7000p_read_word(state, 19);
469 internal /= 1000;
470
471 return internal;
472}
473
474int dib7000p_update_pll(struct dvb_frontend *fe, struct dibx000_bandwidth_config *bw)
475{
476 struct dib7000p_state *state = fe->demodulator_priv;
477 u16 reg_1857, reg_1856 = dib7000p_read_word(state, 1856);
478 u8 loopdiv, prediv;
479 u32 internal, xtal;
480
481 /* get back old values */
482 prediv = reg_1856 & 0x3f;
483 loopdiv = (reg_1856 >> 6) & 0x3f;
484
485 if ((bw != NULL) && (bw->pll_prediv != prediv || bw->pll_ratio != loopdiv)) {
486 dprintk("Updating pll (prediv: old = %d new = %d ; loopdiv : old = %d new = %d)", prediv, bw->pll_prediv, loopdiv, bw->pll_ratio);
487 reg_1856 &= 0xf000;
488 reg_1857 = dib7000p_read_word(state, 1857);
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300489 dib7000p_write_word(state, 1857, reg_1857 & ~(1 << 15));
Olivier Grenie713d54a2011-01-04 04:54:31 -0300490
491 dib7000p_write_word(state, 1856, reg_1856 | ((bw->pll_ratio & 0x3f) << 6) | (bw->pll_prediv & 0x3f));
492
493 /* write new system clk into P_sec_len */
494 internal = dib7000p_get_internal_freq(state);
495 xtal = (internal / loopdiv) * prediv;
496 internal = 1000 * (xtal / bw->pll_prediv) * bw->pll_ratio; /* new internal */
497 dib7000p_write_word(state, 18, (u16) ((internal >> 16) & 0xffff));
498 dib7000p_write_word(state, 19, (u16) (internal & 0xffff));
499
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300500 dib7000p_write_word(state, 1857, reg_1857 | (1 << 15));
Olivier Grenie713d54a2011-01-04 04:54:31 -0300501
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300502 while (((dib7000p_read_word(state, 1856) >> 15) & 0x1) != 1)
Olivier Grenie713d54a2011-01-04 04:54:31 -0300503 dprintk("Waiting for PLL to lock");
Olivier Grenie713d54a2011-01-04 04:54:31 -0300504
505 return 0;
506 }
507 return -EIO;
508}
509EXPORT_SYMBOL(dib7000p_update_pll);
510
Patrick Boettchera75763f2006-10-18 08:34:16 -0300511static int dib7000p_reset_gpio(struct dib7000p_state *st)
512{
513 /* reset the GPIOs */
Olivier Grenie713d54a2011-01-04 04:54:31 -0300514 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 -0300515
516 dib7000p_write_word(st, 1029, st->gpio_dir);
517 dib7000p_write_word(st, 1030, st->gpio_val);
518
519 /* TODO 1031 is P_gpio_od */
520
521 dib7000p_write_word(st, 1032, st->cfg.gpio_pwm_pos);
522
523 dib7000p_write_word(st, 1037, st->cfg.pwm_freq_div);
524 return 0;
525}
526
Patrick Boettcher01373a52007-07-30 12:49:04 -0300527static int dib7000p_cfg_gpio(struct dib7000p_state *st, u8 num, u8 dir, u8 val)
528{
529 st->gpio_dir = dib7000p_read_word(st, 1029);
Olivier Grenie713d54a2011-01-04 04:54:31 -0300530 st->gpio_dir &= ~(1 << num); /* reset the direction bit */
531 st->gpio_dir |= (dir & 0x1) << num; /* set the new direction */
Patrick Boettcher01373a52007-07-30 12:49:04 -0300532 dib7000p_write_word(st, 1029, st->gpio_dir);
533
534 st->gpio_val = dib7000p_read_word(st, 1030);
Olivier Grenie713d54a2011-01-04 04:54:31 -0300535 st->gpio_val &= ~(1 << num); /* reset the direction bit */
536 st->gpio_val |= (val & 0x01) << num; /* set the new value */
Patrick Boettcher01373a52007-07-30 12:49:04 -0300537 dib7000p_write_word(st, 1030, st->gpio_val);
538
539 return 0;
540}
541
542int dib7000p_set_gpio(struct dvb_frontend *demod, u8 num, u8 dir, u8 val)
543{
544 struct dib7000p_state *state = demod->demodulator_priv;
545 return dib7000p_cfg_gpio(state, num, dir, val);
546}
Patrick Boettcher01373a52007-07-30 12:49:04 -0300547EXPORT_SYMBOL(dib7000p_set_gpio);
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300548
Olivier Grenie713d54a2011-01-04 04:54:31 -0300549static u16 dib7000p_defaults[] = {
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300550 // auto search configuration
551 3, 2,
Olivier Grenie713d54a2011-01-04 04:54:31 -0300552 0x0004,
Olivier Grenie2e802862011-08-05 10:39:15 -0300553 (1<<3)|(1<<11)|(1<<12)|(1<<13),
Olivier Grenie713d54a2011-01-04 04:54:31 -0300554 0x0814, /* Equal Lock */
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300555
556 12, 6,
Olivier Grenie713d54a2011-01-04 04:54:31 -0300557 0x001b,
558 0x7740,
559 0x005b,
560 0x8d80,
561 0x01c9,
562 0xc380,
563 0x0000,
564 0x0080,
565 0x0000,
566 0x0090,
567 0x0001,
568 0xd4c0,
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300569
570 1, 26,
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300571 0x6680,
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300572
573 /* set ADC level to -16 */
574 11, 79,
Olivier Grenie713d54a2011-01-04 04:54:31 -0300575 (1 << 13) - 825 - 117,
576 (1 << 13) - 837 - 117,
577 (1 << 13) - 811 - 117,
578 (1 << 13) - 766 - 117,
579 (1 << 13) - 737 - 117,
580 (1 << 13) - 693 - 117,
581 (1 << 13) - 648 - 117,
582 (1 << 13) - 619 - 117,
583 (1 << 13) - 575 - 117,
584 (1 << 13) - 531 - 117,
585 (1 << 13) - 501 - 117,
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300586
587 1, 142,
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300588 0x0410,
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300589
590 /* disable power smoothing */
591 8, 145,
Olivier Grenie713d54a2011-01-04 04:54:31 -0300592 0,
593 0,
594 0,
595 0,
596 0,
597 0,
598 0,
599 0,
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300600
601 1, 154,
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300602 1 << 13,
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300603
604 1, 168,
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300605 0x0ccd,
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300606
607 1, 183,
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300608 0x200f,
Olivier Grenie713d54a2011-01-04 04:54:31 -0300609
610 1, 212,
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300611 0x169,
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300612
613 5, 187,
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300614 0x023d,
615 0x00a4,
616 0x00a4,
617 0x7ff0,
618 0x3ccc,
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300619
620 1, 198,
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300621 0x800,
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300622
623 1, 222,
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300624 0x0010,
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300625
626 1, 235,
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300627 0x0062,
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300628
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300629 0,
630};
631
Patrick Boettchera75763f2006-10-18 08:34:16 -0300632static int dib7000p_demod_reset(struct dib7000p_state *state)
633{
634 dib7000p_set_power_mode(state, DIB7000P_POWER_ALL);
635
Olivier Grenie713d54a2011-01-04 04:54:31 -0300636 if (state->version == SOC7090)
637 dibx000_reset_i2c_master(&state->i2c_master);
638
Patrick Boettchera75763f2006-10-18 08:34:16 -0300639 dib7000p_set_adc_state(state, DIBX000_VBG_ENABLE);
640
641 /* restart all parts */
Olivier Grenie713d54a2011-01-04 04:54:31 -0300642 dib7000p_write_word(state, 770, 0xffff);
643 dib7000p_write_word(state, 771, 0xffff);
644 dib7000p_write_word(state, 772, 0x001f);
Olivier Grenie713d54a2011-01-04 04:54:31 -0300645 dib7000p_write_word(state, 1280, 0x001f - ((1 << 4) | (1 << 3)));
Patrick Boettchera75763f2006-10-18 08:34:16 -0300646
Olivier Grenie713d54a2011-01-04 04:54:31 -0300647 dib7000p_write_word(state, 770, 0);
648 dib7000p_write_word(state, 771, 0);
649 dib7000p_write_word(state, 772, 0);
Patrick Boettchera75763f2006-10-18 08:34:16 -0300650 dib7000p_write_word(state, 1280, 0);
651
Olivier Grenie2e802862011-08-05 10:39:15 -0300652 if (state->version != SOC7090) {
653 dib7000p_write_word(state, 898, 0x0003);
654 dib7000p_write_word(state, 898, 0);
655 }
656
Patrick Boettchera75763f2006-10-18 08:34:16 -0300657 /* default */
658 dib7000p_reset_pll(state);
659
660 if (dib7000p_reset_gpio(state) != 0)
Olivier Grenie713d54a2011-01-04 04:54:31 -0300661 dprintk("GPIO reset was not successful.");
Patrick Boettchera75763f2006-10-18 08:34:16 -0300662
Olivier Grenie713d54a2011-01-04 04:54:31 -0300663 if (state->version == SOC7090) {
664 dib7000p_write_word(state, 899, 0);
665
666 /* impulse noise */
667 dib7000p_write_word(state, 42, (1<<5) | 3); /* P_iqc_thsat_ipc = 1 ; P_iqc_win2 = 3 */
668 dib7000p_write_word(state, 43, 0x2d4); /*-300 fag P_iqc_dect_min = -280 */
669 dib7000p_write_word(state, 44, 300); /* 300 fag P_iqc_dect_min = +280 */
Olivier Grenie2e802862011-08-05 10:39:15 -0300670 dib7000p_write_word(state, 273, (0<<6) | 30);
Olivier Grenie713d54a2011-01-04 04:54:31 -0300671 }
Patrick Boettchera75763f2006-10-18 08:34:16 -0300672 if (dib7000p_set_output_mode(state, OUTMODE_HIGH_Z) != 0)
Olivier Grenie713d54a2011-01-04 04:54:31 -0300673 dprintk("OUTPUT_MODE could not be reset.");
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300674
675 dib7000p_set_adc_state(state, DIBX000_SLOW_ADC_ON);
676 dib7000p_sad_calib(state);
677 dib7000p_set_adc_state(state, DIBX000_SLOW_ADC_OFF);
678
Olivier Grenie713d54a2011-01-04 04:54:31 -0300679 /* unforce divstr regardless whether i2c enumeration was done or not */
680 dib7000p_write_word(state, 1285, dib7000p_read_word(state, 1285) & ~(1 << 1));
681
682 dib7000p_set_bandwidth(state, 8000);
683
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300684 if (state->version == SOC7090) {
Olivier Grenie2e802862011-08-05 10:39:15 -0300685 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 -0300686 } else {
Olivier Grenie713d54a2011-01-04 04:54:31 -0300687 if (state->cfg.tuner_is_baseband)
688 dib7000p_write_word(state, 36, 0x0755);
689 else
690 dib7000p_write_word(state, 36, 0x1f55);
691 }
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300692
693 dib7000p_write_tab(state, dib7000p_defaults);
Olivier Grenie2e802862011-08-05 10:39:15 -0300694 if (state->version != SOC7090) {
695 dib7000p_write_word(state, 901, 0x0006);
696 dib7000p_write_word(state, 902, (3 << 10) | (1 << 6));
697 dib7000p_write_word(state, 905, 0x2c8e);
698 }
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300699
Patrick Boettchera75763f2006-10-18 08:34:16 -0300700 dib7000p_set_power_mode(state, DIB7000P_POWER_INTERFACE_ONLY);
701
702 return 0;
703}
704
Patrick Boettchera75763f2006-10-18 08:34:16 -0300705static void dib7000p_pll_clk_cfg(struct dib7000p_state *state)
706{
707 u16 tmp = 0;
708 tmp = dib7000p_read_word(state, 903);
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300709 dib7000p_write_word(state, 903, (tmp | 0x1));
Patrick Boettchera75763f2006-10-18 08:34:16 -0300710 tmp = dib7000p_read_word(state, 900);
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300711 dib7000p_write_word(state, 900, (tmp & 0x7fff) | (1 << 6));
Patrick Boettchera75763f2006-10-18 08:34:16 -0300712}
713
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300714static void dib7000p_restart_agc(struct dib7000p_state *state)
Patrick Boettchera75763f2006-10-18 08:34:16 -0300715{
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300716 // P_restart_iqc & P_restart_agc
717 dib7000p_write_word(state, 770, (1 << 11) | (1 << 9));
718 dib7000p_write_word(state, 770, 0x0000);
Patrick Boettchera75763f2006-10-18 08:34:16 -0300719}
720
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300721static int dib7000p_update_lna(struct dib7000p_state *state)
Patrick Boettchera75763f2006-10-18 08:34:16 -0300722{
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300723 u16 dyn_gain;
724
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300725 if (state->cfg.update_lna) {
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300726 dyn_gain = dib7000p_read_word(state, 394);
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300727 if (state->cfg.update_lna(&state->demod, dyn_gain)) {
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300728 dib7000p_restart_agc(state);
729 return 1;
730 }
731 }
732
733 return 0;
734}
735
736static int dib7000p_set_agc_config(struct dib7000p_state *state, u8 band)
737{
738 struct dibx000_agc_config *agc = NULL;
739 int i;
740 if (state->current_band == band && state->current_agc != NULL)
741 return 0;
742 state->current_band = band;
743
744 for (i = 0; i < state->cfg.agc_config_count; i++)
745 if (state->cfg.agc[i].band_caps & band) {
746 agc = &state->cfg.agc[i];
747 break;
748 }
749
750 if (agc == NULL) {
Olivier Grenie713d54a2011-01-04 04:54:31 -0300751 dprintk("no valid AGC configuration found for band 0x%02x", band);
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300752 return -EINVAL;
753 }
754
755 state->current_agc = agc;
756
757 /* AGC */
Olivier Grenie713d54a2011-01-04 04:54:31 -0300758 dib7000p_write_word(state, 75, agc->setup);
759 dib7000p_write_word(state, 76, agc->inv_gain);
760 dib7000p_write_word(state, 77, agc->time_stabiliz);
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300761 dib7000p_write_word(state, 100, (agc->alpha_level << 12) | agc->thlock);
762
763 // Demod AGC loop configuration
764 dib7000p_write_word(state, 101, (agc->alpha_mant << 5) | agc->alpha_exp);
Olivier Grenie713d54a2011-01-04 04:54:31 -0300765 dib7000p_write_word(state, 102, (agc->beta_mant << 6) | agc->beta_exp);
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300766
767 /* AGC continued */
Olivier Grenie713d54a2011-01-04 04:54:31 -0300768 dprintk("WBD: ref: %d, sel: %d, active: %d, alpha: %d",
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300769 state->wbd_ref != 0 ? state->wbd_ref : agc->wbd_ref, agc->wbd_sel, !agc->perform_agc_softsplit, agc->wbd_sel);
770
771 if (state->wbd_ref != 0)
772 dib7000p_write_word(state, 105, (agc->wbd_inv << 12) | state->wbd_ref);
773 else
774 dib7000p_write_word(state, 105, (agc->wbd_inv << 12) | agc->wbd_ref);
775
776 dib7000p_write_word(state, 106, (agc->wbd_sel << 13) | (agc->wbd_alpha << 9) | (agc->perform_agc_softsplit << 8));
777
Olivier Grenie713d54a2011-01-04 04:54:31 -0300778 dib7000p_write_word(state, 107, agc->agc1_max);
779 dib7000p_write_word(state, 108, agc->agc1_min);
780 dib7000p_write_word(state, 109, agc->agc2_max);
781 dib7000p_write_word(state, 110, agc->agc2_min);
782 dib7000p_write_word(state, 111, (agc->agc1_pt1 << 8) | agc->agc1_pt2);
783 dib7000p_write_word(state, 112, agc->agc1_pt3);
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300784 dib7000p_write_word(state, 113, (agc->agc1_slope1 << 8) | agc->agc1_slope2);
Olivier Grenie713d54a2011-01-04 04:54:31 -0300785 dib7000p_write_word(state, 114, (agc->agc2_pt1 << 8) | agc->agc2_pt2);
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300786 dib7000p_write_word(state, 115, (agc->agc2_slope1 << 8) | agc->agc2_slope2);
787 return 0;
788}
789
Olivier Grenie713d54a2011-01-04 04:54:31 -0300790static void dib7000p_set_dds(struct dib7000p_state *state, s32 offset_khz)
791{
792 u32 internal = dib7000p_get_internal_freq(state);
793 s32 unit_khz_dds_val = 67108864 / (internal); /* 2**26 / Fsampling is the unit 1KHz offset */
794 u32 abs_offset_khz = ABS(offset_khz);
795 u32 dds = state->cfg.bw->ifreq & 0x1ffffff;
796 u8 invert = !!(state->cfg.bw->ifreq & (1 << 25));
797
798 dprintk("setting a frequency offset of %dkHz internal freq = %d invert = %d", offset_khz, internal, invert);
799
800 if (offset_khz < 0)
801 unit_khz_dds_val *= -1;
802
803 /* IF tuner */
804 if (invert)
805 dds -= (abs_offset_khz * unit_khz_dds_val); /* /100 because of /100 on the unit_khz_dds_val line calc for better accuracy */
806 else
807 dds += (abs_offset_khz * unit_khz_dds_val);
808
809 if (abs_offset_khz <= (internal / 2)) { /* Max dds offset is the half of the demod freq */
810 dib7000p_write_word(state, 21, (u16) (((dds >> 16) & 0x1ff) | (0 << 10) | (invert << 9)));
811 dib7000p_write_word(state, 22, (u16) (dds & 0xffff));
812 }
813}
814
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300815static int dib7000p_agc_startup(struct dvb_frontend *demod, struct dvb_frontend_parameters *ch)
816{
817 struct dib7000p_state *state = demod->demodulator_priv;
818 int ret = -1;
819 u8 *agc_state = &state->agc_state;
820 u8 agc_split;
Olivier Grenie713d54a2011-01-04 04:54:31 -0300821 u16 reg;
822 u32 upd_demod_gain_period = 0x1000;
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300823
824 switch (state->agc_state) {
Olivier Grenie713d54a2011-01-04 04:54:31 -0300825 case 0:
Olivier Grenie713d54a2011-01-04 04:54:31 -0300826 dib7000p_set_power_mode(state, DIB7000P_POWER_ALL);
827 if (state->version == SOC7090) {
828 reg = dib7000p_read_word(state, 0x79b) & 0xff00;
829 dib7000p_write_word(state, 0x79a, upd_demod_gain_period & 0xFFFF); /* lsb */
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300830 dib7000p_write_word(state, 0x79b, reg | (1 << 14) | ((upd_demod_gain_period >> 16) & 0xFF));
Olivier Grenie713d54a2011-01-04 04:54:31 -0300831
832 /* enable adc i & q */
833 reg = dib7000p_read_word(state, 0x780);
834 dib7000p_write_word(state, 0x780, (reg | (0x3)) & (~(1 << 7)));
835 } else {
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300836 dib7000p_set_adc_state(state, DIBX000_ADC_ON);
837 dib7000p_pll_clk_cfg(state);
Olivier Grenie713d54a2011-01-04 04:54:31 -0300838 }
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300839
Olivier Grenie713d54a2011-01-04 04:54:31 -0300840 if (dib7000p_set_agc_config(state, BAND_OF_FREQUENCY(ch->frequency / 1000)) != 0)
841 return -1;
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300842
Olivier Grenie713d54a2011-01-04 04:54:31 -0300843 dib7000p_set_dds(state, 0);
844 ret = 7;
845 (*agc_state)++;
846 break;
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300847
Olivier Grenie713d54a2011-01-04 04:54:31 -0300848 case 1:
Olivier Grenie713d54a2011-01-04 04:54:31 -0300849 if (state->cfg.agc_control)
850 state->cfg.agc_control(&state->demod, 1);
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300851
Olivier Grenie713d54a2011-01-04 04:54:31 -0300852 dib7000p_write_word(state, 78, 32768);
853 if (!state->current_agc->perform_agc_softsplit) {
854 /* we are using the wbd - so slow AGC startup */
855 /* force 0 split on WBD and restart AGC */
856 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 -0300857 (*agc_state)++;
858 ret = 5;
Olivier Grenie713d54a2011-01-04 04:54:31 -0300859 } else {
860 /* default AGC startup */
861 (*agc_state) = 4;
862 /* wait AGC rough lock time */
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300863 ret = 7;
Olivier Grenie713d54a2011-01-04 04:54:31 -0300864 }
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300865
Olivier Grenie713d54a2011-01-04 04:54:31 -0300866 dib7000p_restart_agc(state);
867 break;
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300868
Olivier Grenie713d54a2011-01-04 04:54:31 -0300869 case 2: /* fast split search path after 5sec */
870 dib7000p_write_word(state, 75, state->current_agc->setup | (1 << 4)); /* freeze AGC loop */
871 dib7000p_write_word(state, 106, (state->current_agc->wbd_sel << 13) | (2 << 9) | (0 << 8)); /* fast split search 0.25kHz */
872 (*agc_state)++;
873 ret = 14;
874 break;
875
876 case 3: /* split search ended */
877 agc_split = (u8) dib7000p_read_word(state, 396); /* store the split value for the next time */
878 dib7000p_write_word(state, 78, dib7000p_read_word(state, 394)); /* set AGC gain start value */
879
880 dib7000p_write_word(state, 75, state->current_agc->setup); /* std AGC loop */
881 dib7000p_write_word(state, 106, (state->current_agc->wbd_sel << 13) | (state->current_agc->wbd_alpha << 9) | agc_split); /* standard split search */
882
883 dib7000p_restart_agc(state);
884
885 dprintk("SPLIT %p: %hd", demod, agc_split);
886
887 (*agc_state)++;
888 ret = 5;
889 break;
890
891 case 4: /* LNA startup */
Olivier Grenie713d54a2011-01-04 04:54:31 -0300892 ret = 7;
893
894 if (dib7000p_update_lna(state))
Olivier Grenie713d54a2011-01-04 04:54:31 -0300895 ret = 5;
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300896 else
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300897 (*agc_state)++;
Olivier Grenie713d54a2011-01-04 04:54:31 -0300898 break;
899
900 case 5:
901 if (state->cfg.agc_control)
902 state->cfg.agc_control(&state->demod, 0);
903 (*agc_state)++;
904 break;
905 default:
906 break;
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300907 }
908 return ret;
909}
910
911static void dib7000p_update_timf(struct dib7000p_state *state)
912{
913 u32 timf = (dib7000p_read_word(state, 427) << 16) | dib7000p_read_word(state, 428);
914 state->timf = timf * 160 / (state->current_bandwidth / 50);
915 dib7000p_write_word(state, 23, (u16) (timf >> 16));
916 dib7000p_write_word(state, 24, (u16) (timf & 0xffff));
Olivier Grenie713d54a2011-01-04 04:54:31 -0300917 dprintk("updated timf_frequency: %d (default: %d)", state->timf, state->cfg.bw->timf);
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300918
919}
920
Olivier Grenie713d54a2011-01-04 04:54:31 -0300921u32 dib7000p_ctrl_timf(struct dvb_frontend *fe, u8 op, u32 timf)
922{
923 struct dib7000p_state *state = fe->demodulator_priv;
924 switch (op) {
925 case DEMOD_TIMF_SET:
926 state->timf = timf;
927 break;
928 case DEMOD_TIMF_UPDATE:
929 dib7000p_update_timf(state);
930 break;
931 case DEMOD_TIMF_GET:
932 break;
933 }
934 dib7000p_set_bandwidth(state, state->current_bandwidth);
935 return state->timf;
936}
937EXPORT_SYMBOL(dib7000p_ctrl_timf);
938
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300939static void dib7000p_set_channel(struct dib7000p_state *state, struct dvb_frontend_parameters *ch, u8 seq)
940{
941 u16 value, est[4];
942
Olivier Grenie713d54a2011-01-04 04:54:31 -0300943 dib7000p_set_bandwidth(state, BANDWIDTH_TO_KHZ(ch->u.ofdm.bandwidth));
Patrick Boettchera75763f2006-10-18 08:34:16 -0300944
945 /* nfft, guard, qam, alpha */
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300946 value = 0;
947 switch (ch->u.ofdm.transmission_mode) {
Olivier Grenie713d54a2011-01-04 04:54:31 -0300948 case TRANSMISSION_MODE_2K:
949 value |= (0 << 7);
950 break;
Mauro Carvalho Chehab46f72962011-01-16 13:01:20 -0200951 case TRANSMISSION_MODE_4K:
Olivier Grenie713d54a2011-01-04 04:54:31 -0300952 value |= (2 << 7);
953 break;
954 default:
955 case TRANSMISSION_MODE_8K:
956 value |= (1 << 7);
957 break;
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300958 }
959 switch (ch->u.ofdm.guard_interval) {
Olivier Grenie713d54a2011-01-04 04:54:31 -0300960 case GUARD_INTERVAL_1_32:
961 value |= (0 << 5);
962 break;
963 case GUARD_INTERVAL_1_16:
964 value |= (1 << 5);
965 break;
966 case GUARD_INTERVAL_1_4:
967 value |= (3 << 5);
968 break;
969 default:
970 case GUARD_INTERVAL_1_8:
971 value |= (2 << 5);
972 break;
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300973 }
974 switch (ch->u.ofdm.constellation) {
Olivier Grenie713d54a2011-01-04 04:54:31 -0300975 case QPSK:
976 value |= (0 << 3);
977 break;
978 case QAM_16:
979 value |= (1 << 3);
980 break;
981 default:
982 case QAM_64:
983 value |= (2 << 3);
984 break;
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300985 }
986 switch (HIERARCHY_1) {
Olivier Grenie713d54a2011-01-04 04:54:31 -0300987 case HIERARCHY_2:
988 value |= 2;
989 break;
990 case HIERARCHY_4:
991 value |= 4;
992 break;
993 default:
994 case HIERARCHY_1:
995 value |= 1;
996 break;
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300997 }
998 dib7000p_write_word(state, 0, value);
Olivier Grenie713d54a2011-01-04 04:54:31 -0300999 dib7000p_write_word(state, 5, (seq << 4) | 1); /* do not force tps, search list 0 */
Patrick Boettchera75763f2006-10-18 08:34:16 -03001000
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001001 /* P_dintl_native, P_dintlv_inv, P_hrch, P_code_rate, P_select_hp */
1002 value = 0;
1003 if (1 != 0)
1004 value |= (1 << 6);
1005 if (ch->u.ofdm.hierarchy_information == 1)
1006 value |= (1 << 4);
1007 if (1 == 1)
1008 value |= 1;
1009 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 -03001010 case FEC_2_3:
1011 value |= (2 << 1);
1012 break;
1013 case FEC_3_4:
1014 value |= (3 << 1);
1015 break;
1016 case FEC_5_6:
1017 value |= (5 << 1);
1018 break;
1019 case FEC_7_8:
1020 value |= (7 << 1);
1021 break;
1022 default:
1023 case FEC_1_2:
1024 value |= (1 << 1);
1025 break;
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001026 }
1027 dib7000p_write_word(state, 208, value);
1028
1029 /* offset loop parameters */
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001030 dib7000p_write_word(state, 26, 0x6680);
1031 dib7000p_write_word(state, 32, 0x0003);
1032 dib7000p_write_word(state, 29, 0x1273);
1033 dib7000p_write_word(state, 33, 0x0005);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001034
1035 /* P_dvsy_sync_wait */
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001036 switch (ch->u.ofdm.transmission_mode) {
Olivier Grenie713d54a2011-01-04 04:54:31 -03001037 case TRANSMISSION_MODE_8K:
1038 value = 256;
1039 break;
1040 case TRANSMISSION_MODE_4K:
1041 value = 128;
1042 break;
1043 case TRANSMISSION_MODE_2K:
1044 default:
1045 value = 64;
1046 break;
Patrick Boettchera75763f2006-10-18 08:34:16 -03001047 }
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001048 switch (ch->u.ofdm.guard_interval) {
Olivier Grenie713d54a2011-01-04 04:54:31 -03001049 case GUARD_INTERVAL_1_16:
1050 value *= 2;
1051 break;
1052 case GUARD_INTERVAL_1_8:
1053 value *= 4;
1054 break;
1055 case GUARD_INTERVAL_1_4:
1056 value *= 8;
1057 break;
1058 default:
1059 case GUARD_INTERVAL_1_32:
1060 value *= 1;
1061 break;
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001062 }
Olivier Grenie970d14c2010-09-07 12:50:46 -03001063 if (state->cfg.diversity_delay == 0)
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001064 state->div_sync_wait = (value * 3) / 2 + 48;
Olivier Grenie970d14c2010-09-07 12:50:46 -03001065 else
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001066 state->div_sync_wait = (value * 3) / 2 + state->cfg.diversity_delay;
Patrick Boettchera75763f2006-10-18 08:34:16 -03001067
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001068 /* deactive the possibility of diversity reception if extended interleaver */
1069 state->div_force_off = !1 && ch->u.ofdm.transmission_mode != TRANSMISSION_MODE_8K;
1070 dib7000p_set_diversity_in(&state->demod, state->div_state);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001071
1072 /* channel estimation fine configuration */
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001073 switch (ch->u.ofdm.constellation) {
Olivier Grenie713d54a2011-01-04 04:54:31 -03001074 case QAM_64:
1075 est[0] = 0x0148; /* P_adp_regul_cnt 0.04 */
1076 est[1] = 0xfff0; /* P_adp_noise_cnt -0.002 */
1077 est[2] = 0x00a4; /* P_adp_regul_ext 0.02 */
1078 est[3] = 0xfff8; /* P_adp_noise_ext -0.001 */
1079 break;
1080 case QAM_16:
1081 est[0] = 0x023d; /* P_adp_regul_cnt 0.07 */
1082 est[1] = 0xffdf; /* P_adp_noise_cnt -0.004 */
1083 est[2] = 0x00a4; /* P_adp_regul_ext 0.02 */
1084 est[3] = 0xfff0; /* P_adp_noise_ext -0.002 */
1085 break;
1086 default:
1087 est[0] = 0x099a; /* P_adp_regul_cnt 0.3 */
1088 est[1] = 0xffae; /* P_adp_noise_cnt -0.01 */
1089 est[2] = 0x0333; /* P_adp_regul_ext 0.1 */
1090 est[3] = 0xfff8; /* P_adp_noise_ext -0.002 */
1091 break;
Patrick Boettchera75763f2006-10-18 08:34:16 -03001092 }
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001093 for (value = 0; value < 4; value++)
1094 dib7000p_write_word(state, 187 + value, est[value]);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001095}
1096
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001097static int dib7000p_autosearch_start(struct dvb_frontend *demod, struct dvb_frontend_parameters *ch)
Patrick Boettchera75763f2006-10-18 08:34:16 -03001098{
1099 struct dib7000p_state *state = demod->demodulator_priv;
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001100 struct dvb_frontend_parameters schan;
1101 u32 value, factor;
Olivier Grenie713d54a2011-01-04 04:54:31 -03001102 u32 internal = dib7000p_get_internal_freq(state);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001103
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001104 schan = *ch;
1105 schan.u.ofdm.constellation = QAM_64;
Olivier Grenie713d54a2011-01-04 04:54:31 -03001106 schan.u.ofdm.guard_interval = GUARD_INTERVAL_1_32;
1107 schan.u.ofdm.transmission_mode = TRANSMISSION_MODE_8K;
1108 schan.u.ofdm.code_rate_HP = FEC_2_3;
1109 schan.u.ofdm.code_rate_LP = FEC_3_4;
1110 schan.u.ofdm.hierarchy_information = 0;
Patrick Boettchera75763f2006-10-18 08:34:16 -03001111
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001112 dib7000p_set_channel(state, &schan, 7);
1113
1114 factor = BANDWIDTH_TO_KHZ(ch->u.ofdm.bandwidth);
Olivier Grenie2e802862011-08-05 10:39:15 -03001115 if (factor >= 5000) {
1116 if (state->version == SOC7090)
1117 factor = 2;
1118 else
1119 factor = 1;
1120 } else
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001121 factor = 6;
Patrick Boettchera75763f2006-10-18 08:34:16 -03001122
Olivier Grenie713d54a2011-01-04 04:54:31 -03001123 value = 30 * internal * factor;
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001124 dib7000p_write_word(state, 6, (u16) ((value >> 16) & 0xffff));
1125 dib7000p_write_word(state, 7, (u16) (value & 0xffff));
Olivier Grenie713d54a2011-01-04 04:54:31 -03001126 value = 100 * internal * factor;
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001127 dib7000p_write_word(state, 8, (u16) ((value >> 16) & 0xffff));
1128 dib7000p_write_word(state, 9, (u16) (value & 0xffff));
Olivier Grenie713d54a2011-01-04 04:54:31 -03001129 value = 500 * internal * factor;
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001130 dib7000p_write_word(state, 10, (u16) ((value >> 16) & 0xffff));
1131 dib7000p_write_word(state, 11, (u16) (value & 0xffff));
Patrick Boettchera75763f2006-10-18 08:34:16 -03001132
1133 value = dib7000p_read_word(state, 0);
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001134 dib7000p_write_word(state, 0, (u16) ((1 << 9) | value));
Patrick Boettchera75763f2006-10-18 08:34:16 -03001135 dib7000p_read_word(state, 1284);
1136 dib7000p_write_word(state, 0, (u16) value);
1137
1138 return 0;
1139}
1140
1141static int dib7000p_autosearch_is_irq(struct dvb_frontend *demod)
1142{
1143 struct dib7000p_state *state = demod->demodulator_priv;
1144 u16 irq_pending = dib7000p_read_word(state, 1284);
1145
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001146 if (irq_pending & 0x1)
Patrick Boettchera75763f2006-10-18 08:34:16 -03001147 return 1;
1148
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001149 if (irq_pending & 0x2)
Patrick Boettchera75763f2006-10-18 08:34:16 -03001150 return 2;
1151
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001152 return 0;
Patrick Boettchera75763f2006-10-18 08:34:16 -03001153}
1154
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001155static void dib7000p_spur_protect(struct dib7000p_state *state, u32 rf_khz, u32 bw)
1156{
Olivier Grenie713d54a2011-01-04 04:54:31 -03001157 static s16 notch[] = { 16143, 14402, 12238, 9713, 6902, 3888, 759, -2392 };
1158 static u8 sine[] = { 0, 2, 3, 5, 6, 8, 9, 11, 13, 14, 16, 17, 19, 20, 22,
1159 24, 25, 27, 28, 30, 31, 33, 34, 36, 38, 39, 41, 42, 44, 45, 47, 48, 50, 51,
1160 53, 55, 56, 58, 59, 61, 62, 64, 65, 67, 68, 70, 71, 73, 74, 76, 77, 79, 80,
1161 82, 83, 85, 86, 88, 89, 91, 92, 94, 95, 97, 98, 99, 101, 102, 104, 105,
1162 107, 108, 109, 111, 112, 114, 115, 117, 118, 119, 121, 122, 123, 125, 126,
1163 128, 129, 130, 132, 133, 134, 136, 137, 138, 140, 141, 142, 144, 145, 146,
1164 147, 149, 150, 151, 152, 154, 155, 156, 157, 159, 160, 161, 162, 164, 165,
1165 166, 167, 168, 170, 171, 172, 173, 174, 175, 177, 178, 179, 180, 181, 182,
1166 183, 184, 185, 186, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198,
1167 199, 200, 201, 202, 203, 204, 205, 206, 207, 207, 208, 209, 210, 211, 212,
1168 213, 214, 215, 215, 216, 217, 218, 219, 220, 220, 221, 222, 223, 224, 224,
1169 225, 226, 227, 227, 228, 229, 229, 230, 231, 231, 232, 233, 233, 234, 235,
1170 235, 236, 237, 237, 238, 238, 239, 239, 240, 241, 241, 242, 242, 243, 243,
1171 244, 244, 245, 245, 245, 246, 246, 247, 247, 248, 248, 248, 249, 249, 249,
1172 250, 250, 250, 251, 251, 251, 252, 252, 252, 252, 253, 253, 253, 253, 254,
1173 254, 254, 254, 254, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
1174 255, 255, 255, 255, 255, 255
1175 };
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001176
1177 u32 xtal = state->cfg.bw->xtal_hz / 1000;
Julia Lawall75b697f2009-08-01 16:48:41 -03001178 int f_rel = DIV_ROUND_CLOSEST(rf_khz, xtal) * xtal - rf_khz;
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001179 int k;
Olivier Grenie713d54a2011-01-04 04:54:31 -03001180 int coef_re[8], coef_im[8];
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001181 int bw_khz = bw;
1182 u32 pha;
1183
Olivier Grenie713d54a2011-01-04 04:54:31 -03001184 dprintk("relative position of the Spur: %dk (RF: %dk, XTAL: %dk)", f_rel, rf_khz, xtal);
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001185
Olivier Grenie713d54a2011-01-04 04:54:31 -03001186 if (f_rel < -bw_khz / 2 || f_rel > bw_khz / 2)
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001187 return;
1188
1189 bw_khz /= 100;
1190
Olivier Grenie713d54a2011-01-04 04:54:31 -03001191 dib7000p_write_word(state, 142, 0x0610);
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001192
1193 for (k = 0; k < 8; k++) {
Olivier Grenie713d54a2011-01-04 04:54:31 -03001194 pha = ((f_rel * (k + 1) * 112 * 80 / bw_khz) / 1000) & 0x3ff;
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001195
Olivier Grenie713d54a2011-01-04 04:54:31 -03001196 if (pha == 0) {
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001197 coef_re[k] = 256;
1198 coef_im[k] = 0;
Olivier Grenie713d54a2011-01-04 04:54:31 -03001199 } else if (pha < 256) {
1200 coef_re[k] = sine[256 - (pha & 0xff)];
1201 coef_im[k] = sine[pha & 0xff];
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001202 } else if (pha == 256) {
1203 coef_re[k] = 0;
1204 coef_im[k] = 256;
1205 } else if (pha < 512) {
Olivier Grenie713d54a2011-01-04 04:54:31 -03001206 coef_re[k] = -sine[pha & 0xff];
1207 coef_im[k] = sine[256 - (pha & 0xff)];
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001208 } else if (pha == 512) {
1209 coef_re[k] = -256;
1210 coef_im[k] = 0;
1211 } else if (pha < 768) {
Olivier Grenie713d54a2011-01-04 04:54:31 -03001212 coef_re[k] = -sine[256 - (pha & 0xff)];
1213 coef_im[k] = -sine[pha & 0xff];
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001214 } else if (pha == 768) {
1215 coef_re[k] = 0;
1216 coef_im[k] = -256;
1217 } else {
Olivier Grenie713d54a2011-01-04 04:54:31 -03001218 coef_re[k] = sine[pha & 0xff];
1219 coef_im[k] = -sine[256 - (pha & 0xff)];
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001220 }
1221
1222 coef_re[k] *= notch[k];
Olivier Grenie713d54a2011-01-04 04:54:31 -03001223 coef_re[k] += (1 << 14);
1224 if (coef_re[k] >= (1 << 24))
1225 coef_re[k] = (1 << 24) - 1;
1226 coef_re[k] /= (1 << 15);
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001227
1228 coef_im[k] *= notch[k];
Olivier Grenie713d54a2011-01-04 04:54:31 -03001229 coef_im[k] += (1 << 14);
1230 if (coef_im[k] >= (1 << 24))
1231 coef_im[k] = (1 << 24) - 1;
1232 coef_im[k] /= (1 << 15);
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001233
Olivier Grenie713d54a2011-01-04 04:54:31 -03001234 dprintk("PALF COEF: %d re: %d im: %d", k, coef_re[k], coef_im[k]);
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001235
1236 dib7000p_write_word(state, 143, (0 << 14) | (k << 10) | (coef_re[k] & 0x3ff));
1237 dib7000p_write_word(state, 144, coef_im[k] & 0x3ff);
1238 dib7000p_write_word(state, 143, (1 << 14) | (k << 10) | (coef_re[k] & 0x3ff));
1239 }
Olivier Grenie713d54a2011-01-04 04:54:31 -03001240 dib7000p_write_word(state, 143, 0);
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001241}
1242
1243static int dib7000p_tune(struct dvb_frontend *demod, struct dvb_frontend_parameters *ch)
Patrick Boettchera75763f2006-10-18 08:34:16 -03001244{
1245 struct dib7000p_state *state = demod->demodulator_priv;
1246 u16 tmp = 0;
1247
1248 if (ch != NULL)
1249 dib7000p_set_channel(state, ch, 0);
1250 else
1251 return -EINVAL;
1252
1253 // restart demod
1254 dib7000p_write_word(state, 770, 0x4000);
1255 dib7000p_write_word(state, 770, 0x0000);
1256 msleep(45);
1257
1258 /* 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 -03001259 tmp = (0 << 14) | (4 << 10) | (0 << 9) | (3 << 5) | (1 << 4) | (0x3);
1260 if (state->sfn_workaround_active) {
Olivier Grenie713d54a2011-01-04 04:54:31 -03001261 dprintk("SFN workaround is active");
Matt Doran8f6956c2007-07-31 07:09:30 -03001262 tmp |= (1 << 9);
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001263 dib7000p_write_word(state, 166, 0x4000);
Matt Doran8f6956c2007-07-31 07:09:30 -03001264 } else {
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001265 dib7000p_write_word(state, 166, 0x0000);
Matt Doran8f6956c2007-07-31 07:09:30 -03001266 }
1267 dib7000p_write_word(state, 29, tmp);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001268
1269 // never achieved a lock with that bandwidth so far - wait for osc-freq to update
1270 if (state->timf == 0)
1271 msleep(200);
1272
1273 /* offset loop parameters */
1274
1275 /* P_timf_alpha, P_corm_alpha=6, P_corm_thres=0x80 */
1276 tmp = (6 << 8) | 0x80;
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001277 switch (ch->u.ofdm.transmission_mode) {
Olivier Grenie713d54a2011-01-04 04:54:31 -03001278 case TRANSMISSION_MODE_2K:
1279 tmp |= (2 << 12);
1280 break;
Mauro Carvalho Chehab46f72962011-01-16 13:01:20 -02001281 case TRANSMISSION_MODE_4K:
Olivier Grenie713d54a2011-01-04 04:54:31 -03001282 tmp |= (3 << 12);
1283 break;
1284 default:
1285 case TRANSMISSION_MODE_8K:
1286 tmp |= (4 << 12);
1287 break;
Patrick Boettchera75763f2006-10-18 08:34:16 -03001288 }
Olivier Grenie713d54a2011-01-04 04:54:31 -03001289 dib7000p_write_word(state, 26, tmp); /* timf_a(6xxx) */
Patrick Boettchera75763f2006-10-18 08:34:16 -03001290
1291 /* P_ctrl_freeze_pha_shift=0, P_ctrl_pha_off_max */
1292 tmp = (0 << 4);
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001293 switch (ch->u.ofdm.transmission_mode) {
Olivier Grenie713d54a2011-01-04 04:54:31 -03001294 case TRANSMISSION_MODE_2K:
1295 tmp |= 0x6;
1296 break;
Mauro Carvalho Chehab46f72962011-01-16 13:01:20 -02001297 case TRANSMISSION_MODE_4K:
Olivier Grenie713d54a2011-01-04 04:54:31 -03001298 tmp |= 0x7;
1299 break;
1300 default:
1301 case TRANSMISSION_MODE_8K:
1302 tmp |= 0x8;
1303 break;
Patrick Boettchera75763f2006-10-18 08:34:16 -03001304 }
Olivier Grenie713d54a2011-01-04 04:54:31 -03001305 dib7000p_write_word(state, 32, tmp);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001306
1307 /* P_ctrl_sfreq_inh=0, P_ctrl_sfreq_step */
1308 tmp = (0 << 4);
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001309 switch (ch->u.ofdm.transmission_mode) {
Olivier Grenie713d54a2011-01-04 04:54:31 -03001310 case TRANSMISSION_MODE_2K:
1311 tmp |= 0x6;
1312 break;
1313 case TRANSMISSION_MODE_4K:
1314 tmp |= 0x7;
1315 break;
1316 default:
1317 case TRANSMISSION_MODE_8K:
1318 tmp |= 0x8;
1319 break;
Patrick Boettchera75763f2006-10-18 08:34:16 -03001320 }
Olivier Grenie713d54a2011-01-04 04:54:31 -03001321 dib7000p_write_word(state, 33, tmp);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001322
Olivier Grenie713d54a2011-01-04 04:54:31 -03001323 tmp = dib7000p_read_word(state, 509);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001324 if (!((tmp >> 6) & 0x1)) {
1325 /* restart the fec */
Olivier Grenie713d54a2011-01-04 04:54:31 -03001326 tmp = dib7000p_read_word(state, 771);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001327 dib7000p_write_word(state, 771, tmp | (1 << 1));
1328 dib7000p_write_word(state, 771, tmp);
Olivier Grenie713d54a2011-01-04 04:54:31 -03001329 msleep(40);
1330 tmp = dib7000p_read_word(state, 509);
1331 }
1332 // we achieved a lock - it's time to update the osc freq
1333 if ((tmp >> 6) & 0x1) {
1334 dib7000p_update_timf(state);
1335 /* P_timf_alpha += 2 */
1336 tmp = dib7000p_read_word(state, 26);
1337 dib7000p_write_word(state, 26, (tmp & ~(0xf << 12)) | ((((tmp >> 12) & 0xf) + 5) << 12));
Patrick Boettchera75763f2006-10-18 08:34:16 -03001338 }
1339
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001340 if (state->cfg.spur_protect)
Olivier Grenie713d54a2011-01-04 04:54:31 -03001341 dib7000p_spur_protect(state, ch->frequency / 1000, BANDWIDTH_TO_KHZ(ch->u.ofdm.bandwidth));
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001342
Olivier Grenie713d54a2011-01-04 04:54:31 -03001343 dib7000p_set_bandwidth(state, BANDWIDTH_TO_KHZ(ch->u.ofdm.bandwidth));
Patrick Boettchera75763f2006-10-18 08:34:16 -03001344 return 0;
1345}
1346
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001347static int dib7000p_wakeup(struct dvb_frontend *demod)
Patrick Boettchera75763f2006-10-18 08:34:16 -03001348{
Patrick Boettchera75763f2006-10-18 08:34:16 -03001349 struct dib7000p_state *state = demod->demodulator_priv;
Patrick Boettchera75763f2006-10-18 08:34:16 -03001350 dib7000p_set_power_mode(state, DIB7000P_POWER_ALL);
1351 dib7000p_set_adc_state(state, DIBX000_SLOW_ADC_ON);
Olivier Grenie713d54a2011-01-04 04:54:31 -03001352 if (state->version == SOC7090)
1353 dib7000p_sad_calib(state);
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001354 return 0;
Patrick Boettchera75763f2006-10-18 08:34:16 -03001355}
1356
1357static int dib7000p_sleep(struct dvb_frontend *demod)
1358{
1359 struct dib7000p_state *state = demod->demodulator_priv;
Olivier Grenie713d54a2011-01-04 04:54:31 -03001360 if (state->version == SOC7090)
Olivier Grenie2e802862011-08-05 10:39:15 -03001361 return dib7000p_set_power_mode(state, DIB7000P_POWER_INTERFACE_ONLY);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001362 return dib7000p_set_output_mode(state, OUTMODE_HIGH_Z) | dib7000p_set_power_mode(state, DIB7000P_POWER_INTERFACE_ONLY);
1363}
1364
1365static int dib7000p_identify(struct dib7000p_state *st)
1366{
1367 u16 value;
Olivier Grenie713d54a2011-01-04 04:54:31 -03001368 dprintk("checking demod on I2C address: %d (%x)", st->i2c_addr, st->i2c_addr);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001369
1370 if ((value = dib7000p_read_word(st, 768)) != 0x01b3) {
Olivier Grenie713d54a2011-01-04 04:54:31 -03001371 dprintk("wrong Vendor ID (read=0x%x)", value);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001372 return -EREMOTEIO;
1373 }
1374
1375 if ((value = dib7000p_read_word(st, 769)) != 0x4000) {
Olivier Grenie713d54a2011-01-04 04:54:31 -03001376 dprintk("wrong Device ID (%x)", value);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001377 return -EREMOTEIO;
1378 }
1379
1380 return 0;
1381}
1382
Olivier Grenie713d54a2011-01-04 04:54:31 -03001383static int dib7000p_get_frontend(struct dvb_frontend *fe, struct dvb_frontend_parameters *fep)
Patrick Boettchera75763f2006-10-18 08:34:16 -03001384{
1385 struct dib7000p_state *state = fe->demodulator_priv;
Olivier Grenie713d54a2011-01-04 04:54:31 -03001386 u16 tps = dib7000p_read_word(state, 463);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001387
1388 fep->inversion = INVERSION_AUTO;
1389
Patrick Boettcher904a82e2008-01-25 07:31:58 -03001390 fep->u.ofdm.bandwidth = BANDWIDTH_TO_INDEX(state->current_bandwidth);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001391
1392 switch ((tps >> 8) & 0x3) {
Olivier Grenie713d54a2011-01-04 04:54:31 -03001393 case 0:
1394 fep->u.ofdm.transmission_mode = TRANSMISSION_MODE_2K;
1395 break;
1396 case 1:
1397 fep->u.ofdm.transmission_mode = TRANSMISSION_MODE_8K;
1398 break;
Mauro Carvalho Chehab46f72962011-01-16 13:01:20 -02001399 /* case 2: fep->u.ofdm.transmission_mode = TRANSMISSION_MODE_4K; break; */
Patrick Boettchera75763f2006-10-18 08:34:16 -03001400 }
1401
1402 switch (tps & 0x3) {
Olivier Grenie713d54a2011-01-04 04:54:31 -03001403 case 0:
1404 fep->u.ofdm.guard_interval = GUARD_INTERVAL_1_32;
1405 break;
1406 case 1:
1407 fep->u.ofdm.guard_interval = GUARD_INTERVAL_1_16;
1408 break;
1409 case 2:
1410 fep->u.ofdm.guard_interval = GUARD_INTERVAL_1_8;
1411 break;
1412 case 3:
1413 fep->u.ofdm.guard_interval = GUARD_INTERVAL_1_4;
1414 break;
Patrick Boettchera75763f2006-10-18 08:34:16 -03001415 }
1416
1417 switch ((tps >> 14) & 0x3) {
Olivier Grenie713d54a2011-01-04 04:54:31 -03001418 case 0:
1419 fep->u.ofdm.constellation = QPSK;
1420 break;
1421 case 1:
1422 fep->u.ofdm.constellation = QAM_16;
1423 break;
1424 case 2:
1425 default:
1426 fep->u.ofdm.constellation = QAM_64;
1427 break;
Patrick Boettchera75763f2006-10-18 08:34:16 -03001428 }
1429
1430 /* as long as the frontend_param structure is fixed for hierarchical transmission I refuse to use it */
1431 /* (tps >> 13) & 0x1 == hrch is used, (tps >> 10) & 0x7 == alpha */
1432
1433 fep->u.ofdm.hierarchy_information = HIERARCHY_NONE;
1434 switch ((tps >> 5) & 0x7) {
Olivier Grenie713d54a2011-01-04 04:54:31 -03001435 case 1:
1436 fep->u.ofdm.code_rate_HP = FEC_1_2;
1437 break;
1438 case 2:
1439 fep->u.ofdm.code_rate_HP = FEC_2_3;
1440 break;
1441 case 3:
1442 fep->u.ofdm.code_rate_HP = FEC_3_4;
1443 break;
1444 case 5:
1445 fep->u.ofdm.code_rate_HP = FEC_5_6;
1446 break;
1447 case 7:
1448 default:
1449 fep->u.ofdm.code_rate_HP = FEC_7_8;
1450 break;
Patrick Boettchera75763f2006-10-18 08:34:16 -03001451
1452 }
1453
1454 switch ((tps >> 2) & 0x7) {
Olivier Grenie713d54a2011-01-04 04:54:31 -03001455 case 1:
1456 fep->u.ofdm.code_rate_LP = FEC_1_2;
1457 break;
1458 case 2:
1459 fep->u.ofdm.code_rate_LP = FEC_2_3;
1460 break;
1461 case 3:
1462 fep->u.ofdm.code_rate_LP = FEC_3_4;
1463 break;
1464 case 5:
1465 fep->u.ofdm.code_rate_LP = FEC_5_6;
1466 break;
1467 case 7:
1468 default:
1469 fep->u.ofdm.code_rate_LP = FEC_7_8;
1470 break;
Patrick Boettchera75763f2006-10-18 08:34:16 -03001471 }
1472
1473 /* native interleaver: (dib7000p_read_word(state, 464) >> 5) & 0x1 */
1474
1475 return 0;
1476}
1477
Olivier Grenie713d54a2011-01-04 04:54:31 -03001478static int dib7000p_set_frontend(struct dvb_frontend *fe, struct dvb_frontend_parameters *fep)
Patrick Boettchera75763f2006-10-18 08:34:16 -03001479{
1480 struct dib7000p_state *state = fe->demodulator_priv;
Soeren Moch853ea132008-01-25 06:27:06 -03001481 int time, ret;
Patrick Boettchera75763f2006-10-18 08:34:16 -03001482
Olivier Grenie2e802862011-08-05 10:39:15 -03001483 if (state->version == SOC7090)
Olivier Grenie713d54a2011-01-04 04:54:31 -03001484 dib7090_set_diversity_in(fe, 0);
Olivier Grenie2e802862011-08-05 10:39:15 -03001485 else
Olivier Grenie713d54a2011-01-04 04:54:31 -03001486 dib7000p_set_output_mode(state, OUTMODE_HIGH_Z);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001487
Olivier Grenie713d54a2011-01-04 04:54:31 -03001488 /* maybe the parameter has been changed */
Matt Doran8f6956c2007-07-31 07:09:30 -03001489 state->sfn_workaround_active = buggy_sfn_workaround;
1490
Patrick Boettchera75763f2006-10-18 08:34:16 -03001491 if (fe->ops.tuner_ops.set_params)
Mauro Carvalho Chehab14d24d12011-12-24 12:24:33 -03001492 fe->ops.tuner_ops.set_params(fe);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001493
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001494 /* start up the AGC */
1495 state->agc_state = 0;
1496 do {
1497 time = dib7000p_agc_startup(fe, fep);
1498 if (time != -1)
1499 msleep(time);
1500 } while (time != -1);
1501
Patrick Boettchera75763f2006-10-18 08:34:16 -03001502 if (fep->u.ofdm.transmission_mode == TRANSMISSION_MODE_AUTO ||
Olivier Grenie713d54a2011-01-04 04:54:31 -03001503 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 -03001504 int i = 800, found;
1505
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001506 dib7000p_autosearch_start(fe, fep);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001507 do {
1508 msleep(1);
1509 found = dib7000p_autosearch_is_irq(fe);
1510 } while (found == 0 && i--);
1511
Olivier Grenie713d54a2011-01-04 04:54:31 -03001512 dprintk("autosearch returns: %d", found);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001513 if (found == 0 || found == 1)
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001514 return 0;
Patrick Boettchera75763f2006-10-18 08:34:16 -03001515
1516 dib7000p_get_frontend(fe, fep);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001517 }
1518
Soeren Moch853ea132008-01-25 06:27:06 -03001519 ret = dib7000p_tune(fe, fep);
1520
Patrick Boettchera75763f2006-10-18 08:34:16 -03001521 /* make this a config parameter */
Olivier Grenie2e802862011-08-05 10:39:15 -03001522 if (state->version == SOC7090) {
Olivier Grenie713d54a2011-01-04 04:54:31 -03001523 dib7090_set_output_mode(fe, state->cfg.output_mode);
Olivier Grenie2e802862011-08-05 10:39:15 -03001524 if (state->cfg.enMpegOutput == 0) {
1525 dib7090_setDibTxMux(state, MPEG_ON_DIBTX);
1526 dib7090_setHostBusMux(state, DIBTX_ON_HOSTBUS);
1527 }
1528 } else
Olivier Grenie713d54a2011-01-04 04:54:31 -03001529 dib7000p_set_output_mode(state, state->cfg.output_mode);
1530
1531 return ret;
Patrick Boettchera75763f2006-10-18 08:34:16 -03001532}
1533
Olivier Grenie713d54a2011-01-04 04:54:31 -03001534static int dib7000p_read_status(struct dvb_frontend *fe, fe_status_t * stat)
Patrick Boettchera75763f2006-10-18 08:34:16 -03001535{
1536 struct dib7000p_state *state = fe->demodulator_priv;
1537 u16 lock = dib7000p_read_word(state, 509);
1538
1539 *stat = 0;
1540
1541 if (lock & 0x8000)
1542 *stat |= FE_HAS_SIGNAL;
1543 if (lock & 0x3000)
1544 *stat |= FE_HAS_CARRIER;
1545 if (lock & 0x0100)
1546 *stat |= FE_HAS_VITERBI;
1547 if (lock & 0x0010)
1548 *stat |= FE_HAS_SYNC;
Olivier Grenie713d54a2011-01-04 04:54:31 -03001549 if ((lock & 0x0038) == 0x38)
Patrick Boettchera75763f2006-10-18 08:34:16 -03001550 *stat |= FE_HAS_LOCK;
1551
1552 return 0;
1553}
1554
Olivier Grenie713d54a2011-01-04 04:54:31 -03001555static int dib7000p_read_ber(struct dvb_frontend *fe, u32 * ber)
Patrick Boettchera75763f2006-10-18 08:34:16 -03001556{
1557 struct dib7000p_state *state = fe->demodulator_priv;
1558 *ber = (dib7000p_read_word(state, 500) << 16) | dib7000p_read_word(state, 501);
1559 return 0;
1560}
1561
Olivier Grenie713d54a2011-01-04 04:54:31 -03001562static int dib7000p_read_unc_blocks(struct dvb_frontend *fe, u32 * unc)
Patrick Boettchera75763f2006-10-18 08:34:16 -03001563{
1564 struct dib7000p_state *state = fe->demodulator_priv;
1565 *unc = dib7000p_read_word(state, 506);
1566 return 0;
1567}
1568
Olivier Grenie713d54a2011-01-04 04:54:31 -03001569static int dib7000p_read_signal_strength(struct dvb_frontend *fe, u16 * strength)
Patrick Boettchera75763f2006-10-18 08:34:16 -03001570{
1571 struct dib7000p_state *state = fe->demodulator_priv;
1572 u16 val = dib7000p_read_word(state, 394);
1573 *strength = 65535 - val;
1574 return 0;
1575}
1576
Olivier Grenie713d54a2011-01-04 04:54:31 -03001577static int dib7000p_read_snr(struct dvb_frontend *fe, u16 * snr)
Patrick Boettchera75763f2006-10-18 08:34:16 -03001578{
Olivier Grenieef801962009-09-15 06:46:52 -03001579 struct dib7000p_state *state = fe->demodulator_priv;
1580 u16 val;
1581 s32 signal_mant, signal_exp, noise_mant, noise_exp;
1582 u32 result = 0;
1583
1584 val = dib7000p_read_word(state, 479);
1585 noise_mant = (val >> 4) & 0xff;
1586 noise_exp = ((val & 0xf) << 2);
1587 val = dib7000p_read_word(state, 480);
1588 noise_exp += ((val >> 14) & 0x3);
1589 if ((noise_exp & 0x20) != 0)
1590 noise_exp -= 0x40;
1591
1592 signal_mant = (val >> 6) & 0xFF;
Olivier Grenie713d54a2011-01-04 04:54:31 -03001593 signal_exp = (val & 0x3F);
Olivier Grenieef801962009-09-15 06:46:52 -03001594 if ((signal_exp & 0x20) != 0)
1595 signal_exp -= 0x40;
1596
1597 if (signal_mant != 0)
Olivier Grenie713d54a2011-01-04 04:54:31 -03001598 result = intlog10(2) * 10 * signal_exp + 10 * intlog10(signal_mant);
Olivier Grenieef801962009-09-15 06:46:52 -03001599 else
1600 result = intlog10(2) * 10 * signal_exp - 100;
1601
1602 if (noise_mant != 0)
Olivier Grenie713d54a2011-01-04 04:54:31 -03001603 result -= intlog10(2) * 10 * noise_exp + 10 * intlog10(noise_mant);
Olivier Grenieef801962009-09-15 06:46:52 -03001604 else
1605 result -= intlog10(2) * 10 * noise_exp - 100;
1606
1607 *snr = result / ((1 << 24) / 10);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001608 return 0;
1609}
1610
Olivier Grenie713d54a2011-01-04 04:54:31 -03001611static int dib7000p_fe_get_tune_settings(struct dvb_frontend *fe, struct dvb_frontend_tune_settings *tune)
Patrick Boettchera75763f2006-10-18 08:34:16 -03001612{
1613 tune->min_delay_ms = 1000;
1614 return 0;
1615}
1616
1617static void dib7000p_release(struct dvb_frontend *demod)
1618{
1619 struct dib7000p_state *st = demod->demodulator_priv;
1620 dibx000_exit_i2c_master(&st->i2c_master);
Olivier Grenie713d54a2011-01-04 04:54:31 -03001621 i2c_del_adapter(&st->dib7090_tuner_adap);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001622 kfree(st);
1623}
1624
1625int dib7000pc_detection(struct i2c_adapter *i2c_adap)
1626{
Olivier Grenie5a0deee2011-05-03 12:27:33 -03001627 u8 *tx, *rx;
Patrick Boettchera75763f2006-10-18 08:34:16 -03001628 struct i2c_msg msg[2] = {
Olivier Grenie5a0deee2011-05-03 12:27:33 -03001629 {.addr = 18 >> 1, .flags = 0, .len = 2},
1630 {.addr = 18 >> 1, .flags = I2C_M_RD, .len = 2},
Patrick Boettchera75763f2006-10-18 08:34:16 -03001631 };
Olivier Grenie5a0deee2011-05-03 12:27:33 -03001632 int ret = 0;
1633
1634 tx = kzalloc(2*sizeof(u8), GFP_KERNEL);
1635 if (!tx)
1636 return -ENOMEM;
1637 rx = kzalloc(2*sizeof(u8), GFP_KERNEL);
1638 if (!rx) {
Olivier Grenie5a0deee2011-05-03 12:27:33 -03001639 ret = -ENOMEM;
Dan Carpenter0c61cc3b2011-08-06 05:00:34 -03001640 goto rx_memory_error;
Olivier Grenie5a0deee2011-05-03 12:27:33 -03001641 }
1642
1643 msg[0].buf = tx;
1644 msg[1].buf = rx;
Patrick Boettchera75763f2006-10-18 08:34:16 -03001645
1646 tx[0] = 0x03;
1647 tx[1] = 0x00;
1648
1649 if (i2c_transfer(i2c_adap, msg, 2) == 2)
1650 if (rx[0] == 0x01 && rx[1] == 0xb3) {
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001651 dprintk("-D- DiB7000PC detected");
Patrick Boettchera75763f2006-10-18 08:34:16 -03001652 return 1;
1653 }
1654
1655 msg[0].addr = msg[1].addr = 0x40;
1656
1657 if (i2c_transfer(i2c_adap, msg, 2) == 2)
1658 if (rx[0] == 0x01 && rx[1] == 0xb3) {
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001659 dprintk("-D- DiB7000PC detected");
Patrick Boettchera75763f2006-10-18 08:34:16 -03001660 return 1;
1661 }
1662
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001663 dprintk("-D- DiB7000PC not detected");
Olivier Grenie5a0deee2011-05-03 12:27:33 -03001664
1665 kfree(rx);
1666rx_memory_error:
1667 kfree(tx);
1668 return ret;
Patrick Boettchera75763f2006-10-18 08:34:16 -03001669}
1670EXPORT_SYMBOL(dib7000pc_detection);
1671
Olivier Grenie713d54a2011-01-04 04:54:31 -03001672struct i2c_adapter *dib7000p_get_i2c_master(struct dvb_frontend *demod, enum dibx000_i2c_interface intf, int gating)
Patrick Boettchera75763f2006-10-18 08:34:16 -03001673{
1674 struct dib7000p_state *st = demod->demodulator_priv;
1675 return dibx000_get_i2c_adapter(&st->i2c_master, intf, gating);
1676}
1677EXPORT_SYMBOL(dib7000p_get_i2c_master);
1678
Olivier Grenief8731f42009-09-18 04:08:43 -03001679int dib7000p_pid_filter_ctrl(struct dvb_frontend *fe, u8 onoff)
1680{
Olivier Grenie713d54a2011-01-04 04:54:31 -03001681 struct dib7000p_state *state = fe->demodulator_priv;
1682 u16 val = dib7000p_read_word(state, 235) & 0xffef;
1683 val |= (onoff & 0x1) << 4;
1684 dprintk("PID filter enabled %d", onoff);
1685 return dib7000p_write_word(state, 235, val);
Olivier Grenief8731f42009-09-18 04:08:43 -03001686}
1687EXPORT_SYMBOL(dib7000p_pid_filter_ctrl);
1688
1689int dib7000p_pid_filter(struct dvb_frontend *fe, u8 id, u16 pid, u8 onoff)
1690{
Olivier Grenie713d54a2011-01-04 04:54:31 -03001691 struct dib7000p_state *state = fe->demodulator_priv;
1692 dprintk("PID filter: index %x, PID %d, OnOff %d", id, pid, onoff);
1693 return dib7000p_write_word(state, 241 + id, onoff ? (1 << 13) | pid : 0);
Olivier Grenief8731f42009-09-18 04:08:43 -03001694}
1695EXPORT_SYMBOL(dib7000p_pid_filter);
1696
Patrick Boettchera75763f2006-10-18 08:34:16 -03001697int dib7000p_i2c_enumeration(struct i2c_adapter *i2c, int no_of_demods, u8 default_addr, struct dib7000p_config cfg[])
1698{
Randy Dunlap30d81bb2010-02-08 20:30:44 -03001699 struct dib7000p_state *dpst;
Patrick Boettchera75763f2006-10-18 08:34:16 -03001700 int k = 0;
1701 u8 new_addr = 0;
1702
Randy Dunlap30d81bb2010-02-08 20:30:44 -03001703 dpst = kzalloc(sizeof(struct dib7000p_state), GFP_KERNEL);
1704 if (!dpst)
Andrew Morton0b427602010-04-27 19:09:45 -03001705 return -ENOMEM;
Randy Dunlap30d81bb2010-02-08 20:30:44 -03001706
1707 dpst->i2c_adap = i2c;
Patrick Boettcher79fcce32011-08-03 12:08:21 -03001708 mutex_init(&dpst->i2c_buffer_lock);
Randy Dunlap30d81bb2010-02-08 20:30:44 -03001709
Olivier Grenie713d54a2011-01-04 04:54:31 -03001710 for (k = no_of_demods - 1; k >= 0; k--) {
Randy Dunlap30d81bb2010-02-08 20:30:44 -03001711 dpst->cfg = cfg[k];
Patrick Boettchera75763f2006-10-18 08:34:16 -03001712
1713 /* designated i2c address */
Olivier Grenie713d54a2011-01-04 04:54:31 -03001714 if (cfg[k].default_i2c_addr != 0)
1715 new_addr = cfg[k].default_i2c_addr + (k << 1);
1716 else
1717 new_addr = (0x40 + k) << 1;
Randy Dunlap30d81bb2010-02-08 20:30:44 -03001718 dpst->i2c_addr = new_addr;
Olivier Grenie713d54a2011-01-04 04:54:31 -03001719 dib7000p_write_word(dpst, 1287, 0x0003); /* sram lead in, rdy */
Randy Dunlap30d81bb2010-02-08 20:30:44 -03001720 if (dib7000p_identify(dpst) != 0) {
1721 dpst->i2c_addr = default_addr;
Olivier Grenie713d54a2011-01-04 04:54:31 -03001722 dib7000p_write_word(dpst, 1287, 0x0003); /* sram lead in, rdy */
Randy Dunlap30d81bb2010-02-08 20:30:44 -03001723 if (dib7000p_identify(dpst) != 0) {
Patrick Boettchera75763f2006-10-18 08:34:16 -03001724 dprintk("DiB7000P #%d: not identified\n", k);
Randy Dunlap30d81bb2010-02-08 20:30:44 -03001725 kfree(dpst);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001726 return -EIO;
1727 }
1728 }
1729
1730 /* start diversity to pull_down div_str - just for i2c-enumeration */
Randy Dunlap30d81bb2010-02-08 20:30:44 -03001731 dib7000p_set_output_mode(dpst, OUTMODE_DIVERSITY);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001732
1733 /* set new i2c address and force divstart */
Randy Dunlap30d81bb2010-02-08 20:30:44 -03001734 dib7000p_write_word(dpst, 1285, (new_addr << 2) | 0x2);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001735
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001736 dprintk("IC %d initialized (to i2c_address 0x%x)", k, new_addr);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001737 }
1738
1739 for (k = 0; k < no_of_demods; k++) {
Randy Dunlap30d81bb2010-02-08 20:30:44 -03001740 dpst->cfg = cfg[k];
Olivier Grenie713d54a2011-01-04 04:54:31 -03001741 if (cfg[k].default_i2c_addr != 0)
1742 dpst->i2c_addr = (cfg[k].default_i2c_addr + k) << 1;
1743 else
1744 dpst->i2c_addr = (0x40 + k) << 1;
Patrick Boettchera75763f2006-10-18 08:34:16 -03001745
1746 // unforce divstr
Randy Dunlap30d81bb2010-02-08 20:30:44 -03001747 dib7000p_write_word(dpst, 1285, dpst->i2c_addr << 2);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001748
1749 /* deactivate div - it was just for i2c-enumeration */
Randy Dunlap30d81bb2010-02-08 20:30:44 -03001750 dib7000p_set_output_mode(dpst, OUTMODE_HIGH_Z);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001751 }
1752
Randy Dunlap30d81bb2010-02-08 20:30:44 -03001753 kfree(dpst);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001754 return 0;
1755}
1756EXPORT_SYMBOL(dib7000p_i2c_enumeration);
1757
Olivier Grenie713d54a2011-01-04 04:54:31 -03001758static const s32 lut_1000ln_mant[] = {
1759 6908, 6956, 7003, 7047, 7090, 7131, 7170, 7208, 7244, 7279, 7313, 7346, 7377, 7408, 7438, 7467, 7495, 7523, 7549, 7575, 7600
1760};
1761
1762static s32 dib7000p_get_adc_power(struct dvb_frontend *fe)
1763{
1764 struct dib7000p_state *state = fe->demodulator_priv;
1765 u32 tmp_val = 0, exp = 0, mant = 0;
1766 s32 pow_i;
1767 u16 buf[2];
1768 u8 ix = 0;
1769
1770 buf[0] = dib7000p_read_word(state, 0x184);
1771 buf[1] = dib7000p_read_word(state, 0x185);
1772 pow_i = (buf[0] << 16) | buf[1];
1773 dprintk("raw pow_i = %d", pow_i);
1774
1775 tmp_val = pow_i;
1776 while (tmp_val >>= 1)
1777 exp++;
1778
1779 mant = (pow_i * 1000 / (1 << exp));
1780 dprintk(" mant = %d exp = %d", mant / 1000, exp);
1781
1782 ix = (u8) ((mant - 1000) / 100); /* index of the LUT */
1783 dprintk(" ix = %d", ix);
1784
1785 pow_i = (lut_1000ln_mant[ix] + 693 * (exp - 20) - 6908);
1786 pow_i = (pow_i << 8) / 1000;
1787 dprintk(" pow_i = %d", pow_i);
1788
1789 return pow_i;
1790}
1791
1792static int map_addr_to_serpar_number(struct i2c_msg *msg)
1793{
1794 if ((msg->buf[0] <= 15))
1795 msg->buf[0] -= 1;
1796 else if (msg->buf[0] == 17)
1797 msg->buf[0] = 15;
1798 else if (msg->buf[0] == 16)
1799 msg->buf[0] = 17;
1800 else if (msg->buf[0] == 19)
1801 msg->buf[0] = 16;
1802 else if (msg->buf[0] >= 21 && msg->buf[0] <= 25)
1803 msg->buf[0] -= 3;
1804 else if (msg->buf[0] == 28)
1805 msg->buf[0] = 23;
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001806 else
Olivier Grenie713d54a2011-01-04 04:54:31 -03001807 return -EINVAL;
Olivier Grenie713d54a2011-01-04 04:54:31 -03001808 return 0;
1809}
1810
1811static int w7090p_tuner_write_serpar(struct i2c_adapter *i2c_adap, struct i2c_msg msg[], int num)
1812{
1813 struct dib7000p_state *state = i2c_get_adapdata(i2c_adap);
1814 u8 n_overflow = 1;
1815 u16 i = 1000;
1816 u16 serpar_num = msg[0].buf[0];
1817
1818 while (n_overflow == 1 && i) {
1819 n_overflow = (dib7000p_read_word(state, 1984) >> 1) & 0x1;
1820 i--;
1821 if (i == 0)
1822 dprintk("Tuner ITF: write busy (overflow)");
1823 }
1824 dib7000p_write_word(state, 1985, (1 << 6) | (serpar_num & 0x3f));
1825 dib7000p_write_word(state, 1986, (msg[0].buf[1] << 8) | msg[0].buf[2]);
1826
1827 return num;
1828}
1829
1830static int w7090p_tuner_read_serpar(struct i2c_adapter *i2c_adap, struct i2c_msg msg[], int num)
1831{
1832 struct dib7000p_state *state = i2c_get_adapdata(i2c_adap);
1833 u8 n_overflow = 1, n_empty = 1;
1834 u16 i = 1000;
1835 u16 serpar_num = msg[0].buf[0];
1836 u16 read_word;
1837
1838 while (n_overflow == 1 && i) {
1839 n_overflow = (dib7000p_read_word(state, 1984) >> 1) & 0x1;
1840 i--;
1841 if (i == 0)
1842 dprintk("TunerITF: read busy (overflow)");
1843 }
1844 dib7000p_write_word(state, 1985, (0 << 6) | (serpar_num & 0x3f));
1845
1846 i = 1000;
1847 while (n_empty == 1 && i) {
1848 n_empty = dib7000p_read_word(state, 1984) & 0x1;
1849 i--;
1850 if (i == 0)
1851 dprintk("TunerITF: read busy (empty)");
1852 }
1853 read_word = dib7000p_read_word(state, 1987);
1854 msg[1].buf[0] = (read_word >> 8) & 0xff;
1855 msg[1].buf[1] = (read_word) & 0xff;
1856
1857 return num;
1858}
1859
1860static int w7090p_tuner_rw_serpar(struct i2c_adapter *i2c_adap, struct i2c_msg msg[], int num)
1861{
1862 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... */
1863 if (num == 1) { /* write */
1864 return w7090p_tuner_write_serpar(i2c_adap, msg, 1);
1865 } else { /* read */
1866 return w7090p_tuner_read_serpar(i2c_adap, msg, 2);
1867 }
1868 }
1869 return num;
1870}
1871
Olivier Greniea685dbb2011-08-05 14:10:40 -03001872static int dib7090p_rw_on_apb(struct i2c_adapter *i2c_adap,
1873 struct i2c_msg msg[], int num, u16 apb_address)
Olivier Grenie713d54a2011-01-04 04:54:31 -03001874{
1875 struct dib7000p_state *state = i2c_get_adapdata(i2c_adap);
1876 u16 word;
1877
1878 if (num == 1) { /* write */
1879 dib7000p_write_word(state, apb_address, ((msg[0].buf[1] << 8) | (msg[0].buf[2])));
1880 } else {
1881 word = dib7000p_read_word(state, apb_address);
1882 msg[1].buf[0] = (word >> 8) & 0xff;
1883 msg[1].buf[1] = (word) & 0xff;
1884 }
1885
1886 return num;
1887}
1888
1889static int dib7090_tuner_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg msg[], int num)
1890{
1891 struct dib7000p_state *state = i2c_get_adapdata(i2c_adap);
1892
1893 u16 apb_address = 0, word;
1894 int i = 0;
1895 switch (msg[0].buf[0]) {
1896 case 0x12:
1897 apb_address = 1920;
1898 break;
1899 case 0x14:
1900 apb_address = 1921;
1901 break;
1902 case 0x24:
1903 apb_address = 1922;
1904 break;
1905 case 0x1a:
1906 apb_address = 1923;
1907 break;
1908 case 0x22:
1909 apb_address = 1924;
1910 break;
1911 case 0x33:
1912 apb_address = 1926;
1913 break;
1914 case 0x34:
1915 apb_address = 1927;
1916 break;
1917 case 0x35:
1918 apb_address = 1928;
1919 break;
1920 case 0x36:
1921 apb_address = 1929;
1922 break;
1923 case 0x37:
1924 apb_address = 1930;
1925 break;
1926 case 0x38:
1927 apb_address = 1931;
1928 break;
1929 case 0x39:
1930 apb_address = 1932;
1931 break;
1932 case 0x2a:
1933 apb_address = 1935;
1934 break;
1935 case 0x2b:
1936 apb_address = 1936;
1937 break;
1938 case 0x2c:
1939 apb_address = 1937;
1940 break;
1941 case 0x2d:
1942 apb_address = 1938;
1943 break;
1944 case 0x2e:
1945 apb_address = 1939;
1946 break;
1947 case 0x2f:
1948 apb_address = 1940;
1949 break;
1950 case 0x30:
1951 apb_address = 1941;
1952 break;
1953 case 0x31:
1954 apb_address = 1942;
1955 break;
1956 case 0x32:
1957 apb_address = 1943;
1958 break;
1959 case 0x3e:
1960 apb_address = 1944;
1961 break;
1962 case 0x3f:
1963 apb_address = 1945;
1964 break;
1965 case 0x40:
1966 apb_address = 1948;
1967 break;
1968 case 0x25:
1969 apb_address = 914;
1970 break;
1971 case 0x26:
1972 apb_address = 915;
1973 break;
1974 case 0x27:
Olivier Grenie2e802862011-08-05 10:39:15 -03001975 apb_address = 917;
Olivier Grenie713d54a2011-01-04 04:54:31 -03001976 break;
1977 case 0x28:
Olivier Grenie2e802862011-08-05 10:39:15 -03001978 apb_address = 916;
Olivier Grenie713d54a2011-01-04 04:54:31 -03001979 break;
1980 case 0x1d:
1981 i = ((dib7000p_read_word(state, 72) >> 12) & 0x3);
1982 word = dib7000p_read_word(state, 384 + i);
1983 msg[1].buf[0] = (word >> 8) & 0xff;
1984 msg[1].buf[1] = (word) & 0xff;
1985 return num;
1986 case 0x1f:
1987 if (num == 1) { /* write */
1988 word = (u16) ((msg[0].buf[1] << 8) | msg[0].buf[2]);
1989 word &= 0x3;
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001990 word = (dib7000p_read_word(state, 72) & ~(3 << 12)) | (word << 12);
Olivier Grenie713d54a2011-01-04 04:54:31 -03001991 dib7000p_write_word(state, 72, word); /* Set the proper input */
1992 return num;
1993 }
1994 }
1995
1996 if (apb_address != 0) /* R/W acces via APB */
1997 return dib7090p_rw_on_apb(i2c_adap, msg, num, apb_address);
1998 else /* R/W access via SERPAR */
1999 return w7090p_tuner_rw_serpar(i2c_adap, msg, num);
2000
2001 return 0;
2002}
2003
2004static u32 dib7000p_i2c_func(struct i2c_adapter *adapter)
2005{
2006 return I2C_FUNC_I2C;
2007}
2008
2009static struct i2c_algorithm dib7090_tuner_xfer_algo = {
2010 .master_xfer = dib7090_tuner_xfer,
2011 .functionality = dib7000p_i2c_func,
2012};
2013
2014struct i2c_adapter *dib7090_get_i2c_tuner(struct dvb_frontend *fe)
2015{
2016 struct dib7000p_state *st = fe->demodulator_priv;
2017 return &st->dib7090_tuner_adap;
2018}
2019EXPORT_SYMBOL(dib7090_get_i2c_tuner);
2020
2021static int dib7090_host_bus_drive(struct dib7000p_state *state, u8 drive)
2022{
2023 u16 reg;
2024
2025 /* drive host bus 2, 3, 4 */
2026 reg = dib7000p_read_word(state, 1798) & ~((0x7) | (0x7 << 6) | (0x7 << 12));
2027 reg |= (drive << 12) | (drive << 6) | drive;
2028 dib7000p_write_word(state, 1798, reg);
2029
2030 /* drive host bus 5,6 */
2031 reg = dib7000p_read_word(state, 1799) & ~((0x7 << 2) | (0x7 << 8));
2032 reg |= (drive << 8) | (drive << 2);
2033 dib7000p_write_word(state, 1799, reg);
2034
2035 /* drive host bus 7, 8, 9 */
2036 reg = dib7000p_read_word(state, 1800) & ~((0x7) | (0x7 << 6) | (0x7 << 12));
2037 reg |= (drive << 12) | (drive << 6) | drive;
2038 dib7000p_write_word(state, 1800, reg);
2039
2040 /* drive host bus 10, 11 */
2041 reg = dib7000p_read_word(state, 1801) & ~((0x7 << 2) | (0x7 << 8));
2042 reg |= (drive << 8) | (drive << 2);
2043 dib7000p_write_word(state, 1801, reg);
2044
2045 /* drive host bus 12, 13, 14 */
2046 reg = dib7000p_read_word(state, 1802) & ~((0x7) | (0x7 << 6) | (0x7 << 12));
2047 reg |= (drive << 12) | (drive << 6) | drive;
2048 dib7000p_write_word(state, 1802, reg);
2049
2050 return 0;
2051}
2052
2053static u32 dib7090_calcSyncFreq(u32 P_Kin, u32 P_Kout, u32 insertExtSynchro, u32 syncSize)
2054{
2055 u32 quantif = 3;
2056 u32 nom = (insertExtSynchro * P_Kin + syncSize);
2057 u32 denom = P_Kout;
2058 u32 syncFreq = ((nom << quantif) / denom);
2059
2060 if ((syncFreq & ((1 << quantif) - 1)) != 0)
2061 syncFreq = (syncFreq >> quantif) + 1;
2062 else
2063 syncFreq = (syncFreq >> quantif);
2064
2065 if (syncFreq != 0)
2066 syncFreq = syncFreq - 1;
2067
2068 return syncFreq;
2069}
2070
2071static int dib7090_cfg_DibTx(struct dib7000p_state *state, u32 P_Kin, u32 P_Kout, u32 insertExtSynchro, u32 synchroMode, u32 syncWord, u32 syncSize)
2072{
Olivier Grenie713d54a2011-01-04 04:54:31 -03002073 dprintk("Configure DibStream Tx");
Olivier Grenie713d54a2011-01-04 04:54:31 -03002074
2075 dib7000p_write_word(state, 1615, 1);
2076 dib7000p_write_word(state, 1603, P_Kin);
2077 dib7000p_write_word(state, 1605, P_Kout);
2078 dib7000p_write_word(state, 1606, insertExtSynchro);
2079 dib7000p_write_word(state, 1608, synchroMode);
2080 dib7000p_write_word(state, 1609, (syncWord >> 16) & 0xffff);
2081 dib7000p_write_word(state, 1610, syncWord & 0xffff);
2082 dib7000p_write_word(state, 1612, syncSize);
2083 dib7000p_write_word(state, 1615, 0);
2084
Olivier Grenie713d54a2011-01-04 04:54:31 -03002085 return 0;
2086}
2087
2088static int dib7090_cfg_DibRx(struct dib7000p_state *state, u32 P_Kin, u32 P_Kout, u32 synchroMode, u32 insertExtSynchro, u32 syncWord, u32 syncSize,
2089 u32 dataOutRate)
2090{
2091 u32 syncFreq;
2092
2093 dprintk("Configure DibStream Rx");
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002094 if ((P_Kin != 0) && (P_Kout != 0)) {
Olivier Grenie713d54a2011-01-04 04:54:31 -03002095 syncFreq = dib7090_calcSyncFreq(P_Kin, P_Kout, insertExtSynchro, syncSize);
2096 dib7000p_write_word(state, 1542, syncFreq);
2097 }
2098 dib7000p_write_word(state, 1554, 1);
2099 dib7000p_write_word(state, 1536, P_Kin);
2100 dib7000p_write_word(state, 1537, P_Kout);
2101 dib7000p_write_word(state, 1539, synchroMode);
2102 dib7000p_write_word(state, 1540, (syncWord >> 16) & 0xffff);
2103 dib7000p_write_word(state, 1541, syncWord & 0xffff);
2104 dib7000p_write_word(state, 1543, syncSize);
2105 dib7000p_write_word(state, 1544, dataOutRate);
2106 dib7000p_write_word(state, 1554, 0);
2107
2108 return 0;
2109}
2110
Olivier Grenie2e802862011-08-05 10:39:15 -03002111static void dib7090_enMpegMux(struct dib7000p_state *state, int onoff)
Olivier Grenie713d54a2011-01-04 04:54:31 -03002112{
Olivier Grenie2e802862011-08-05 10:39:15 -03002113 u16 reg_1287 = dib7000p_read_word(state, 1287);
Olivier Grenie713d54a2011-01-04 04:54:31 -03002114
Olivier Grenie2e802862011-08-05 10:39:15 -03002115 switch (onoff) {
2116 case 1:
2117 reg_1287 &= ~(1<<7);
2118 break;
2119 case 0:
2120 reg_1287 |= (1<<7);
2121 break;
2122 }
Olivier Grenie713d54a2011-01-04 04:54:31 -03002123
Olivier Grenie2e802862011-08-05 10:39:15 -03002124 dib7000p_write_word(state, 1287, reg_1287);
Olivier Grenie713d54a2011-01-04 04:54:31 -03002125}
2126
Olivier Grenie2e802862011-08-05 10:39:15 -03002127static void dib7090_configMpegMux(struct dib7000p_state *state,
2128 u16 pulseWidth, u16 enSerialMode, u16 enSerialClkDiv2)
Olivier Grenie713d54a2011-01-04 04:54:31 -03002129{
Olivier Grenie713d54a2011-01-04 04:54:31 -03002130 dprintk("Enable Mpeg mux");
Olivier Grenie713d54a2011-01-04 04:54:31 -03002131
Olivier Grenie2e802862011-08-05 10:39:15 -03002132 dib7090_enMpegMux(state, 0);
Olivier Grenie713d54a2011-01-04 04:54:31 -03002133
Olivier Grenie2e802862011-08-05 10:39:15 -03002134 /* If the input mode is MPEG do not divide the serial clock */
2135 if ((enSerialMode == 1) && (state->input_mode_mpeg == 1))
2136 enSerialClkDiv2 = 0;
Olivier Grenie713d54a2011-01-04 04:54:31 -03002137
Olivier Grenie2e802862011-08-05 10:39:15 -03002138 dib7000p_write_word(state, 1287, ((pulseWidth & 0x1f) << 2)
2139 | ((enSerialMode & 0x1) << 1)
2140 | (enSerialClkDiv2 & 0x1));
2141
2142 dib7090_enMpegMux(state, 1);
Olivier Grenie713d54a2011-01-04 04:54:31 -03002143}
2144
Olivier Grenie2e802862011-08-05 10:39:15 -03002145static void dib7090_setDibTxMux(struct dib7000p_state *state, int mode)
Olivier Grenie713d54a2011-01-04 04:54:31 -03002146{
Olivier Grenie2e802862011-08-05 10:39:15 -03002147 u16 reg_1288 = dib7000p_read_word(state, 1288) & ~(0x7 << 7);
Olivier Grenie713d54a2011-01-04 04:54:31 -03002148
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002149 switch (mode) {
Olivier Grenie2e802862011-08-05 10:39:15 -03002150 case MPEG_ON_DIBTX:
2151 dprintk("SET MPEG ON DIBSTREAM TX");
2152 dib7090_cfg_DibTx(state, 8, 5, 0, 0, 0, 0);
2153 reg_1288 |= (1<<9);
Olivier Grenie713d54a2011-01-04 04:54:31 -03002154 break;
Olivier Grenie2e802862011-08-05 10:39:15 -03002155 case DIV_ON_DIBTX:
2156 dprintk("SET DIV_OUT ON DIBSTREAM TX");
2157 dib7090_cfg_DibTx(state, 5, 5, 0, 0, 0, 0);
2158 reg_1288 |= (1<<8);
Olivier Grenie713d54a2011-01-04 04:54:31 -03002159 break;
Olivier Grenie2e802862011-08-05 10:39:15 -03002160 case ADC_ON_DIBTX:
2161 dprintk("SET ADC_OUT ON DIBSTREAM TX");
2162 dib7090_cfg_DibTx(state, 20, 5, 10, 0, 0, 0);
2163 reg_1288 |= (1<<7);
2164 break;
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002165 default:
Olivier Grenie713d54a2011-01-04 04:54:31 -03002166 break;
2167 }
Olivier Grenie2e802862011-08-05 10:39:15 -03002168 dib7000p_write_word(state, 1288, reg_1288);
Olivier Grenie713d54a2011-01-04 04:54:31 -03002169}
2170
Olivier Grenie2e802862011-08-05 10:39:15 -03002171static void dib7090_setHostBusMux(struct dib7000p_state *state, int mode)
Olivier Grenie713d54a2011-01-04 04:54:31 -03002172{
Olivier Grenie2e802862011-08-05 10:39:15 -03002173 u16 reg_1288 = dib7000p_read_word(state, 1288) & ~(0x7 << 4);
2174
2175 switch (mode) {
2176 case DEMOUT_ON_HOSTBUS:
2177 dprintk("SET DEM OUT OLD INTERF ON HOST BUS");
2178 dib7090_enMpegMux(state, 0);
2179 reg_1288 |= (1<<6);
2180 break;
2181 case DIBTX_ON_HOSTBUS:
2182 dprintk("SET DIBSTREAM TX ON HOST BUS");
2183 dib7090_enMpegMux(state, 0);
2184 reg_1288 |= (1<<5);
2185 break;
2186 case MPEG_ON_HOSTBUS:
2187 dprintk("SET MPEG MUX ON HOST BUS");
2188 reg_1288 |= (1<<4);
2189 break;
2190 default:
2191 break;
2192 }
2193 dib7000p_write_word(state, 1288, reg_1288);
2194}
2195
2196int dib7090_set_diversity_in(struct dvb_frontend *fe, int onoff)
2197{
2198 struct dib7000p_state *state = fe->demodulator_priv;
2199 u16 reg_1287;
2200
Olivier Grenie713d54a2011-01-04 04:54:31 -03002201 switch (onoff) {
Olivier Grenie2e802862011-08-05 10:39:15 -03002202 case 0: /* only use the internal way - not the diversity input */
2203 dprintk("%s mode OFF : by default Enable Mpeg INPUT", __func__);
2204 dib7090_cfg_DibRx(state, 8, 5, 0, 0, 0, 8, 0);
2205
2206 /* Do not divide the serial clock of MPEG MUX */
2207 /* in SERIAL MODE in case input mode MPEG is used */
2208 reg_1287 = dib7000p_read_word(state, 1287);
2209 /* enSerialClkDiv2 == 1 ? */
2210 if ((reg_1287 & 0x1) == 1) {
2211 /* force enSerialClkDiv2 = 0 */
2212 reg_1287 &= ~0x1;
2213 dib7000p_write_word(state, 1287, reg_1287);
2214 }
2215 state->input_mode_mpeg = 1;
2216 break;
2217 case 1: /* both ways */
2218 case 2: /* only the diversity input */
2219 dprintk("%s ON : Enable diversity INPUT", __func__);
2220 dib7090_cfg_DibRx(state, 5, 5, 0, 0, 0, 0, 0);
2221 state->input_mode_mpeg = 0;
2222 break;
Olivier Grenie713d54a2011-01-04 04:54:31 -03002223 }
2224
Olivier Grenie2e802862011-08-05 10:39:15 -03002225 dib7000p_set_diversity_in(&state->demod, onoff);
Olivier Grenie713d54a2011-01-04 04:54:31 -03002226 return 0;
2227}
2228
2229static int dib7090_set_output_mode(struct dvb_frontend *fe, int mode)
2230{
2231 struct dib7000p_state *state = fe->demodulator_priv;
2232
2233 u16 outreg, smo_mode, fifo_threshold;
2234 u8 prefer_mpeg_mux_use = 1;
2235 int ret = 0;
2236
2237 dib7090_host_bus_drive(state, 1);
2238
2239 fifo_threshold = 1792;
2240 smo_mode = (dib7000p_read_word(state, 235) & 0x0050) | (1 << 1);
2241 outreg = dib7000p_read_word(state, 1286) & ~((1 << 10) | (0x7 << 6) | (1 << 1));
2242
2243 switch (mode) {
2244 case OUTMODE_HIGH_Z:
2245 outreg = 0;
2246 break;
2247
2248 case OUTMODE_MPEG2_SERIAL:
2249 if (prefer_mpeg_mux_use) {
Olivier Grenie2e802862011-08-05 10:39:15 -03002250 dprintk("setting output mode TS_SERIAL using Mpeg Mux");
2251 dib7090_configMpegMux(state, 3, 1, 1);
2252 dib7090_setHostBusMux(state, MPEG_ON_HOSTBUS);
2253 } else {/* Use Smooth block */
2254 dprintk("setting output mode TS_SERIAL using Smooth bloc");
2255 dib7090_setHostBusMux(state, DEMOUT_ON_HOSTBUS);
2256 outreg |= (2<<6) | (0 << 1);
Olivier Grenie713d54a2011-01-04 04:54:31 -03002257 }
2258 break;
2259
2260 case OUTMODE_MPEG2_PAR_GATED_CLK:
2261 if (prefer_mpeg_mux_use) {
Olivier Grenie2e802862011-08-05 10:39:15 -03002262 dprintk("setting output mode TS_PARALLEL_GATED using Mpeg Mux");
2263 dib7090_configMpegMux(state, 2, 0, 0);
2264 dib7090_setHostBusMux(state, MPEG_ON_HOSTBUS);
2265 } else { /* Use Smooth block */
2266 dprintk("setting output mode TS_PARALLEL_GATED using Smooth block");
2267 dib7090_setHostBusMux(state, DEMOUT_ON_HOSTBUS);
2268 outreg |= (0<<6);
Olivier Grenie713d54a2011-01-04 04:54:31 -03002269 }
2270 break;
2271
2272 case OUTMODE_MPEG2_PAR_CONT_CLK: /* Using Smooth block only */
Olivier Grenie2e802862011-08-05 10:39:15 -03002273 dprintk("setting output mode TS_PARALLEL_CONT using Smooth block");
2274 dib7090_setHostBusMux(state, DEMOUT_ON_HOSTBUS);
2275 outreg |= (1<<6);
Olivier Grenie713d54a2011-01-04 04:54:31 -03002276 break;
2277
2278 case OUTMODE_MPEG2_FIFO: /* Using Smooth block because not supported by new Mpeg Mux bloc */
Olivier Grenie2e802862011-08-05 10:39:15 -03002279 dprintk("setting output mode TS_FIFO using Smooth block");
2280 dib7090_setHostBusMux(state, DEMOUT_ON_HOSTBUS);
2281 outreg |= (5<<6);
Olivier Grenie713d54a2011-01-04 04:54:31 -03002282 smo_mode |= (3 << 1);
2283 fifo_threshold = 512;
2284 break;
2285
2286 case OUTMODE_DIVERSITY:
Olivier Grenie2e802862011-08-05 10:39:15 -03002287 dprintk("setting output mode MODE_DIVERSITY");
2288 dib7090_setDibTxMux(state, DIV_ON_DIBTX);
2289 dib7090_setHostBusMux(state, DIBTX_ON_HOSTBUS);
Olivier Grenie713d54a2011-01-04 04:54:31 -03002290 break;
2291
2292 case OUTMODE_ANALOG_ADC:
Olivier Grenie2e802862011-08-05 10:39:15 -03002293 dprintk("setting output mode MODE_ANALOG_ADC");
2294 dib7090_setDibTxMux(state, ADC_ON_DIBTX);
2295 dib7090_setHostBusMux(state, DIBTX_ON_HOSTBUS);
Olivier Grenie713d54a2011-01-04 04:54:31 -03002296 break;
2297 }
Olivier Grenie2e802862011-08-05 10:39:15 -03002298 if (mode != OUTMODE_HIGH_Z)
2299 outreg |= (1 << 10);
Olivier Grenie713d54a2011-01-04 04:54:31 -03002300
2301 if (state->cfg.output_mpeg2_in_188_bytes)
2302 smo_mode |= (1 << 5);
2303
2304 ret |= dib7000p_write_word(state, 235, smo_mode);
2305 ret |= dib7000p_write_word(state, 236, fifo_threshold); /* synchronous fread */
Olivier Grenie2e802862011-08-05 10:39:15 -03002306 ret |= dib7000p_write_word(state, 1286, outreg);
Olivier Grenie713d54a2011-01-04 04:54:31 -03002307
2308 return ret;
2309}
2310
2311int dib7090_tuner_sleep(struct dvb_frontend *fe, int onoff)
2312{
2313 struct dib7000p_state *state = fe->demodulator_priv;
2314 u16 en_cur_state;
2315
2316 dprintk("sleep dib7090: %d", onoff);
2317
2318 en_cur_state = dib7000p_read_word(state, 1922);
2319
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002320 if (en_cur_state > 0xff)
Olivier Grenie713d54a2011-01-04 04:54:31 -03002321 state->tuner_enable = en_cur_state;
Olivier Grenie713d54a2011-01-04 04:54:31 -03002322
2323 if (onoff)
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002324 en_cur_state &= 0x00ff;
Olivier Grenie713d54a2011-01-04 04:54:31 -03002325 else {
2326 if (state->tuner_enable != 0)
2327 en_cur_state = state->tuner_enable;
2328 }
2329
2330 dib7000p_write_word(state, 1922, en_cur_state);
2331
2332 return 0;
2333}
2334EXPORT_SYMBOL(dib7090_tuner_sleep);
2335
Olivier Grenie713d54a2011-01-04 04:54:31 -03002336int dib7090_get_adc_power(struct dvb_frontend *fe)
2337{
2338 return dib7000p_get_adc_power(fe);
2339}
2340EXPORT_SYMBOL(dib7090_get_adc_power);
2341
2342int dib7090_slave_reset(struct dvb_frontend *fe)
2343{
2344 struct dib7000p_state *state = fe->demodulator_priv;
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002345 u16 reg;
Olivier Grenie713d54a2011-01-04 04:54:31 -03002346
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002347 reg = dib7000p_read_word(state, 1794);
2348 dib7000p_write_word(state, 1794, reg | (4 << 12));
Olivier Grenie713d54a2011-01-04 04:54:31 -03002349
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002350 dib7000p_write_word(state, 1032, 0xffff);
2351 return 0;
Olivier Grenie713d54a2011-01-04 04:54:31 -03002352}
2353EXPORT_SYMBOL(dib7090_slave_reset);
2354
Patrick Boettchera75763f2006-10-18 08:34:16 -03002355static struct dvb_frontend_ops dib7000p_ops;
Olivier Grenie713d54a2011-01-04 04:54:31 -03002356struct dvb_frontend *dib7000p_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr, struct dib7000p_config *cfg)
Patrick Boettchera75763f2006-10-18 08:34:16 -03002357{
2358 struct dvb_frontend *demod;
2359 struct dib7000p_state *st;
2360 st = kzalloc(sizeof(struct dib7000p_state), GFP_KERNEL);
2361 if (st == NULL)
2362 return NULL;
2363
2364 memcpy(&st->cfg, cfg, sizeof(struct dib7000p_config));
2365 st->i2c_adap = i2c_adap;
2366 st->i2c_addr = i2c_addr;
2367 st->gpio_val = cfg->gpio_val;
2368 st->gpio_dir = cfg->gpio_dir;
2369
Steven Totha38d6e32008-04-22 15:37:01 -03002370 /* Ensure the output mode remains at the previous default if it's
2371 * not specifically set by the caller.
2372 */
Olivier Grenie713d54a2011-01-04 04:54:31 -03002373 if ((st->cfg.output_mode != OUTMODE_MPEG2_SERIAL) && (st->cfg.output_mode != OUTMODE_MPEG2_PAR_GATED_CLK))
Steven Totha38d6e32008-04-22 15:37:01 -03002374 st->cfg.output_mode = OUTMODE_MPEG2_FIFO;
2375
Olivier Grenie713d54a2011-01-04 04:54:31 -03002376 demod = &st->demod;
Patrick Boettchera75763f2006-10-18 08:34:16 -03002377 demod->demodulator_priv = st;
2378 memcpy(&st->demod.ops, &dib7000p_ops, sizeof(struct dvb_frontend_ops));
Patrick Boettcher79fcce32011-08-03 12:08:21 -03002379 mutex_init(&st->i2c_buffer_lock);
Patrick Boettchera75763f2006-10-18 08:34:16 -03002380
Olivier Grenie713d54a2011-01-04 04:54:31 -03002381 dib7000p_write_word(st, 1287, 0x0003); /* sram lead in, rdy */
Olivier Grenieeac1fe12009-09-23 13:41:27 -03002382
Patrick Boettchera75763f2006-10-18 08:34:16 -03002383 if (dib7000p_identify(st) != 0)
2384 goto error;
2385
Olivier Grenie713d54a2011-01-04 04:54:31 -03002386 st->version = dib7000p_read_word(st, 897);
2387
Martin Samek7646b9d2009-09-30 22:59:09 -03002388 /* FIXME: make sure the dev.parent field is initialized, or else
Patrick Boettcher79fcce32011-08-03 12:08:21 -03002389 request_firmware() will hit an OOPS (this should be moved somewhere
2390 more common) */
2391 st->i2c_master.gated_tuner_i2c_adap.dev.parent = i2c_adap->dev.parent;
Martin Samek7646b9d2009-09-30 22:59:09 -03002392
Devin Heitmueller85ec9d72009-07-20 00:45:25 -03002393 /* FIXME: make sure the dev.parent field is initialized, or else
2394 request_firmware() will hit an OOPS (this should be moved somewhere
2395 more common) */
2396 st->i2c_master.gated_tuner_i2c_adap.dev.parent = i2c_adap->dev.parent;
2397
Patrick Boettchera75763f2006-10-18 08:34:16 -03002398 dibx000_init_i2c_master(&st->i2c_master, DIB7000P, st->i2c_adap, st->i2c_addr);
2399
Olivier Grenie713d54a2011-01-04 04:54:31 -03002400 /* init 7090 tuner adapter */
2401 strncpy(st->dib7090_tuner_adap.name, "DiB7090 tuner interface", sizeof(st->dib7090_tuner_adap.name));
2402 st->dib7090_tuner_adap.algo = &dib7090_tuner_xfer_algo;
2403 st->dib7090_tuner_adap.algo_data = NULL;
2404 st->dib7090_tuner_adap.dev.parent = st->i2c_adap->dev.parent;
2405 i2c_set_adapdata(&st->dib7090_tuner_adap, st);
2406 i2c_add_adapter(&st->dib7090_tuner_adap);
2407
Patrick Boettchera75763f2006-10-18 08:34:16 -03002408 dib7000p_demod_reset(st);
2409
Olivier Grenie713d54a2011-01-04 04:54:31 -03002410 if (st->version == SOC7090) {
2411 dib7090_set_output_mode(demod, st->cfg.output_mode);
2412 dib7090_set_diversity_in(demod, 0);
2413 }
2414
Patrick Boettchera75763f2006-10-18 08:34:16 -03002415 return demod;
2416
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002417error:
Patrick Boettchera75763f2006-10-18 08:34:16 -03002418 kfree(st);
2419 return NULL;
2420}
2421EXPORT_SYMBOL(dib7000p_attach);
2422
2423static struct dvb_frontend_ops dib7000p_ops = {
2424 .info = {
Olivier Grenie713d54a2011-01-04 04:54:31 -03002425 .name = "DiBcom 7000PC",
2426 .type = FE_OFDM,
2427 .frequency_min = 44250000,
2428 .frequency_max = 867250000,
2429 .frequency_stepsize = 62500,
2430 .caps = FE_CAN_INVERSION_AUTO |
2431 FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
2432 FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
2433 FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO |
2434 FE_CAN_TRANSMISSION_MODE_AUTO | FE_CAN_GUARD_INTERVAL_AUTO | FE_CAN_RECOVER | FE_CAN_HIERARCHY_AUTO,
2435 },
Patrick Boettchera75763f2006-10-18 08:34:16 -03002436
Olivier Grenie713d54a2011-01-04 04:54:31 -03002437 .release = dib7000p_release,
Patrick Boettchera75763f2006-10-18 08:34:16 -03002438
Olivier Grenie713d54a2011-01-04 04:54:31 -03002439 .init = dib7000p_wakeup,
2440 .sleep = dib7000p_sleep,
Patrick Boettchera75763f2006-10-18 08:34:16 -03002441
Olivier Grenie713d54a2011-01-04 04:54:31 -03002442 .set_frontend = dib7000p_set_frontend,
2443 .get_tune_settings = dib7000p_fe_get_tune_settings,
2444 .get_frontend = dib7000p_get_frontend,
Patrick Boettchera75763f2006-10-18 08:34:16 -03002445
Olivier Grenie713d54a2011-01-04 04:54:31 -03002446 .read_status = dib7000p_read_status,
2447 .read_ber = dib7000p_read_ber,
Patrick Boettchera75763f2006-10-18 08:34:16 -03002448 .read_signal_strength = dib7000p_read_signal_strength,
Olivier Grenie713d54a2011-01-04 04:54:31 -03002449 .read_snr = dib7000p_read_snr,
2450 .read_ucblocks = dib7000p_read_unc_blocks,
Patrick Boettchera75763f2006-10-18 08:34:16 -03002451};
2452
Olivier Grenie713d54a2011-01-04 04:54:31 -03002453MODULE_AUTHOR("Olivier Grenie <ogrenie@dibcom.fr>");
Patrick Boettchera75763f2006-10-18 08:34:16 -03002454MODULE_AUTHOR("Patrick Boettcher <pboettcher@dibcom.fr>");
2455MODULE_DESCRIPTION("Driver for the DiBcom 7000PC COFDM demodulator");
2456MODULE_LICENSE("GPL");