blob: 4eb9c2b49cd566e3d835738dce705819370b3bec [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;
Patrick Boettchera75763f2006-10-18 08:34:16 -030073};
74
75enum dib7000p_power_mode {
76 DIB7000P_POWER_ALL = 0,
Patrick Boettcherb6884a12007-07-27 10:08:51 -030077 DIB7000P_POWER_ANALOG_ADC,
Patrick Boettchera75763f2006-10-18 08:34:16 -030078 DIB7000P_POWER_INTERFACE_ONLY,
79};
80
Olivier Grenie713d54a2011-01-04 04:54:31 -030081static int dib7090_set_output_mode(struct dvb_frontend *fe, int mode);
82static int dib7090_set_diversity_in(struct dvb_frontend *fe, int onoff);
83
Patrick Boettchera75763f2006-10-18 08:34:16 -030084static u16 dib7000p_read_word(struct dib7000p_state *state, u16 reg)
85{
Patrick Boettcher79fcce32011-08-03 12:08:21 -030086 u16 ret;
87
88 if (mutex_lock_interruptible(&state->i2c_buffer_lock) < 0) {
89 dprintk("could not acquire lock");
90 return 0;
91 }
92
Olivier Grenie5a0deee2011-05-03 12:27:33 -030093 state->i2c_write_buffer[0] = reg >> 8;
94 state->i2c_write_buffer[1] = reg & 0xff;
Patrick Boettchera75763f2006-10-18 08:34:16 -030095
Olivier Grenie5a0deee2011-05-03 12:27:33 -030096 memset(state->msg, 0, 2 * sizeof(struct i2c_msg));
97 state->msg[0].addr = state->i2c_addr >> 1;
98 state->msg[0].flags = 0;
99 state->msg[0].buf = state->i2c_write_buffer;
100 state->msg[0].len = 2;
101 state->msg[1].addr = state->i2c_addr >> 1;
102 state->msg[1].flags = I2C_M_RD;
103 state->msg[1].buf = state->i2c_read_buffer;
104 state->msg[1].len = 2;
105
106 if (i2c_transfer(state->i2c_adap, state->msg, 2) != 2)
Olivier Grenie713d54a2011-01-04 04:54:31 -0300107 dprintk("i2c read error on %d", reg);
Patrick Boettchera75763f2006-10-18 08:34:16 -0300108
Patrick Boettcher79fcce32011-08-03 12:08:21 -0300109 ret = (state->i2c_read_buffer[0] << 8) | state->i2c_read_buffer[1];
110 mutex_unlock(&state->i2c_buffer_lock);
111 return ret;
Patrick Boettchera75763f2006-10-18 08:34:16 -0300112}
113
114static int dib7000p_write_word(struct dib7000p_state *state, u16 reg, u16 val)
115{
Patrick Boettcher79fcce32011-08-03 12:08:21 -0300116 int ret;
117
118 if (mutex_lock_interruptible(&state->i2c_buffer_lock) < 0) {
119 dprintk("could not acquire lock");
120 return -EINVAL;
121 }
122
Olivier Grenie5a0deee2011-05-03 12:27:33 -0300123 state->i2c_write_buffer[0] = (reg >> 8) & 0xff;
124 state->i2c_write_buffer[1] = reg & 0xff;
125 state->i2c_write_buffer[2] = (val >> 8) & 0xff;
126 state->i2c_write_buffer[3] = val & 0xff;
127
128 memset(&state->msg[0], 0, sizeof(struct i2c_msg));
129 state->msg[0].addr = state->i2c_addr >> 1;
130 state->msg[0].flags = 0;
131 state->msg[0].buf = state->i2c_write_buffer;
132 state->msg[0].len = 4;
133
Patrick Boettcher79fcce32011-08-03 12:08:21 -0300134 ret = (i2c_transfer(state->i2c_adap, state->msg, 1) != 1 ?
135 -EREMOTEIO : 0);
136 mutex_unlock(&state->i2c_buffer_lock);
137 return ret;
Patrick Boettchera75763f2006-10-18 08:34:16 -0300138}
Olivier Grenie713d54a2011-01-04 04:54:31 -0300139
140static void dib7000p_write_tab(struct dib7000p_state *state, u16 * buf)
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300141{
142 u16 l = 0, r, *n;
143 n = buf;
144 l = *n++;
145 while (l) {
146 r = *n++;
147
148 do {
149 dib7000p_write_word(state, r, *n++);
150 r++;
151 } while (--l);
152 l = *n++;
153 }
154}
155
Patrick Boettchera75763f2006-10-18 08:34:16 -0300156static int dib7000p_set_output_mode(struct dib7000p_state *state, int mode)
157{
Olivier Grenie713d54a2011-01-04 04:54:31 -0300158 int ret = 0;
Patrick Boettchera75763f2006-10-18 08:34:16 -0300159 u16 outreg, fifo_threshold, smo_mode;
160
161 outreg = 0;
162 fifo_threshold = 1792;
Olivier Grenieeac1fe12009-09-23 13:41:27 -0300163 smo_mode = (dib7000p_read_word(state, 235) & 0x0050) | (1 << 1);
Patrick Boettchera75763f2006-10-18 08:34:16 -0300164
Olivier Grenie713d54a2011-01-04 04:54:31 -0300165 dprintk("setting output mode for demod %p to %d", &state->demod, mode);
Patrick Boettchera75763f2006-10-18 08:34:16 -0300166
167 switch (mode) {
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300168 case OUTMODE_MPEG2_PAR_GATED_CLK:
Olivier Grenie713d54a2011-01-04 04:54:31 -0300169 outreg = (1 << 10); /* 0x0400 */
170 break;
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300171 case OUTMODE_MPEG2_PAR_CONT_CLK:
Olivier Grenie713d54a2011-01-04 04:54:31 -0300172 outreg = (1 << 10) | (1 << 6); /* 0x0440 */
173 break;
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300174 case OUTMODE_MPEG2_SERIAL:
Olivier Grenie713d54a2011-01-04 04:54:31 -0300175 outreg = (1 << 10) | (2 << 6) | (0 << 1); /* 0x0480 */
176 break;
177 case OUTMODE_DIVERSITY:
178 if (state->cfg.hostbus_diversity)
179 outreg = (1 << 10) | (4 << 6); /* 0x0500 */
180 else
181 outreg = (1 << 11);
182 break;
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300183 case OUTMODE_MPEG2_FIFO:
Olivier Grenie713d54a2011-01-04 04:54:31 -0300184 smo_mode |= (3 << 1);
185 fifo_threshold = 512;
186 outreg = (1 << 10) | (5 << 6);
187 break;
188 case OUTMODE_ANALOG_ADC:
189 outreg = (1 << 10) | (3 << 6);
190 break;
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300191 case OUTMODE_HIGH_Z:
Olivier Grenie713d54a2011-01-04 04:54:31 -0300192 outreg = 0;
193 break;
194 default:
195 dprintk("Unhandled output_mode passed to be set for demod %p", &state->demod);
196 break;
Patrick Boettchera75763f2006-10-18 08:34:16 -0300197 }
198
199 if (state->cfg.output_mpeg2_in_188_bytes)
Olivier Grenie713d54a2011-01-04 04:54:31 -0300200 smo_mode |= (1 << 5);
Patrick Boettchera75763f2006-10-18 08:34:16 -0300201
Olivier Grenie713d54a2011-01-04 04:54:31 -0300202 ret |= dib7000p_write_word(state, 235, smo_mode);
203 ret |= dib7000p_write_word(state, 236, fifo_threshold); /* synchronous fread */
204 if (state->version != SOC7090)
205 ret |= dib7000p_write_word(state, 1286, outreg); /* P_Div_active */
Patrick Boettchera75763f2006-10-18 08:34:16 -0300206
207 return ret;
208}
209
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300210static int dib7000p_set_diversity_in(struct dvb_frontend *demod, int onoff)
211{
212 struct dib7000p_state *state = demod->demodulator_priv;
213
214 if (state->div_force_off) {
Olivier Grenie713d54a2011-01-04 04:54:31 -0300215 dprintk("diversity combination deactivated - forced by COFDM parameters");
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300216 onoff = 0;
Olivier Grenieeac1fe12009-09-23 13:41:27 -0300217 dib7000p_write_word(state, 207, 0);
218 } else
219 dib7000p_write_word(state, 207, (state->div_sync_wait << 4) | (1 << 2) | (2 << 0));
220
Olivier Grenie713d54a2011-01-04 04:54:31 -0300221 state->div_state = (u8) onoff;
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300222
223 if (onoff) {
224 dib7000p_write_word(state, 204, 6);
225 dib7000p_write_word(state, 205, 16);
226 /* P_dvsy_sync_mode = 0, P_dvsy_sync_enable=1, P_dvcb_comb_mode=2 */
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300227 } else {
228 dib7000p_write_word(state, 204, 1);
229 dib7000p_write_word(state, 205, 0);
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300230 }
231
232 return 0;
233}
234
Patrick Boettchera75763f2006-10-18 08:34:16 -0300235static int dib7000p_set_power_mode(struct dib7000p_state *state, enum dib7000p_power_mode mode)
236{
237 /* by default everything is powered off */
Olivier Grenie713d54a2011-01-04 04:54:31 -0300238 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 -0300239
240 /* now, depending on the requested mode, we power on */
241 switch (mode) {
242 /* power up everything in the demod */
Olivier Grenie713d54a2011-01-04 04:54:31 -0300243 case DIB7000P_POWER_ALL:
244 reg_774 = 0x0000;
245 reg_775 = 0x0000;
246 reg_776 = 0x0;
247 reg_899 = 0x0;
248 if (state->version == SOC7090)
249 reg_1280 &= 0x001f;
250 else
251 reg_1280 &= 0x01ff;
252 break;
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300253
Olivier Grenie713d54a2011-01-04 04:54:31 -0300254 case DIB7000P_POWER_ANALOG_ADC:
255 /* dem, cfg, iqc, sad, agc */
256 reg_774 &= ~((1 << 15) | (1 << 14) | (1 << 11) | (1 << 10) | (1 << 9));
257 /* nud */
258 reg_776 &= ~((1 << 0));
259 /* Dout */
260 if (state->version != SOC7090)
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300261 reg_1280 &= ~((1 << 11));
Olivier Grenie713d54a2011-01-04 04:54:31 -0300262 reg_1280 &= ~(1 << 6);
263 /* fall through wanted to enable the interfaces */
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300264
Patrick Boettchera75763f2006-10-18 08:34:16 -0300265 /* just leave power on the control-interfaces: GPIO and (I2C or SDIO) */
Olivier Grenie713d54a2011-01-04 04:54:31 -0300266 case DIB7000P_POWER_INTERFACE_ONLY: /* TODO power up either SDIO or I2C */
267 if (state->version == SOC7090)
268 reg_1280 &= ~((1 << 7) | (1 << 5));
269 else
Patrick Boettchera75763f2006-10-18 08:34:16 -0300270 reg_1280 &= ~((1 << 14) | (1 << 13) | (1 << 12) | (1 << 10));
Olivier Grenie713d54a2011-01-04 04:54:31 -0300271 break;
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300272
Patrick Boettchera75763f2006-10-18 08:34:16 -0300273/* TODO following stuff is just converted from the dib7000-driver - check when is used what */
274 }
275
Olivier Grenie713d54a2011-01-04 04:54:31 -0300276 dib7000p_write_word(state, 774, reg_774);
277 dib7000p_write_word(state, 775, reg_775);
278 dib7000p_write_word(state, 776, reg_776);
279 dib7000p_write_word(state, 899, reg_899);
Patrick Boettchera75763f2006-10-18 08:34:16 -0300280 dib7000p_write_word(state, 1280, reg_1280);
281
282 return 0;
283}
284
285static void dib7000p_set_adc_state(struct dib7000p_state *state, enum dibx000_adc_states no)
286{
Olivier Grenie713d54a2011-01-04 04:54:31 -0300287 u16 reg_908 = dib7000p_read_word(state, 908), reg_909 = dib7000p_read_word(state, 909);
288 u16 reg;
Patrick Boettchera75763f2006-10-18 08:34:16 -0300289
290 switch (no) {
Olivier Grenie713d54a2011-01-04 04:54:31 -0300291 case DIBX000_SLOW_ADC_ON:
292 if (state->version == SOC7090) {
293 reg = dib7000p_read_word(state, 1925);
294
295 dib7000p_write_word(state, 1925, reg | (1 << 4) | (1 << 2)); /* en_slowAdc = 1 & reset_sladc = 1 */
296
297 reg = dib7000p_read_word(state, 1925); /* read acces to make it works... strange ... */
298 msleep(200);
299 dib7000p_write_word(state, 1925, reg & ~(1 << 4)); /* en_slowAdc = 1 & reset_sladc = 0 */
300
301 reg = dib7000p_read_word(state, 72) & ~((0x3 << 14) | (0x3 << 12));
302 dib7000p_write_word(state, 72, reg | (1 << 14) | (3 << 12) | 524); /* ref = Vin1 => Vbg ; sel = Vin0 or Vin3 ; (Vin2 = Vcm) */
303 } else {
Patrick Boettchera75763f2006-10-18 08:34:16 -0300304 reg_909 |= (1 << 1) | (1 << 0);
305 dib7000p_write_word(state, 909, reg_909);
306 reg_909 &= ~(1 << 1);
Olivier Grenie713d54a2011-01-04 04:54:31 -0300307 }
308 break;
Patrick Boettchera75763f2006-10-18 08:34:16 -0300309
Olivier Grenie713d54a2011-01-04 04:54:31 -0300310 case DIBX000_SLOW_ADC_OFF:
311 if (state->version == SOC7090) {
312 reg = dib7000p_read_word(state, 1925);
313 dib7000p_write_word(state, 1925, (reg & ~(1 << 2)) | (1 << 4)); /* reset_sladc = 1 en_slowAdc = 0 */
314 } else
315 reg_909 |= (1 << 1) | (1 << 0);
316 break;
Patrick Boettchera75763f2006-10-18 08:34:16 -0300317
Olivier Grenie713d54a2011-01-04 04:54:31 -0300318 case DIBX000_ADC_ON:
319 reg_908 &= 0x0fff;
320 reg_909 &= 0x0003;
321 break;
Patrick Boettchera75763f2006-10-18 08:34:16 -0300322
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300323 case DIBX000_ADC_OFF:
Olivier Grenie713d54a2011-01-04 04:54:31 -0300324 reg_908 |= (1 << 14) | (1 << 13) | (1 << 12);
325 reg_909 |= (1 << 5) | (1 << 4) | (1 << 3) | (1 << 2);
326 break;
Patrick Boettchera75763f2006-10-18 08:34:16 -0300327
Olivier Grenie713d54a2011-01-04 04:54:31 -0300328 case DIBX000_VBG_ENABLE:
329 reg_908 &= ~(1 << 15);
330 break;
Patrick Boettchera75763f2006-10-18 08:34:16 -0300331
Olivier Grenie713d54a2011-01-04 04:54:31 -0300332 case DIBX000_VBG_DISABLE:
333 reg_908 |= (1 << 15);
334 break;
Patrick Boettchera75763f2006-10-18 08:34:16 -0300335
Olivier Grenie713d54a2011-01-04 04:54:31 -0300336 default:
337 break;
Patrick Boettchera75763f2006-10-18 08:34:16 -0300338 }
339
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300340// dprintk( "908: %x, 909: %x\n", reg_908, reg_909);
Patrick Boettchera75763f2006-10-18 08:34:16 -0300341
Olivier Grenie970d14c2010-09-07 12:50:46 -0300342 reg_909 |= (state->cfg.disable_sample_and_hold & 1) << 4;
Olivier Grenie90e12ce2010-09-07 12:50:45 -0300343 reg_908 |= (state->cfg.enable_current_mirror & 1) << 7;
344
Patrick Boettchera75763f2006-10-18 08:34:16 -0300345 dib7000p_write_word(state, 908, reg_908);
346 dib7000p_write_word(state, 909, reg_909);
347}
348
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300349static int dib7000p_set_bandwidth(struct dib7000p_state *state, u32 bw)
Patrick Boettchera75763f2006-10-18 08:34:16 -0300350{
Patrick Boettchera75763f2006-10-18 08:34:16 -0300351 u32 timf;
352
353 // store the current bandwidth for later use
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300354 state->current_bandwidth = bw;
Patrick Boettchera75763f2006-10-18 08:34:16 -0300355
356 if (state->timf == 0) {
Olivier Grenie713d54a2011-01-04 04:54:31 -0300357 dprintk("using default timf");
Patrick Boettchera75763f2006-10-18 08:34:16 -0300358 timf = state->cfg.bw->timf;
359 } else {
Olivier Grenie713d54a2011-01-04 04:54:31 -0300360 dprintk("using updated timf");
Patrick Boettchera75763f2006-10-18 08:34:16 -0300361 timf = state->timf;
362 }
363
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300364 timf = timf * (bw / 50) / 160;
Patrick Boettchera75763f2006-10-18 08:34:16 -0300365
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300366 dib7000p_write_word(state, 23, (u16) ((timf >> 16) & 0xffff));
Olivier Grenie713d54a2011-01-04 04:54:31 -0300367 dib7000p_write_word(state, 24, (u16) ((timf) & 0xffff));
Patrick Boettchera75763f2006-10-18 08:34:16 -0300368
369 return 0;
370}
371
372static int dib7000p_sad_calib(struct dib7000p_state *state)
373{
374/* internal */
Patrick Boettchera75763f2006-10-18 08:34:16 -0300375 dib7000p_write_word(state, 73, (0 << 1) | (0 << 0));
Olivier Grenie713d54a2011-01-04 04:54:31 -0300376
377 if (state->version == SOC7090)
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300378 dib7000p_write_word(state, 74, 2048);
Olivier Grenie713d54a2011-01-04 04:54:31 -0300379 else
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300380 dib7000p_write_word(state, 74, 776);
Patrick Boettchera75763f2006-10-18 08:34:16 -0300381
382 /* do the calibration */
383 dib7000p_write_word(state, 73, (1 << 0));
384 dib7000p_write_word(state, 73, (0 << 0));
385
386 msleep(1);
387
388 return 0;
389}
390
Patrick Boettcher01373a52007-07-30 12:49:04 -0300391int dib7000p_set_wbd_ref(struct dvb_frontend *demod, u16 value)
392{
393 struct dib7000p_state *state = demod->demodulator_priv;
394 if (value > 4095)
395 value = 4095;
396 state->wbd_ref = value;
397 return dib7000p_write_word(state, 105, (dib7000p_read_word(state, 105) & 0xf000) | value);
398}
Patrick Boettcher01373a52007-07-30 12:49:04 -0300399EXPORT_SYMBOL(dib7000p_set_wbd_ref);
Olivier Grenie713d54a2011-01-04 04:54:31 -0300400
Patrick Boettchera75763f2006-10-18 08:34:16 -0300401static void dib7000p_reset_pll(struct dib7000p_state *state)
402{
403 struct dibx000_bandwidth_config *bw = &state->cfg.bw[0];
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300404 u16 clk_cfg0;
Patrick Boettchera75763f2006-10-18 08:34:16 -0300405
Olivier Grenie713d54a2011-01-04 04:54:31 -0300406 if (state->version == SOC7090) {
407 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 -0300408
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300409 while (((dib7000p_read_word(state, 1856) >> 15) & 0x1) != 1)
410 ;
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300411
Olivier Grenie713d54a2011-01-04 04:54:31 -0300412 dib7000p_write_word(state, 1857, dib7000p_read_word(state, 1857) | (!bw->pll_bypass << 15));
413 } else {
414 /* force PLL bypass */
415 clk_cfg0 = (1 << 15) | ((bw->pll_ratio & 0x3f) << 9) |
416 (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 -0300417
Olivier Grenie713d54a2011-01-04 04:54:31 -0300418 dib7000p_write_word(state, 900, clk_cfg0);
419
420 /* P_pll_cfg */
421 dib7000p_write_word(state, 903, (bw->pll_prediv << 5) | (((bw->pll_ratio >> 6) & 0x3) << 3) | (bw->pll_range << 1) | bw->pll_reset);
422 clk_cfg0 = (bw->pll_bypass << 15) | (clk_cfg0 & 0x7fff);
423 dib7000p_write_word(state, 900, clk_cfg0);
424 }
425
426 dib7000p_write_word(state, 18, (u16) (((bw->internal * 1000) >> 16) & 0xffff));
427 dib7000p_write_word(state, 19, (u16) ((bw->internal * 1000) & 0xffff));
428 dib7000p_write_word(state, 21, (u16) ((bw->ifreq >> 16) & 0xffff));
429 dib7000p_write_word(state, 22, (u16) ((bw->ifreq) & 0xffff));
Patrick Boettchera75763f2006-10-18 08:34:16 -0300430
431 dib7000p_write_word(state, 72, bw->sad_cfg);
432}
433
Olivier Grenie713d54a2011-01-04 04:54:31 -0300434static u32 dib7000p_get_internal_freq(struct dib7000p_state *state)
435{
436 u32 internal = (u32) dib7000p_read_word(state, 18) << 16;
437 internal |= (u32) dib7000p_read_word(state, 19);
438 internal /= 1000;
439
440 return internal;
441}
442
443int dib7000p_update_pll(struct dvb_frontend *fe, struct dibx000_bandwidth_config *bw)
444{
445 struct dib7000p_state *state = fe->demodulator_priv;
446 u16 reg_1857, reg_1856 = dib7000p_read_word(state, 1856);
447 u8 loopdiv, prediv;
448 u32 internal, xtal;
449
450 /* get back old values */
451 prediv = reg_1856 & 0x3f;
452 loopdiv = (reg_1856 >> 6) & 0x3f;
453
454 if ((bw != NULL) && (bw->pll_prediv != prediv || bw->pll_ratio != loopdiv)) {
455 dprintk("Updating pll (prediv: old = %d new = %d ; loopdiv : old = %d new = %d)", prediv, bw->pll_prediv, loopdiv, bw->pll_ratio);
456 reg_1856 &= 0xf000;
457 reg_1857 = dib7000p_read_word(state, 1857);
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300458 dib7000p_write_word(state, 1857, reg_1857 & ~(1 << 15));
Olivier Grenie713d54a2011-01-04 04:54:31 -0300459
460 dib7000p_write_word(state, 1856, reg_1856 | ((bw->pll_ratio & 0x3f) << 6) | (bw->pll_prediv & 0x3f));
461
462 /* write new system clk into P_sec_len */
463 internal = dib7000p_get_internal_freq(state);
464 xtal = (internal / loopdiv) * prediv;
465 internal = 1000 * (xtal / bw->pll_prediv) * bw->pll_ratio; /* new internal */
466 dib7000p_write_word(state, 18, (u16) ((internal >> 16) & 0xffff));
467 dib7000p_write_word(state, 19, (u16) (internal & 0xffff));
468
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300469 dib7000p_write_word(state, 1857, reg_1857 | (1 << 15));
Olivier Grenie713d54a2011-01-04 04:54:31 -0300470
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300471 while (((dib7000p_read_word(state, 1856) >> 15) & 0x1) != 1)
Olivier Grenie713d54a2011-01-04 04:54:31 -0300472 dprintk("Waiting for PLL to lock");
Olivier Grenie713d54a2011-01-04 04:54:31 -0300473
474 return 0;
475 }
476 return -EIO;
477}
478EXPORT_SYMBOL(dib7000p_update_pll);
479
Patrick Boettchera75763f2006-10-18 08:34:16 -0300480static int dib7000p_reset_gpio(struct dib7000p_state *st)
481{
482 /* reset the GPIOs */
Olivier Grenie713d54a2011-01-04 04:54:31 -0300483 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 -0300484
485 dib7000p_write_word(st, 1029, st->gpio_dir);
486 dib7000p_write_word(st, 1030, st->gpio_val);
487
488 /* TODO 1031 is P_gpio_od */
489
490 dib7000p_write_word(st, 1032, st->cfg.gpio_pwm_pos);
491
492 dib7000p_write_word(st, 1037, st->cfg.pwm_freq_div);
493 return 0;
494}
495
Patrick Boettcher01373a52007-07-30 12:49:04 -0300496static int dib7000p_cfg_gpio(struct dib7000p_state *st, u8 num, u8 dir, u8 val)
497{
498 st->gpio_dir = dib7000p_read_word(st, 1029);
Olivier Grenie713d54a2011-01-04 04:54:31 -0300499 st->gpio_dir &= ~(1 << num); /* reset the direction bit */
500 st->gpio_dir |= (dir & 0x1) << num; /* set the new direction */
Patrick Boettcher01373a52007-07-30 12:49:04 -0300501 dib7000p_write_word(st, 1029, st->gpio_dir);
502
503 st->gpio_val = dib7000p_read_word(st, 1030);
Olivier Grenie713d54a2011-01-04 04:54:31 -0300504 st->gpio_val &= ~(1 << num); /* reset the direction bit */
505 st->gpio_val |= (val & 0x01) << num; /* set the new value */
Patrick Boettcher01373a52007-07-30 12:49:04 -0300506 dib7000p_write_word(st, 1030, st->gpio_val);
507
508 return 0;
509}
510
511int dib7000p_set_gpio(struct dvb_frontend *demod, u8 num, u8 dir, u8 val)
512{
513 struct dib7000p_state *state = demod->demodulator_priv;
514 return dib7000p_cfg_gpio(state, num, dir, val);
515}
Patrick Boettcher01373a52007-07-30 12:49:04 -0300516EXPORT_SYMBOL(dib7000p_set_gpio);
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300517
Olivier Grenie713d54a2011-01-04 04:54:31 -0300518static u16 dib7000p_defaults[] = {
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300519 // auto search configuration
520 3, 2,
Olivier Grenie713d54a2011-01-04 04:54:31 -0300521 0x0004,
522 0x1000,
523 0x0814, /* Equal Lock */
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300524
525 12, 6,
Olivier Grenie713d54a2011-01-04 04:54:31 -0300526 0x001b,
527 0x7740,
528 0x005b,
529 0x8d80,
530 0x01c9,
531 0xc380,
532 0x0000,
533 0x0080,
534 0x0000,
535 0x0090,
536 0x0001,
537 0xd4c0,
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300538
539 1, 26,
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300540 0x6680,
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300541
542 /* set ADC level to -16 */
543 11, 79,
Olivier Grenie713d54a2011-01-04 04:54:31 -0300544 (1 << 13) - 825 - 117,
545 (1 << 13) - 837 - 117,
546 (1 << 13) - 811 - 117,
547 (1 << 13) - 766 - 117,
548 (1 << 13) - 737 - 117,
549 (1 << 13) - 693 - 117,
550 (1 << 13) - 648 - 117,
551 (1 << 13) - 619 - 117,
552 (1 << 13) - 575 - 117,
553 (1 << 13) - 531 - 117,
554 (1 << 13) - 501 - 117,
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300555
556 1, 142,
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300557 0x0410,
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300558
559 /* disable power smoothing */
560 8, 145,
Olivier Grenie713d54a2011-01-04 04:54:31 -0300561 0,
562 0,
563 0,
564 0,
565 0,
566 0,
567 0,
568 0,
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300569
570 1, 154,
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300571 1 << 13,
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300572
573 1, 168,
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300574 0x0ccd,
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300575
576 1, 183,
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300577 0x200f,
Olivier Grenie713d54a2011-01-04 04:54:31 -0300578
579 1, 212,
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300580 0x169,
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300581
582 5, 187,
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300583 0x023d,
584 0x00a4,
585 0x00a4,
586 0x7ff0,
587 0x3ccc,
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300588
589 1, 198,
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300590 0x800,
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300591
592 1, 222,
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300593 0x0010,
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300594
595 1, 235,
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300596 0x0062,
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300597
598 2, 901,
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300599 0x0006,
600 (3 << 10) | (1 << 6),
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300601
602 1, 905,
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300603 0x2c8e,
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300604
605 0,
606};
607
Patrick Boettchera75763f2006-10-18 08:34:16 -0300608static int dib7000p_demod_reset(struct dib7000p_state *state)
609{
610 dib7000p_set_power_mode(state, DIB7000P_POWER_ALL);
611
Olivier Grenie713d54a2011-01-04 04:54:31 -0300612 if (state->version == SOC7090)
613 dibx000_reset_i2c_master(&state->i2c_master);
614
Patrick Boettchera75763f2006-10-18 08:34:16 -0300615 dib7000p_set_adc_state(state, DIBX000_VBG_ENABLE);
616
617 /* restart all parts */
Olivier Grenie713d54a2011-01-04 04:54:31 -0300618 dib7000p_write_word(state, 770, 0xffff);
619 dib7000p_write_word(state, 771, 0xffff);
620 dib7000p_write_word(state, 772, 0x001f);
621 dib7000p_write_word(state, 898, 0x0003);
622 dib7000p_write_word(state, 1280, 0x001f - ((1 << 4) | (1 << 3)));
Patrick Boettchera75763f2006-10-18 08:34:16 -0300623
Olivier Grenie713d54a2011-01-04 04:54:31 -0300624 dib7000p_write_word(state, 770, 0);
625 dib7000p_write_word(state, 771, 0);
626 dib7000p_write_word(state, 772, 0);
627 dib7000p_write_word(state, 898, 0);
Patrick Boettchera75763f2006-10-18 08:34:16 -0300628 dib7000p_write_word(state, 1280, 0);
629
630 /* default */
631 dib7000p_reset_pll(state);
632
633 if (dib7000p_reset_gpio(state) != 0)
Olivier Grenie713d54a2011-01-04 04:54:31 -0300634 dprintk("GPIO reset was not successful.");
Patrick Boettchera75763f2006-10-18 08:34:16 -0300635
Olivier Grenie713d54a2011-01-04 04:54:31 -0300636 if (state->version == SOC7090) {
637 dib7000p_write_word(state, 899, 0);
638
639 /* impulse noise */
640 dib7000p_write_word(state, 42, (1<<5) | 3); /* P_iqc_thsat_ipc = 1 ; P_iqc_win2 = 3 */
641 dib7000p_write_word(state, 43, 0x2d4); /*-300 fag P_iqc_dect_min = -280 */
642 dib7000p_write_word(state, 44, 300); /* 300 fag P_iqc_dect_min = +280 */
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300643 dib7000p_write_word(state, 273, (1<<6) | 30);
Olivier Grenie713d54a2011-01-04 04:54:31 -0300644 }
Patrick Boettchera75763f2006-10-18 08:34:16 -0300645 if (dib7000p_set_output_mode(state, OUTMODE_HIGH_Z) != 0)
Olivier Grenie713d54a2011-01-04 04:54:31 -0300646 dprintk("OUTPUT_MODE could not be reset.");
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300647
648 dib7000p_set_adc_state(state, DIBX000_SLOW_ADC_ON);
649 dib7000p_sad_calib(state);
650 dib7000p_set_adc_state(state, DIBX000_SLOW_ADC_OFF);
651
Olivier Grenie713d54a2011-01-04 04:54:31 -0300652 /* unforce divstr regardless whether i2c enumeration was done or not */
653 dib7000p_write_word(state, 1285, dib7000p_read_word(state, 1285) & ~(1 << 1));
654
655 dib7000p_set_bandwidth(state, 8000);
656
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300657 if (state->version == SOC7090) {
Olivier Grenie713d54a2011-01-04 04:54:31 -0300658 dib7000p_write_word(state, 36, 0x5755);/* P_iqc_impnc_on =1 & P_iqc_corr_inh = 1 for impulsive noise */
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300659 } else {
Olivier Grenie713d54a2011-01-04 04:54:31 -0300660 if (state->cfg.tuner_is_baseband)
661 dib7000p_write_word(state, 36, 0x0755);
662 else
663 dib7000p_write_word(state, 36, 0x1f55);
664 }
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300665
666 dib7000p_write_tab(state, dib7000p_defaults);
667
Patrick Boettchera75763f2006-10-18 08:34:16 -0300668 dib7000p_set_power_mode(state, DIB7000P_POWER_INTERFACE_ONLY);
669
670 return 0;
671}
672
Patrick Boettchera75763f2006-10-18 08:34:16 -0300673static void dib7000p_pll_clk_cfg(struct dib7000p_state *state)
674{
675 u16 tmp = 0;
676 tmp = dib7000p_read_word(state, 903);
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300677 dib7000p_write_word(state, 903, (tmp | 0x1));
Patrick Boettchera75763f2006-10-18 08:34:16 -0300678 tmp = dib7000p_read_word(state, 900);
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300679 dib7000p_write_word(state, 900, (tmp & 0x7fff) | (1 << 6));
Patrick Boettchera75763f2006-10-18 08:34:16 -0300680}
681
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300682static void dib7000p_restart_agc(struct dib7000p_state *state)
Patrick Boettchera75763f2006-10-18 08:34:16 -0300683{
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300684 // P_restart_iqc & P_restart_agc
685 dib7000p_write_word(state, 770, (1 << 11) | (1 << 9));
686 dib7000p_write_word(state, 770, 0x0000);
Patrick Boettchera75763f2006-10-18 08:34:16 -0300687}
688
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300689static int dib7000p_update_lna(struct dib7000p_state *state)
Patrick Boettchera75763f2006-10-18 08:34:16 -0300690{
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300691 u16 dyn_gain;
692
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300693 if (state->cfg.update_lna) {
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300694 dyn_gain = dib7000p_read_word(state, 394);
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300695 if (state->cfg.update_lna(&state->demod, dyn_gain)) {
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300696 dib7000p_restart_agc(state);
697 return 1;
698 }
699 }
700
701 return 0;
702}
703
704static int dib7000p_set_agc_config(struct dib7000p_state *state, u8 band)
705{
706 struct dibx000_agc_config *agc = NULL;
707 int i;
708 if (state->current_band == band && state->current_agc != NULL)
709 return 0;
710 state->current_band = band;
711
712 for (i = 0; i < state->cfg.agc_config_count; i++)
713 if (state->cfg.agc[i].band_caps & band) {
714 agc = &state->cfg.agc[i];
715 break;
716 }
717
718 if (agc == NULL) {
Olivier Grenie713d54a2011-01-04 04:54:31 -0300719 dprintk("no valid AGC configuration found for band 0x%02x", band);
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300720 return -EINVAL;
721 }
722
723 state->current_agc = agc;
724
725 /* AGC */
Olivier Grenie713d54a2011-01-04 04:54:31 -0300726 dib7000p_write_word(state, 75, agc->setup);
727 dib7000p_write_word(state, 76, agc->inv_gain);
728 dib7000p_write_word(state, 77, agc->time_stabiliz);
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300729 dib7000p_write_word(state, 100, (agc->alpha_level << 12) | agc->thlock);
730
731 // Demod AGC loop configuration
732 dib7000p_write_word(state, 101, (agc->alpha_mant << 5) | agc->alpha_exp);
Olivier Grenie713d54a2011-01-04 04:54:31 -0300733 dib7000p_write_word(state, 102, (agc->beta_mant << 6) | agc->beta_exp);
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300734
735 /* AGC continued */
Olivier Grenie713d54a2011-01-04 04:54:31 -0300736 dprintk("WBD: ref: %d, sel: %d, active: %d, alpha: %d",
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300737 state->wbd_ref != 0 ? state->wbd_ref : agc->wbd_ref, agc->wbd_sel, !agc->perform_agc_softsplit, agc->wbd_sel);
738
739 if (state->wbd_ref != 0)
740 dib7000p_write_word(state, 105, (agc->wbd_inv << 12) | state->wbd_ref);
741 else
742 dib7000p_write_word(state, 105, (agc->wbd_inv << 12) | agc->wbd_ref);
743
744 dib7000p_write_word(state, 106, (agc->wbd_sel << 13) | (agc->wbd_alpha << 9) | (agc->perform_agc_softsplit << 8));
745
Olivier Grenie713d54a2011-01-04 04:54:31 -0300746 dib7000p_write_word(state, 107, agc->agc1_max);
747 dib7000p_write_word(state, 108, agc->agc1_min);
748 dib7000p_write_word(state, 109, agc->agc2_max);
749 dib7000p_write_word(state, 110, agc->agc2_min);
750 dib7000p_write_word(state, 111, (agc->agc1_pt1 << 8) | agc->agc1_pt2);
751 dib7000p_write_word(state, 112, agc->agc1_pt3);
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300752 dib7000p_write_word(state, 113, (agc->agc1_slope1 << 8) | agc->agc1_slope2);
Olivier Grenie713d54a2011-01-04 04:54:31 -0300753 dib7000p_write_word(state, 114, (agc->agc2_pt1 << 8) | agc->agc2_pt2);
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300754 dib7000p_write_word(state, 115, (agc->agc2_slope1 << 8) | agc->agc2_slope2);
755 return 0;
756}
757
Olivier Grenie713d54a2011-01-04 04:54:31 -0300758static void dib7000p_set_dds(struct dib7000p_state *state, s32 offset_khz)
759{
760 u32 internal = dib7000p_get_internal_freq(state);
761 s32 unit_khz_dds_val = 67108864 / (internal); /* 2**26 / Fsampling is the unit 1KHz offset */
762 u32 abs_offset_khz = ABS(offset_khz);
763 u32 dds = state->cfg.bw->ifreq & 0x1ffffff;
764 u8 invert = !!(state->cfg.bw->ifreq & (1 << 25));
765
766 dprintk("setting a frequency offset of %dkHz internal freq = %d invert = %d", offset_khz, internal, invert);
767
768 if (offset_khz < 0)
769 unit_khz_dds_val *= -1;
770
771 /* IF tuner */
772 if (invert)
773 dds -= (abs_offset_khz * unit_khz_dds_val); /* /100 because of /100 on the unit_khz_dds_val line calc for better accuracy */
774 else
775 dds += (abs_offset_khz * unit_khz_dds_val);
776
777 if (abs_offset_khz <= (internal / 2)) { /* Max dds offset is the half of the demod freq */
778 dib7000p_write_word(state, 21, (u16) (((dds >> 16) & 0x1ff) | (0 << 10) | (invert << 9)));
779 dib7000p_write_word(state, 22, (u16) (dds & 0xffff));
780 }
781}
782
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300783static int dib7000p_agc_startup(struct dvb_frontend *demod, struct dvb_frontend_parameters *ch)
784{
785 struct dib7000p_state *state = demod->demodulator_priv;
786 int ret = -1;
787 u8 *agc_state = &state->agc_state;
788 u8 agc_split;
Olivier Grenie713d54a2011-01-04 04:54:31 -0300789 u16 reg;
790 u32 upd_demod_gain_period = 0x1000;
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300791
792 switch (state->agc_state) {
Olivier Grenie713d54a2011-01-04 04:54:31 -0300793 case 0:
Olivier Grenie713d54a2011-01-04 04:54:31 -0300794 dib7000p_set_power_mode(state, DIB7000P_POWER_ALL);
795 if (state->version == SOC7090) {
796 reg = dib7000p_read_word(state, 0x79b) & 0xff00;
797 dib7000p_write_word(state, 0x79a, upd_demod_gain_period & 0xFFFF); /* lsb */
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300798 dib7000p_write_word(state, 0x79b, reg | (1 << 14) | ((upd_demod_gain_period >> 16) & 0xFF));
Olivier Grenie713d54a2011-01-04 04:54:31 -0300799
800 /* enable adc i & q */
801 reg = dib7000p_read_word(state, 0x780);
802 dib7000p_write_word(state, 0x780, (reg | (0x3)) & (~(1 << 7)));
803 } else {
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300804 dib7000p_set_adc_state(state, DIBX000_ADC_ON);
805 dib7000p_pll_clk_cfg(state);
Olivier Grenie713d54a2011-01-04 04:54:31 -0300806 }
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300807
Olivier Grenie713d54a2011-01-04 04:54:31 -0300808 if (dib7000p_set_agc_config(state, BAND_OF_FREQUENCY(ch->frequency / 1000)) != 0)
809 return -1;
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300810
Olivier Grenie713d54a2011-01-04 04:54:31 -0300811 dib7000p_set_dds(state, 0);
812 ret = 7;
813 (*agc_state)++;
814 break;
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300815
Olivier Grenie713d54a2011-01-04 04:54:31 -0300816 case 1:
Olivier Grenie713d54a2011-01-04 04:54:31 -0300817 if (state->cfg.agc_control)
818 state->cfg.agc_control(&state->demod, 1);
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300819
Olivier Grenie713d54a2011-01-04 04:54:31 -0300820 dib7000p_write_word(state, 78, 32768);
821 if (!state->current_agc->perform_agc_softsplit) {
822 /* we are using the wbd - so slow AGC startup */
823 /* force 0 split on WBD and restart AGC */
824 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 -0300825 (*agc_state)++;
826 ret = 5;
Olivier Grenie713d54a2011-01-04 04:54:31 -0300827 } else {
828 /* default AGC startup */
829 (*agc_state) = 4;
830 /* wait AGC rough lock time */
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300831 ret = 7;
Olivier Grenie713d54a2011-01-04 04:54:31 -0300832 }
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300833
Olivier Grenie713d54a2011-01-04 04:54:31 -0300834 dib7000p_restart_agc(state);
835 break;
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300836
Olivier Grenie713d54a2011-01-04 04:54:31 -0300837 case 2: /* fast split search path after 5sec */
838 dib7000p_write_word(state, 75, state->current_agc->setup | (1 << 4)); /* freeze AGC loop */
839 dib7000p_write_word(state, 106, (state->current_agc->wbd_sel << 13) | (2 << 9) | (0 << 8)); /* fast split search 0.25kHz */
840 (*agc_state)++;
841 ret = 14;
842 break;
843
844 case 3: /* split search ended */
845 agc_split = (u8) dib7000p_read_word(state, 396); /* store the split value for the next time */
846 dib7000p_write_word(state, 78, dib7000p_read_word(state, 394)); /* set AGC gain start value */
847
848 dib7000p_write_word(state, 75, state->current_agc->setup); /* std AGC loop */
849 dib7000p_write_word(state, 106, (state->current_agc->wbd_sel << 13) | (state->current_agc->wbd_alpha << 9) | agc_split); /* standard split search */
850
851 dib7000p_restart_agc(state);
852
853 dprintk("SPLIT %p: %hd", demod, agc_split);
854
855 (*agc_state)++;
856 ret = 5;
857 break;
858
859 case 4: /* LNA startup */
Olivier Grenie713d54a2011-01-04 04:54:31 -0300860 ret = 7;
861
862 if (dib7000p_update_lna(state))
Olivier Grenie713d54a2011-01-04 04:54:31 -0300863 ret = 5;
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300864 else
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300865 (*agc_state)++;
Olivier Grenie713d54a2011-01-04 04:54:31 -0300866 break;
867
868 case 5:
869 if (state->cfg.agc_control)
870 state->cfg.agc_control(&state->demod, 0);
871 (*agc_state)++;
872 break;
873 default:
874 break;
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300875 }
876 return ret;
877}
878
879static void dib7000p_update_timf(struct dib7000p_state *state)
880{
881 u32 timf = (dib7000p_read_word(state, 427) << 16) | dib7000p_read_word(state, 428);
882 state->timf = timf * 160 / (state->current_bandwidth / 50);
883 dib7000p_write_word(state, 23, (u16) (timf >> 16));
884 dib7000p_write_word(state, 24, (u16) (timf & 0xffff));
Olivier Grenie713d54a2011-01-04 04:54:31 -0300885 dprintk("updated timf_frequency: %d (default: %d)", state->timf, state->cfg.bw->timf);
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300886
887}
888
Olivier Grenie713d54a2011-01-04 04:54:31 -0300889u32 dib7000p_ctrl_timf(struct dvb_frontend *fe, u8 op, u32 timf)
890{
891 struct dib7000p_state *state = fe->demodulator_priv;
892 switch (op) {
893 case DEMOD_TIMF_SET:
894 state->timf = timf;
895 break;
896 case DEMOD_TIMF_UPDATE:
897 dib7000p_update_timf(state);
898 break;
899 case DEMOD_TIMF_GET:
900 break;
901 }
902 dib7000p_set_bandwidth(state, state->current_bandwidth);
903 return state->timf;
904}
905EXPORT_SYMBOL(dib7000p_ctrl_timf);
906
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300907static void dib7000p_set_channel(struct dib7000p_state *state, struct dvb_frontend_parameters *ch, u8 seq)
908{
909 u16 value, est[4];
910
Olivier Grenie713d54a2011-01-04 04:54:31 -0300911 dib7000p_set_bandwidth(state, BANDWIDTH_TO_KHZ(ch->u.ofdm.bandwidth));
Patrick Boettchera75763f2006-10-18 08:34:16 -0300912
913 /* nfft, guard, qam, alpha */
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300914 value = 0;
915 switch (ch->u.ofdm.transmission_mode) {
Olivier Grenie713d54a2011-01-04 04:54:31 -0300916 case TRANSMISSION_MODE_2K:
917 value |= (0 << 7);
918 break;
Mauro Carvalho Chehab46f72962011-01-16 13:01:20 -0200919 case TRANSMISSION_MODE_4K:
Olivier Grenie713d54a2011-01-04 04:54:31 -0300920 value |= (2 << 7);
921 break;
922 default:
923 case TRANSMISSION_MODE_8K:
924 value |= (1 << 7);
925 break;
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300926 }
927 switch (ch->u.ofdm.guard_interval) {
Olivier Grenie713d54a2011-01-04 04:54:31 -0300928 case GUARD_INTERVAL_1_32:
929 value |= (0 << 5);
930 break;
931 case GUARD_INTERVAL_1_16:
932 value |= (1 << 5);
933 break;
934 case GUARD_INTERVAL_1_4:
935 value |= (3 << 5);
936 break;
937 default:
938 case GUARD_INTERVAL_1_8:
939 value |= (2 << 5);
940 break;
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300941 }
942 switch (ch->u.ofdm.constellation) {
Olivier Grenie713d54a2011-01-04 04:54:31 -0300943 case QPSK:
944 value |= (0 << 3);
945 break;
946 case QAM_16:
947 value |= (1 << 3);
948 break;
949 default:
950 case QAM_64:
951 value |= (2 << 3);
952 break;
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300953 }
954 switch (HIERARCHY_1) {
Olivier Grenie713d54a2011-01-04 04:54:31 -0300955 case HIERARCHY_2:
956 value |= 2;
957 break;
958 case HIERARCHY_4:
959 value |= 4;
960 break;
961 default:
962 case HIERARCHY_1:
963 value |= 1;
964 break;
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300965 }
966 dib7000p_write_word(state, 0, value);
Olivier Grenie713d54a2011-01-04 04:54:31 -0300967 dib7000p_write_word(state, 5, (seq << 4) | 1); /* do not force tps, search list 0 */
Patrick Boettchera75763f2006-10-18 08:34:16 -0300968
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300969 /* P_dintl_native, P_dintlv_inv, P_hrch, P_code_rate, P_select_hp */
970 value = 0;
971 if (1 != 0)
972 value |= (1 << 6);
973 if (ch->u.ofdm.hierarchy_information == 1)
974 value |= (1 << 4);
975 if (1 == 1)
976 value |= 1;
977 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 -0300978 case FEC_2_3:
979 value |= (2 << 1);
980 break;
981 case FEC_3_4:
982 value |= (3 << 1);
983 break;
984 case FEC_5_6:
985 value |= (5 << 1);
986 break;
987 case FEC_7_8:
988 value |= (7 << 1);
989 break;
990 default:
991 case FEC_1_2:
992 value |= (1 << 1);
993 break;
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300994 }
995 dib7000p_write_word(state, 208, value);
996
997 /* offset loop parameters */
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300998 dib7000p_write_word(state, 26, 0x6680);
999 dib7000p_write_word(state, 32, 0x0003);
1000 dib7000p_write_word(state, 29, 0x1273);
1001 dib7000p_write_word(state, 33, 0x0005);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001002
1003 /* P_dvsy_sync_wait */
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001004 switch (ch->u.ofdm.transmission_mode) {
Olivier Grenie713d54a2011-01-04 04:54:31 -03001005 case TRANSMISSION_MODE_8K:
1006 value = 256;
1007 break;
1008 case TRANSMISSION_MODE_4K:
1009 value = 128;
1010 break;
1011 case TRANSMISSION_MODE_2K:
1012 default:
1013 value = 64;
1014 break;
Patrick Boettchera75763f2006-10-18 08:34:16 -03001015 }
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001016 switch (ch->u.ofdm.guard_interval) {
Olivier Grenie713d54a2011-01-04 04:54:31 -03001017 case GUARD_INTERVAL_1_16:
1018 value *= 2;
1019 break;
1020 case GUARD_INTERVAL_1_8:
1021 value *= 4;
1022 break;
1023 case GUARD_INTERVAL_1_4:
1024 value *= 8;
1025 break;
1026 default:
1027 case GUARD_INTERVAL_1_32:
1028 value *= 1;
1029 break;
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001030 }
Olivier Grenie970d14c2010-09-07 12:50:46 -03001031 if (state->cfg.diversity_delay == 0)
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001032 state->div_sync_wait = (value * 3) / 2 + 48;
Olivier Grenie970d14c2010-09-07 12:50:46 -03001033 else
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001034 state->div_sync_wait = (value * 3) / 2 + state->cfg.diversity_delay;
Patrick Boettchera75763f2006-10-18 08:34:16 -03001035
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001036 /* deactive the possibility of diversity reception if extended interleaver */
1037 state->div_force_off = !1 && ch->u.ofdm.transmission_mode != TRANSMISSION_MODE_8K;
1038 dib7000p_set_diversity_in(&state->demod, state->div_state);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001039
1040 /* channel estimation fine configuration */
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001041 switch (ch->u.ofdm.constellation) {
Olivier Grenie713d54a2011-01-04 04:54:31 -03001042 case QAM_64:
1043 est[0] = 0x0148; /* P_adp_regul_cnt 0.04 */
1044 est[1] = 0xfff0; /* P_adp_noise_cnt -0.002 */
1045 est[2] = 0x00a4; /* P_adp_regul_ext 0.02 */
1046 est[3] = 0xfff8; /* P_adp_noise_ext -0.001 */
1047 break;
1048 case QAM_16:
1049 est[0] = 0x023d; /* P_adp_regul_cnt 0.07 */
1050 est[1] = 0xffdf; /* P_adp_noise_cnt -0.004 */
1051 est[2] = 0x00a4; /* P_adp_regul_ext 0.02 */
1052 est[3] = 0xfff0; /* P_adp_noise_ext -0.002 */
1053 break;
1054 default:
1055 est[0] = 0x099a; /* P_adp_regul_cnt 0.3 */
1056 est[1] = 0xffae; /* P_adp_noise_cnt -0.01 */
1057 est[2] = 0x0333; /* P_adp_regul_ext 0.1 */
1058 est[3] = 0xfff8; /* P_adp_noise_ext -0.002 */
1059 break;
Patrick Boettchera75763f2006-10-18 08:34:16 -03001060 }
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001061 for (value = 0; value < 4; value++)
1062 dib7000p_write_word(state, 187 + value, est[value]);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001063}
1064
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001065static int dib7000p_autosearch_start(struct dvb_frontend *demod, struct dvb_frontend_parameters *ch)
Patrick Boettchera75763f2006-10-18 08:34:16 -03001066{
1067 struct dib7000p_state *state = demod->demodulator_priv;
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001068 struct dvb_frontend_parameters schan;
1069 u32 value, factor;
Olivier Grenie713d54a2011-01-04 04:54:31 -03001070 u32 internal = dib7000p_get_internal_freq(state);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001071
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001072 schan = *ch;
1073 schan.u.ofdm.constellation = QAM_64;
Olivier Grenie713d54a2011-01-04 04:54:31 -03001074 schan.u.ofdm.guard_interval = GUARD_INTERVAL_1_32;
1075 schan.u.ofdm.transmission_mode = TRANSMISSION_MODE_8K;
1076 schan.u.ofdm.code_rate_HP = FEC_2_3;
1077 schan.u.ofdm.code_rate_LP = FEC_3_4;
1078 schan.u.ofdm.hierarchy_information = 0;
Patrick Boettchera75763f2006-10-18 08:34:16 -03001079
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001080 dib7000p_set_channel(state, &schan, 7);
1081
1082 factor = BANDWIDTH_TO_KHZ(ch->u.ofdm.bandwidth);
1083 if (factor >= 5000)
1084 factor = 1;
1085 else
1086 factor = 6;
Patrick Boettchera75763f2006-10-18 08:34:16 -03001087
Olivier Grenie713d54a2011-01-04 04:54:31 -03001088 value = 30 * internal * factor;
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001089 dib7000p_write_word(state, 6, (u16) ((value >> 16) & 0xffff));
1090 dib7000p_write_word(state, 7, (u16) (value & 0xffff));
Olivier Grenie713d54a2011-01-04 04:54:31 -03001091 value = 100 * internal * factor;
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001092 dib7000p_write_word(state, 8, (u16) ((value >> 16) & 0xffff));
1093 dib7000p_write_word(state, 9, (u16) (value & 0xffff));
Olivier Grenie713d54a2011-01-04 04:54:31 -03001094 value = 500 * internal * factor;
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001095 dib7000p_write_word(state, 10, (u16) ((value >> 16) & 0xffff));
1096 dib7000p_write_word(state, 11, (u16) (value & 0xffff));
Patrick Boettchera75763f2006-10-18 08:34:16 -03001097
1098 value = dib7000p_read_word(state, 0);
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001099 dib7000p_write_word(state, 0, (u16) ((1 << 9) | value));
Patrick Boettchera75763f2006-10-18 08:34:16 -03001100 dib7000p_read_word(state, 1284);
1101 dib7000p_write_word(state, 0, (u16) value);
1102
1103 return 0;
1104}
1105
1106static int dib7000p_autosearch_is_irq(struct dvb_frontend *demod)
1107{
1108 struct dib7000p_state *state = demod->demodulator_priv;
1109 u16 irq_pending = dib7000p_read_word(state, 1284);
1110
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001111 if (irq_pending & 0x1)
Patrick Boettchera75763f2006-10-18 08:34:16 -03001112 return 1;
1113
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001114 if (irq_pending & 0x2)
Patrick Boettchera75763f2006-10-18 08:34:16 -03001115 return 2;
1116
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001117 return 0;
Patrick Boettchera75763f2006-10-18 08:34:16 -03001118}
1119
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001120static void dib7000p_spur_protect(struct dib7000p_state *state, u32 rf_khz, u32 bw)
1121{
Olivier Grenie713d54a2011-01-04 04:54:31 -03001122 static s16 notch[] = { 16143, 14402, 12238, 9713, 6902, 3888, 759, -2392 };
1123 static u8 sine[] = { 0, 2, 3, 5, 6, 8, 9, 11, 13, 14, 16, 17, 19, 20, 22,
1124 24, 25, 27, 28, 30, 31, 33, 34, 36, 38, 39, 41, 42, 44, 45, 47, 48, 50, 51,
1125 53, 55, 56, 58, 59, 61, 62, 64, 65, 67, 68, 70, 71, 73, 74, 76, 77, 79, 80,
1126 82, 83, 85, 86, 88, 89, 91, 92, 94, 95, 97, 98, 99, 101, 102, 104, 105,
1127 107, 108, 109, 111, 112, 114, 115, 117, 118, 119, 121, 122, 123, 125, 126,
1128 128, 129, 130, 132, 133, 134, 136, 137, 138, 140, 141, 142, 144, 145, 146,
1129 147, 149, 150, 151, 152, 154, 155, 156, 157, 159, 160, 161, 162, 164, 165,
1130 166, 167, 168, 170, 171, 172, 173, 174, 175, 177, 178, 179, 180, 181, 182,
1131 183, 184, 185, 186, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198,
1132 199, 200, 201, 202, 203, 204, 205, 206, 207, 207, 208, 209, 210, 211, 212,
1133 213, 214, 215, 215, 216, 217, 218, 219, 220, 220, 221, 222, 223, 224, 224,
1134 225, 226, 227, 227, 228, 229, 229, 230, 231, 231, 232, 233, 233, 234, 235,
1135 235, 236, 237, 237, 238, 238, 239, 239, 240, 241, 241, 242, 242, 243, 243,
1136 244, 244, 245, 245, 245, 246, 246, 247, 247, 248, 248, 248, 249, 249, 249,
1137 250, 250, 250, 251, 251, 251, 252, 252, 252, 252, 253, 253, 253, 253, 254,
1138 254, 254, 254, 254, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
1139 255, 255, 255, 255, 255, 255
1140 };
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001141
1142 u32 xtal = state->cfg.bw->xtal_hz / 1000;
Julia Lawall75b697f2009-08-01 16:48:41 -03001143 int f_rel = DIV_ROUND_CLOSEST(rf_khz, xtal) * xtal - rf_khz;
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001144 int k;
Olivier Grenie713d54a2011-01-04 04:54:31 -03001145 int coef_re[8], coef_im[8];
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001146 int bw_khz = bw;
1147 u32 pha;
1148
Olivier Grenie713d54a2011-01-04 04:54:31 -03001149 dprintk("relative position of the Spur: %dk (RF: %dk, XTAL: %dk)", f_rel, rf_khz, xtal);
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001150
Olivier Grenie713d54a2011-01-04 04:54:31 -03001151 if (f_rel < -bw_khz / 2 || f_rel > bw_khz / 2)
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001152 return;
1153
1154 bw_khz /= 100;
1155
Olivier Grenie713d54a2011-01-04 04:54:31 -03001156 dib7000p_write_word(state, 142, 0x0610);
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001157
1158 for (k = 0; k < 8; k++) {
Olivier Grenie713d54a2011-01-04 04:54:31 -03001159 pha = ((f_rel * (k + 1) * 112 * 80 / bw_khz) / 1000) & 0x3ff;
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001160
Olivier Grenie713d54a2011-01-04 04:54:31 -03001161 if (pha == 0) {
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001162 coef_re[k] = 256;
1163 coef_im[k] = 0;
Olivier Grenie713d54a2011-01-04 04:54:31 -03001164 } else if (pha < 256) {
1165 coef_re[k] = sine[256 - (pha & 0xff)];
1166 coef_im[k] = sine[pha & 0xff];
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001167 } else if (pha == 256) {
1168 coef_re[k] = 0;
1169 coef_im[k] = 256;
1170 } else if (pha < 512) {
Olivier Grenie713d54a2011-01-04 04:54:31 -03001171 coef_re[k] = -sine[pha & 0xff];
1172 coef_im[k] = sine[256 - (pha & 0xff)];
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001173 } else if (pha == 512) {
1174 coef_re[k] = -256;
1175 coef_im[k] = 0;
1176 } else if (pha < 768) {
Olivier Grenie713d54a2011-01-04 04:54:31 -03001177 coef_re[k] = -sine[256 - (pha & 0xff)];
1178 coef_im[k] = -sine[pha & 0xff];
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001179 } else if (pha == 768) {
1180 coef_re[k] = 0;
1181 coef_im[k] = -256;
1182 } else {
Olivier Grenie713d54a2011-01-04 04:54:31 -03001183 coef_re[k] = sine[pha & 0xff];
1184 coef_im[k] = -sine[256 - (pha & 0xff)];
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001185 }
1186
1187 coef_re[k] *= notch[k];
Olivier Grenie713d54a2011-01-04 04:54:31 -03001188 coef_re[k] += (1 << 14);
1189 if (coef_re[k] >= (1 << 24))
1190 coef_re[k] = (1 << 24) - 1;
1191 coef_re[k] /= (1 << 15);
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001192
1193 coef_im[k] *= notch[k];
Olivier Grenie713d54a2011-01-04 04:54:31 -03001194 coef_im[k] += (1 << 14);
1195 if (coef_im[k] >= (1 << 24))
1196 coef_im[k] = (1 << 24) - 1;
1197 coef_im[k] /= (1 << 15);
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001198
Olivier Grenie713d54a2011-01-04 04:54:31 -03001199 dprintk("PALF COEF: %d re: %d im: %d", k, coef_re[k], coef_im[k]);
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001200
1201 dib7000p_write_word(state, 143, (0 << 14) | (k << 10) | (coef_re[k] & 0x3ff));
1202 dib7000p_write_word(state, 144, coef_im[k] & 0x3ff);
1203 dib7000p_write_word(state, 143, (1 << 14) | (k << 10) | (coef_re[k] & 0x3ff));
1204 }
Olivier Grenie713d54a2011-01-04 04:54:31 -03001205 dib7000p_write_word(state, 143, 0);
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001206}
1207
1208static int dib7000p_tune(struct dvb_frontend *demod, struct dvb_frontend_parameters *ch)
Patrick Boettchera75763f2006-10-18 08:34:16 -03001209{
1210 struct dib7000p_state *state = demod->demodulator_priv;
1211 u16 tmp = 0;
1212
1213 if (ch != NULL)
1214 dib7000p_set_channel(state, ch, 0);
1215 else
1216 return -EINVAL;
1217
1218 // restart demod
1219 dib7000p_write_word(state, 770, 0x4000);
1220 dib7000p_write_word(state, 770, 0x0000);
1221 msleep(45);
1222
1223 /* 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 -03001224 tmp = (0 << 14) | (4 << 10) | (0 << 9) | (3 << 5) | (1 << 4) | (0x3);
1225 if (state->sfn_workaround_active) {
Olivier Grenie713d54a2011-01-04 04:54:31 -03001226 dprintk("SFN workaround is active");
Matt Doran8f6956c2007-07-31 07:09:30 -03001227 tmp |= (1 << 9);
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001228 dib7000p_write_word(state, 166, 0x4000);
Matt Doran8f6956c2007-07-31 07:09:30 -03001229 } else {
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001230 dib7000p_write_word(state, 166, 0x0000);
Matt Doran8f6956c2007-07-31 07:09:30 -03001231 }
1232 dib7000p_write_word(state, 29, tmp);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001233
1234 // never achieved a lock with that bandwidth so far - wait for osc-freq to update
1235 if (state->timf == 0)
1236 msleep(200);
1237
1238 /* offset loop parameters */
1239
1240 /* P_timf_alpha, P_corm_alpha=6, P_corm_thres=0x80 */
1241 tmp = (6 << 8) | 0x80;
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001242 switch (ch->u.ofdm.transmission_mode) {
Olivier Grenie713d54a2011-01-04 04:54:31 -03001243 case TRANSMISSION_MODE_2K:
1244 tmp |= (2 << 12);
1245 break;
Mauro Carvalho Chehab46f72962011-01-16 13:01:20 -02001246 case TRANSMISSION_MODE_4K:
Olivier Grenie713d54a2011-01-04 04:54:31 -03001247 tmp |= (3 << 12);
1248 break;
1249 default:
1250 case TRANSMISSION_MODE_8K:
1251 tmp |= (4 << 12);
1252 break;
Patrick Boettchera75763f2006-10-18 08:34:16 -03001253 }
Olivier Grenie713d54a2011-01-04 04:54:31 -03001254 dib7000p_write_word(state, 26, tmp); /* timf_a(6xxx) */
Patrick Boettchera75763f2006-10-18 08:34:16 -03001255
1256 /* P_ctrl_freeze_pha_shift=0, P_ctrl_pha_off_max */
1257 tmp = (0 << 4);
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001258 switch (ch->u.ofdm.transmission_mode) {
Olivier Grenie713d54a2011-01-04 04:54:31 -03001259 case TRANSMISSION_MODE_2K:
1260 tmp |= 0x6;
1261 break;
Mauro Carvalho Chehab46f72962011-01-16 13:01:20 -02001262 case TRANSMISSION_MODE_4K:
Olivier Grenie713d54a2011-01-04 04:54:31 -03001263 tmp |= 0x7;
1264 break;
1265 default:
1266 case TRANSMISSION_MODE_8K:
1267 tmp |= 0x8;
1268 break;
Patrick Boettchera75763f2006-10-18 08:34:16 -03001269 }
Olivier Grenie713d54a2011-01-04 04:54:31 -03001270 dib7000p_write_word(state, 32, tmp);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001271
1272 /* P_ctrl_sfreq_inh=0, P_ctrl_sfreq_step */
1273 tmp = (0 << 4);
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001274 switch (ch->u.ofdm.transmission_mode) {
Olivier Grenie713d54a2011-01-04 04:54:31 -03001275 case TRANSMISSION_MODE_2K:
1276 tmp |= 0x6;
1277 break;
1278 case TRANSMISSION_MODE_4K:
1279 tmp |= 0x7;
1280 break;
1281 default:
1282 case TRANSMISSION_MODE_8K:
1283 tmp |= 0x8;
1284 break;
Patrick Boettchera75763f2006-10-18 08:34:16 -03001285 }
Olivier Grenie713d54a2011-01-04 04:54:31 -03001286 dib7000p_write_word(state, 33, tmp);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001287
Olivier Grenie713d54a2011-01-04 04:54:31 -03001288 tmp = dib7000p_read_word(state, 509);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001289 if (!((tmp >> 6) & 0x1)) {
1290 /* restart the fec */
Olivier Grenie713d54a2011-01-04 04:54:31 -03001291 tmp = dib7000p_read_word(state, 771);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001292 dib7000p_write_word(state, 771, tmp | (1 << 1));
1293 dib7000p_write_word(state, 771, tmp);
Olivier Grenie713d54a2011-01-04 04:54:31 -03001294 msleep(40);
1295 tmp = dib7000p_read_word(state, 509);
1296 }
1297 // we achieved a lock - it's time to update the osc freq
1298 if ((tmp >> 6) & 0x1) {
1299 dib7000p_update_timf(state);
1300 /* P_timf_alpha += 2 */
1301 tmp = dib7000p_read_word(state, 26);
1302 dib7000p_write_word(state, 26, (tmp & ~(0xf << 12)) | ((((tmp >> 12) & 0xf) + 5) << 12));
Patrick Boettchera75763f2006-10-18 08:34:16 -03001303 }
1304
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001305 if (state->cfg.spur_protect)
Olivier Grenie713d54a2011-01-04 04:54:31 -03001306 dib7000p_spur_protect(state, ch->frequency / 1000, BANDWIDTH_TO_KHZ(ch->u.ofdm.bandwidth));
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001307
Olivier Grenie713d54a2011-01-04 04:54:31 -03001308 dib7000p_set_bandwidth(state, BANDWIDTH_TO_KHZ(ch->u.ofdm.bandwidth));
Patrick Boettchera75763f2006-10-18 08:34:16 -03001309 return 0;
1310}
1311
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001312static int dib7000p_wakeup(struct dvb_frontend *demod)
Patrick Boettchera75763f2006-10-18 08:34:16 -03001313{
Patrick Boettchera75763f2006-10-18 08:34:16 -03001314 struct dib7000p_state *state = demod->demodulator_priv;
Patrick Boettchera75763f2006-10-18 08:34:16 -03001315 dib7000p_set_power_mode(state, DIB7000P_POWER_ALL);
1316 dib7000p_set_adc_state(state, DIBX000_SLOW_ADC_ON);
Olivier Grenie713d54a2011-01-04 04:54:31 -03001317 if (state->version == SOC7090)
1318 dib7000p_sad_calib(state);
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001319 return 0;
Patrick Boettchera75763f2006-10-18 08:34:16 -03001320}
1321
1322static int dib7000p_sleep(struct dvb_frontend *demod)
1323{
1324 struct dib7000p_state *state = demod->demodulator_priv;
Olivier Grenie713d54a2011-01-04 04:54:31 -03001325 if (state->version == SOC7090)
1326 return dib7090_set_output_mode(demod, OUTMODE_HIGH_Z) | dib7000p_set_power_mode(state, DIB7000P_POWER_INTERFACE_ONLY);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001327 return dib7000p_set_output_mode(state, OUTMODE_HIGH_Z) | dib7000p_set_power_mode(state, DIB7000P_POWER_INTERFACE_ONLY);
1328}
1329
1330static int dib7000p_identify(struct dib7000p_state *st)
1331{
1332 u16 value;
Olivier Grenie713d54a2011-01-04 04:54:31 -03001333 dprintk("checking demod on I2C address: %d (%x)", st->i2c_addr, st->i2c_addr);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001334
1335 if ((value = dib7000p_read_word(st, 768)) != 0x01b3) {
Olivier Grenie713d54a2011-01-04 04:54:31 -03001336 dprintk("wrong Vendor ID (read=0x%x)", value);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001337 return -EREMOTEIO;
1338 }
1339
1340 if ((value = dib7000p_read_word(st, 769)) != 0x4000) {
Olivier Grenie713d54a2011-01-04 04:54:31 -03001341 dprintk("wrong Device ID (%x)", value);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001342 return -EREMOTEIO;
1343 }
1344
1345 return 0;
1346}
1347
Olivier Grenie713d54a2011-01-04 04:54:31 -03001348static int dib7000p_get_frontend(struct dvb_frontend *fe, struct dvb_frontend_parameters *fep)
Patrick Boettchera75763f2006-10-18 08:34:16 -03001349{
1350 struct dib7000p_state *state = fe->demodulator_priv;
Olivier Grenie713d54a2011-01-04 04:54:31 -03001351 u16 tps = dib7000p_read_word(state, 463);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001352
1353 fep->inversion = INVERSION_AUTO;
1354
Patrick Boettcher904a82e2008-01-25 07:31:58 -03001355 fep->u.ofdm.bandwidth = BANDWIDTH_TO_INDEX(state->current_bandwidth);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001356
1357 switch ((tps >> 8) & 0x3) {
Olivier Grenie713d54a2011-01-04 04:54:31 -03001358 case 0:
1359 fep->u.ofdm.transmission_mode = TRANSMISSION_MODE_2K;
1360 break;
1361 case 1:
1362 fep->u.ofdm.transmission_mode = TRANSMISSION_MODE_8K;
1363 break;
Mauro Carvalho Chehab46f72962011-01-16 13:01:20 -02001364 /* case 2: fep->u.ofdm.transmission_mode = TRANSMISSION_MODE_4K; break; */
Patrick Boettchera75763f2006-10-18 08:34:16 -03001365 }
1366
1367 switch (tps & 0x3) {
Olivier Grenie713d54a2011-01-04 04:54:31 -03001368 case 0:
1369 fep->u.ofdm.guard_interval = GUARD_INTERVAL_1_32;
1370 break;
1371 case 1:
1372 fep->u.ofdm.guard_interval = GUARD_INTERVAL_1_16;
1373 break;
1374 case 2:
1375 fep->u.ofdm.guard_interval = GUARD_INTERVAL_1_8;
1376 break;
1377 case 3:
1378 fep->u.ofdm.guard_interval = GUARD_INTERVAL_1_4;
1379 break;
Patrick Boettchera75763f2006-10-18 08:34:16 -03001380 }
1381
1382 switch ((tps >> 14) & 0x3) {
Olivier Grenie713d54a2011-01-04 04:54:31 -03001383 case 0:
1384 fep->u.ofdm.constellation = QPSK;
1385 break;
1386 case 1:
1387 fep->u.ofdm.constellation = QAM_16;
1388 break;
1389 case 2:
1390 default:
1391 fep->u.ofdm.constellation = QAM_64;
1392 break;
Patrick Boettchera75763f2006-10-18 08:34:16 -03001393 }
1394
1395 /* as long as the frontend_param structure is fixed for hierarchical transmission I refuse to use it */
1396 /* (tps >> 13) & 0x1 == hrch is used, (tps >> 10) & 0x7 == alpha */
1397
1398 fep->u.ofdm.hierarchy_information = HIERARCHY_NONE;
1399 switch ((tps >> 5) & 0x7) {
Olivier Grenie713d54a2011-01-04 04:54:31 -03001400 case 1:
1401 fep->u.ofdm.code_rate_HP = FEC_1_2;
1402 break;
1403 case 2:
1404 fep->u.ofdm.code_rate_HP = FEC_2_3;
1405 break;
1406 case 3:
1407 fep->u.ofdm.code_rate_HP = FEC_3_4;
1408 break;
1409 case 5:
1410 fep->u.ofdm.code_rate_HP = FEC_5_6;
1411 break;
1412 case 7:
1413 default:
1414 fep->u.ofdm.code_rate_HP = FEC_7_8;
1415 break;
Patrick Boettchera75763f2006-10-18 08:34:16 -03001416
1417 }
1418
1419 switch ((tps >> 2) & 0x7) {
Olivier Grenie713d54a2011-01-04 04:54:31 -03001420 case 1:
1421 fep->u.ofdm.code_rate_LP = FEC_1_2;
1422 break;
1423 case 2:
1424 fep->u.ofdm.code_rate_LP = FEC_2_3;
1425 break;
1426 case 3:
1427 fep->u.ofdm.code_rate_LP = FEC_3_4;
1428 break;
1429 case 5:
1430 fep->u.ofdm.code_rate_LP = FEC_5_6;
1431 break;
1432 case 7:
1433 default:
1434 fep->u.ofdm.code_rate_LP = FEC_7_8;
1435 break;
Patrick Boettchera75763f2006-10-18 08:34:16 -03001436 }
1437
1438 /* native interleaver: (dib7000p_read_word(state, 464) >> 5) & 0x1 */
1439
1440 return 0;
1441}
1442
Olivier Grenie713d54a2011-01-04 04:54:31 -03001443static int dib7000p_set_frontend(struct dvb_frontend *fe, struct dvb_frontend_parameters *fep)
Patrick Boettchera75763f2006-10-18 08:34:16 -03001444{
1445 struct dib7000p_state *state = fe->demodulator_priv;
Soeren Moch853ea132008-01-25 06:27:06 -03001446 int time, ret;
Patrick Boettchera75763f2006-10-18 08:34:16 -03001447
Olivier Grenie713d54a2011-01-04 04:54:31 -03001448 if (state->version == SOC7090) {
1449 dib7090_set_diversity_in(fe, 0);
1450 dib7090_set_output_mode(fe, OUTMODE_HIGH_Z);
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001451 } else
Olivier Grenie713d54a2011-01-04 04:54:31 -03001452 dib7000p_set_output_mode(state, OUTMODE_HIGH_Z);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001453
Olivier Grenie713d54a2011-01-04 04:54:31 -03001454 /* maybe the parameter has been changed */
Matt Doran8f6956c2007-07-31 07:09:30 -03001455 state->sfn_workaround_active = buggy_sfn_workaround;
1456
Patrick Boettchera75763f2006-10-18 08:34:16 -03001457 if (fe->ops.tuner_ops.set_params)
1458 fe->ops.tuner_ops.set_params(fe, fep);
1459
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001460 /* start up the AGC */
1461 state->agc_state = 0;
1462 do {
1463 time = dib7000p_agc_startup(fe, fep);
1464 if (time != -1)
1465 msleep(time);
1466 } while (time != -1);
1467
Patrick Boettchera75763f2006-10-18 08:34:16 -03001468 if (fep->u.ofdm.transmission_mode == TRANSMISSION_MODE_AUTO ||
Olivier Grenie713d54a2011-01-04 04:54:31 -03001469 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 -03001470 int i = 800, found;
1471
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001472 dib7000p_autosearch_start(fe, fep);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001473 do {
1474 msleep(1);
1475 found = dib7000p_autosearch_is_irq(fe);
1476 } while (found == 0 && i--);
1477
Olivier Grenie713d54a2011-01-04 04:54:31 -03001478 dprintk("autosearch returns: %d", found);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001479 if (found == 0 || found == 1)
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001480 return 0;
Patrick Boettchera75763f2006-10-18 08:34:16 -03001481
1482 dib7000p_get_frontend(fe, fep);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001483 }
1484
Soeren Moch853ea132008-01-25 06:27:06 -03001485 ret = dib7000p_tune(fe, fep);
1486
Patrick Boettchera75763f2006-10-18 08:34:16 -03001487 /* make this a config parameter */
Olivier Grenie713d54a2011-01-04 04:54:31 -03001488 if (state->version == SOC7090)
1489 dib7090_set_output_mode(fe, state->cfg.output_mode);
1490 else
1491 dib7000p_set_output_mode(state, state->cfg.output_mode);
1492
1493 return ret;
Patrick Boettchera75763f2006-10-18 08:34:16 -03001494}
1495
Olivier Grenie713d54a2011-01-04 04:54:31 -03001496static int dib7000p_read_status(struct dvb_frontend *fe, fe_status_t * stat)
Patrick Boettchera75763f2006-10-18 08:34:16 -03001497{
1498 struct dib7000p_state *state = fe->demodulator_priv;
1499 u16 lock = dib7000p_read_word(state, 509);
1500
1501 *stat = 0;
1502
1503 if (lock & 0x8000)
1504 *stat |= FE_HAS_SIGNAL;
1505 if (lock & 0x3000)
1506 *stat |= FE_HAS_CARRIER;
1507 if (lock & 0x0100)
1508 *stat |= FE_HAS_VITERBI;
1509 if (lock & 0x0010)
1510 *stat |= FE_HAS_SYNC;
Olivier Grenie713d54a2011-01-04 04:54:31 -03001511 if ((lock & 0x0038) == 0x38)
Patrick Boettchera75763f2006-10-18 08:34:16 -03001512 *stat |= FE_HAS_LOCK;
1513
1514 return 0;
1515}
1516
Olivier Grenie713d54a2011-01-04 04:54:31 -03001517static int dib7000p_read_ber(struct dvb_frontend *fe, u32 * ber)
Patrick Boettchera75763f2006-10-18 08:34:16 -03001518{
1519 struct dib7000p_state *state = fe->demodulator_priv;
1520 *ber = (dib7000p_read_word(state, 500) << 16) | dib7000p_read_word(state, 501);
1521 return 0;
1522}
1523
Olivier Grenie713d54a2011-01-04 04:54:31 -03001524static int dib7000p_read_unc_blocks(struct dvb_frontend *fe, u32 * unc)
Patrick Boettchera75763f2006-10-18 08:34:16 -03001525{
1526 struct dib7000p_state *state = fe->demodulator_priv;
1527 *unc = dib7000p_read_word(state, 506);
1528 return 0;
1529}
1530
Olivier Grenie713d54a2011-01-04 04:54:31 -03001531static int dib7000p_read_signal_strength(struct dvb_frontend *fe, u16 * strength)
Patrick Boettchera75763f2006-10-18 08:34:16 -03001532{
1533 struct dib7000p_state *state = fe->demodulator_priv;
1534 u16 val = dib7000p_read_word(state, 394);
1535 *strength = 65535 - val;
1536 return 0;
1537}
1538
Olivier Grenie713d54a2011-01-04 04:54:31 -03001539static int dib7000p_read_snr(struct dvb_frontend *fe, u16 * snr)
Patrick Boettchera75763f2006-10-18 08:34:16 -03001540{
Olivier Grenieef801962009-09-15 06:46:52 -03001541 struct dib7000p_state *state = fe->demodulator_priv;
1542 u16 val;
1543 s32 signal_mant, signal_exp, noise_mant, noise_exp;
1544 u32 result = 0;
1545
1546 val = dib7000p_read_word(state, 479);
1547 noise_mant = (val >> 4) & 0xff;
1548 noise_exp = ((val & 0xf) << 2);
1549 val = dib7000p_read_word(state, 480);
1550 noise_exp += ((val >> 14) & 0x3);
1551 if ((noise_exp & 0x20) != 0)
1552 noise_exp -= 0x40;
1553
1554 signal_mant = (val >> 6) & 0xFF;
Olivier Grenie713d54a2011-01-04 04:54:31 -03001555 signal_exp = (val & 0x3F);
Olivier Grenieef801962009-09-15 06:46:52 -03001556 if ((signal_exp & 0x20) != 0)
1557 signal_exp -= 0x40;
1558
1559 if (signal_mant != 0)
Olivier Grenie713d54a2011-01-04 04:54:31 -03001560 result = intlog10(2) * 10 * signal_exp + 10 * intlog10(signal_mant);
Olivier Grenieef801962009-09-15 06:46:52 -03001561 else
1562 result = intlog10(2) * 10 * signal_exp - 100;
1563
1564 if (noise_mant != 0)
Olivier Grenie713d54a2011-01-04 04:54:31 -03001565 result -= intlog10(2) * 10 * noise_exp + 10 * intlog10(noise_mant);
Olivier Grenieef801962009-09-15 06:46:52 -03001566 else
1567 result -= intlog10(2) * 10 * noise_exp - 100;
1568
1569 *snr = result / ((1 << 24) / 10);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001570 return 0;
1571}
1572
Olivier Grenie713d54a2011-01-04 04:54:31 -03001573static int dib7000p_fe_get_tune_settings(struct dvb_frontend *fe, struct dvb_frontend_tune_settings *tune)
Patrick Boettchera75763f2006-10-18 08:34:16 -03001574{
1575 tune->min_delay_ms = 1000;
1576 return 0;
1577}
1578
1579static void dib7000p_release(struct dvb_frontend *demod)
1580{
1581 struct dib7000p_state *st = demod->demodulator_priv;
1582 dibx000_exit_i2c_master(&st->i2c_master);
Olivier Grenie713d54a2011-01-04 04:54:31 -03001583 i2c_del_adapter(&st->dib7090_tuner_adap);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001584 kfree(st);
1585}
1586
1587int dib7000pc_detection(struct i2c_adapter *i2c_adap)
1588{
Olivier Grenie5a0deee2011-05-03 12:27:33 -03001589 u8 *tx, *rx;
Patrick Boettchera75763f2006-10-18 08:34:16 -03001590 struct i2c_msg msg[2] = {
Olivier Grenie5a0deee2011-05-03 12:27:33 -03001591 {.addr = 18 >> 1, .flags = 0, .len = 2},
1592 {.addr = 18 >> 1, .flags = I2C_M_RD, .len = 2},
Patrick Boettchera75763f2006-10-18 08:34:16 -03001593 };
Olivier Grenie5a0deee2011-05-03 12:27:33 -03001594 int ret = 0;
1595
1596 tx = kzalloc(2*sizeof(u8), GFP_KERNEL);
1597 if (!tx)
1598 return -ENOMEM;
1599 rx = kzalloc(2*sizeof(u8), GFP_KERNEL);
1600 if (!rx) {
1601 goto rx_memory_error;
1602 ret = -ENOMEM;
1603 }
1604
1605 msg[0].buf = tx;
1606 msg[1].buf = rx;
Patrick Boettchera75763f2006-10-18 08:34:16 -03001607
1608 tx[0] = 0x03;
1609 tx[1] = 0x00;
1610
1611 if (i2c_transfer(i2c_adap, msg, 2) == 2)
1612 if (rx[0] == 0x01 && rx[1] == 0xb3) {
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001613 dprintk("-D- DiB7000PC detected");
Patrick Boettchera75763f2006-10-18 08:34:16 -03001614 return 1;
1615 }
1616
1617 msg[0].addr = msg[1].addr = 0x40;
1618
1619 if (i2c_transfer(i2c_adap, msg, 2) == 2)
1620 if (rx[0] == 0x01 && rx[1] == 0xb3) {
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001621 dprintk("-D- DiB7000PC detected");
Patrick Boettchera75763f2006-10-18 08:34:16 -03001622 return 1;
1623 }
1624
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001625 dprintk("-D- DiB7000PC not detected");
Olivier Grenie5a0deee2011-05-03 12:27:33 -03001626
1627 kfree(rx);
1628rx_memory_error:
1629 kfree(tx);
1630 return ret;
Patrick Boettchera75763f2006-10-18 08:34:16 -03001631}
1632EXPORT_SYMBOL(dib7000pc_detection);
1633
Olivier Grenie713d54a2011-01-04 04:54:31 -03001634struct i2c_adapter *dib7000p_get_i2c_master(struct dvb_frontend *demod, enum dibx000_i2c_interface intf, int gating)
Patrick Boettchera75763f2006-10-18 08:34:16 -03001635{
1636 struct dib7000p_state *st = demod->demodulator_priv;
1637 return dibx000_get_i2c_adapter(&st->i2c_master, intf, gating);
1638}
1639EXPORT_SYMBOL(dib7000p_get_i2c_master);
1640
Olivier Grenief8731f42009-09-18 04:08:43 -03001641int dib7000p_pid_filter_ctrl(struct dvb_frontend *fe, u8 onoff)
1642{
Olivier Grenie713d54a2011-01-04 04:54:31 -03001643 struct dib7000p_state *state = fe->demodulator_priv;
1644 u16 val = dib7000p_read_word(state, 235) & 0xffef;
1645 val |= (onoff & 0x1) << 4;
1646 dprintk("PID filter enabled %d", onoff);
1647 return dib7000p_write_word(state, 235, val);
Olivier Grenief8731f42009-09-18 04:08:43 -03001648}
1649EXPORT_SYMBOL(dib7000p_pid_filter_ctrl);
1650
1651int dib7000p_pid_filter(struct dvb_frontend *fe, u8 id, u16 pid, u8 onoff)
1652{
Olivier Grenie713d54a2011-01-04 04:54:31 -03001653 struct dib7000p_state *state = fe->demodulator_priv;
1654 dprintk("PID filter: index %x, PID %d, OnOff %d", id, pid, onoff);
1655 return dib7000p_write_word(state, 241 + id, onoff ? (1 << 13) | pid : 0);
Olivier Grenief8731f42009-09-18 04:08:43 -03001656}
1657EXPORT_SYMBOL(dib7000p_pid_filter);
1658
Patrick Boettchera75763f2006-10-18 08:34:16 -03001659int dib7000p_i2c_enumeration(struct i2c_adapter *i2c, int no_of_demods, u8 default_addr, struct dib7000p_config cfg[])
1660{
Randy Dunlap30d81bb2010-02-08 20:30:44 -03001661 struct dib7000p_state *dpst;
Patrick Boettchera75763f2006-10-18 08:34:16 -03001662 int k = 0;
1663 u8 new_addr = 0;
1664
Randy Dunlap30d81bb2010-02-08 20:30:44 -03001665 dpst = kzalloc(sizeof(struct dib7000p_state), GFP_KERNEL);
1666 if (!dpst)
Andrew Morton0b427602010-04-27 19:09:45 -03001667 return -ENOMEM;
Randy Dunlap30d81bb2010-02-08 20:30:44 -03001668
1669 dpst->i2c_adap = i2c;
Patrick Boettcher79fcce32011-08-03 12:08:21 -03001670 mutex_init(&dpst->i2c_buffer_lock);
Randy Dunlap30d81bb2010-02-08 20:30:44 -03001671
Olivier Grenie713d54a2011-01-04 04:54:31 -03001672 for (k = no_of_demods - 1; k >= 0; k--) {
Randy Dunlap30d81bb2010-02-08 20:30:44 -03001673 dpst->cfg = cfg[k];
Patrick Boettchera75763f2006-10-18 08:34:16 -03001674
1675 /* designated i2c address */
Olivier Grenie713d54a2011-01-04 04:54:31 -03001676 if (cfg[k].default_i2c_addr != 0)
1677 new_addr = cfg[k].default_i2c_addr + (k << 1);
1678 else
1679 new_addr = (0x40 + k) << 1;
Randy Dunlap30d81bb2010-02-08 20:30:44 -03001680 dpst->i2c_addr = new_addr;
Olivier Grenie713d54a2011-01-04 04:54:31 -03001681 dib7000p_write_word(dpst, 1287, 0x0003); /* sram lead in, rdy */
Randy Dunlap30d81bb2010-02-08 20:30:44 -03001682 if (dib7000p_identify(dpst) != 0) {
1683 dpst->i2c_addr = default_addr;
Olivier Grenie713d54a2011-01-04 04:54:31 -03001684 dib7000p_write_word(dpst, 1287, 0x0003); /* sram lead in, rdy */
Randy Dunlap30d81bb2010-02-08 20:30:44 -03001685 if (dib7000p_identify(dpst) != 0) {
Patrick Boettchera75763f2006-10-18 08:34:16 -03001686 dprintk("DiB7000P #%d: not identified\n", k);
Randy Dunlap30d81bb2010-02-08 20:30:44 -03001687 kfree(dpst);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001688 return -EIO;
1689 }
1690 }
1691
1692 /* start diversity to pull_down div_str - just for i2c-enumeration */
Randy Dunlap30d81bb2010-02-08 20:30:44 -03001693 dib7000p_set_output_mode(dpst, OUTMODE_DIVERSITY);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001694
1695 /* set new i2c address and force divstart */
Randy Dunlap30d81bb2010-02-08 20:30:44 -03001696 dib7000p_write_word(dpst, 1285, (new_addr << 2) | 0x2);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001697
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001698 dprintk("IC %d initialized (to i2c_address 0x%x)", k, new_addr);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001699 }
1700
1701 for (k = 0; k < no_of_demods; k++) {
Randy Dunlap30d81bb2010-02-08 20:30:44 -03001702 dpst->cfg = cfg[k];
Olivier Grenie713d54a2011-01-04 04:54:31 -03001703 if (cfg[k].default_i2c_addr != 0)
1704 dpst->i2c_addr = (cfg[k].default_i2c_addr + k) << 1;
1705 else
1706 dpst->i2c_addr = (0x40 + k) << 1;
Patrick Boettchera75763f2006-10-18 08:34:16 -03001707
1708 // unforce divstr
Randy Dunlap30d81bb2010-02-08 20:30:44 -03001709 dib7000p_write_word(dpst, 1285, dpst->i2c_addr << 2);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001710
1711 /* deactivate div - it was just for i2c-enumeration */
Randy Dunlap30d81bb2010-02-08 20:30:44 -03001712 dib7000p_set_output_mode(dpst, OUTMODE_HIGH_Z);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001713 }
1714
Randy Dunlap30d81bb2010-02-08 20:30:44 -03001715 kfree(dpst);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001716 return 0;
1717}
1718EXPORT_SYMBOL(dib7000p_i2c_enumeration);
1719
Olivier Grenie713d54a2011-01-04 04:54:31 -03001720static const s32 lut_1000ln_mant[] = {
1721 6908, 6956, 7003, 7047, 7090, 7131, 7170, 7208, 7244, 7279, 7313, 7346, 7377, 7408, 7438, 7467, 7495, 7523, 7549, 7575, 7600
1722};
1723
1724static s32 dib7000p_get_adc_power(struct dvb_frontend *fe)
1725{
1726 struct dib7000p_state *state = fe->demodulator_priv;
1727 u32 tmp_val = 0, exp = 0, mant = 0;
1728 s32 pow_i;
1729 u16 buf[2];
1730 u8 ix = 0;
1731
1732 buf[0] = dib7000p_read_word(state, 0x184);
1733 buf[1] = dib7000p_read_word(state, 0x185);
1734 pow_i = (buf[0] << 16) | buf[1];
1735 dprintk("raw pow_i = %d", pow_i);
1736
1737 tmp_val = pow_i;
1738 while (tmp_val >>= 1)
1739 exp++;
1740
1741 mant = (pow_i * 1000 / (1 << exp));
1742 dprintk(" mant = %d exp = %d", mant / 1000, exp);
1743
1744 ix = (u8) ((mant - 1000) / 100); /* index of the LUT */
1745 dprintk(" ix = %d", ix);
1746
1747 pow_i = (lut_1000ln_mant[ix] + 693 * (exp - 20) - 6908);
1748 pow_i = (pow_i << 8) / 1000;
1749 dprintk(" pow_i = %d", pow_i);
1750
1751 return pow_i;
1752}
1753
1754static int map_addr_to_serpar_number(struct i2c_msg *msg)
1755{
1756 if ((msg->buf[0] <= 15))
1757 msg->buf[0] -= 1;
1758 else if (msg->buf[0] == 17)
1759 msg->buf[0] = 15;
1760 else if (msg->buf[0] == 16)
1761 msg->buf[0] = 17;
1762 else if (msg->buf[0] == 19)
1763 msg->buf[0] = 16;
1764 else if (msg->buf[0] >= 21 && msg->buf[0] <= 25)
1765 msg->buf[0] -= 3;
1766 else if (msg->buf[0] == 28)
1767 msg->buf[0] = 23;
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001768 else
Olivier Grenie713d54a2011-01-04 04:54:31 -03001769 return -EINVAL;
Olivier Grenie713d54a2011-01-04 04:54:31 -03001770 return 0;
1771}
1772
1773static int w7090p_tuner_write_serpar(struct i2c_adapter *i2c_adap, struct i2c_msg msg[], int num)
1774{
1775 struct dib7000p_state *state = i2c_get_adapdata(i2c_adap);
1776 u8 n_overflow = 1;
1777 u16 i = 1000;
1778 u16 serpar_num = msg[0].buf[0];
1779
1780 while (n_overflow == 1 && i) {
1781 n_overflow = (dib7000p_read_word(state, 1984) >> 1) & 0x1;
1782 i--;
1783 if (i == 0)
1784 dprintk("Tuner ITF: write busy (overflow)");
1785 }
1786 dib7000p_write_word(state, 1985, (1 << 6) | (serpar_num & 0x3f));
1787 dib7000p_write_word(state, 1986, (msg[0].buf[1] << 8) | msg[0].buf[2]);
1788
1789 return num;
1790}
1791
1792static int w7090p_tuner_read_serpar(struct i2c_adapter *i2c_adap, struct i2c_msg msg[], int num)
1793{
1794 struct dib7000p_state *state = i2c_get_adapdata(i2c_adap);
1795 u8 n_overflow = 1, n_empty = 1;
1796 u16 i = 1000;
1797 u16 serpar_num = msg[0].buf[0];
1798 u16 read_word;
1799
1800 while (n_overflow == 1 && i) {
1801 n_overflow = (dib7000p_read_word(state, 1984) >> 1) & 0x1;
1802 i--;
1803 if (i == 0)
1804 dprintk("TunerITF: read busy (overflow)");
1805 }
1806 dib7000p_write_word(state, 1985, (0 << 6) | (serpar_num & 0x3f));
1807
1808 i = 1000;
1809 while (n_empty == 1 && i) {
1810 n_empty = dib7000p_read_word(state, 1984) & 0x1;
1811 i--;
1812 if (i == 0)
1813 dprintk("TunerITF: read busy (empty)");
1814 }
1815 read_word = dib7000p_read_word(state, 1987);
1816 msg[1].buf[0] = (read_word >> 8) & 0xff;
1817 msg[1].buf[1] = (read_word) & 0xff;
1818
1819 return num;
1820}
1821
1822static int w7090p_tuner_rw_serpar(struct i2c_adapter *i2c_adap, struct i2c_msg msg[], int num)
1823{
1824 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... */
1825 if (num == 1) { /* write */
1826 return w7090p_tuner_write_serpar(i2c_adap, msg, 1);
1827 } else { /* read */
1828 return w7090p_tuner_read_serpar(i2c_adap, msg, 2);
1829 }
1830 }
1831 return num;
1832}
1833
1834int dib7090p_rw_on_apb(struct i2c_adapter *i2c_adap, struct i2c_msg msg[], int num, u16 apb_address)
1835{
1836 struct dib7000p_state *state = i2c_get_adapdata(i2c_adap);
1837 u16 word;
1838
1839 if (num == 1) { /* write */
1840 dib7000p_write_word(state, apb_address, ((msg[0].buf[1] << 8) | (msg[0].buf[2])));
1841 } else {
1842 word = dib7000p_read_word(state, apb_address);
1843 msg[1].buf[0] = (word >> 8) & 0xff;
1844 msg[1].buf[1] = (word) & 0xff;
1845 }
1846
1847 return num;
1848}
1849
1850static int dib7090_tuner_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg msg[], int num)
1851{
1852 struct dib7000p_state *state = i2c_get_adapdata(i2c_adap);
1853
1854 u16 apb_address = 0, word;
1855 int i = 0;
1856 switch (msg[0].buf[0]) {
1857 case 0x12:
1858 apb_address = 1920;
1859 break;
1860 case 0x14:
1861 apb_address = 1921;
1862 break;
1863 case 0x24:
1864 apb_address = 1922;
1865 break;
1866 case 0x1a:
1867 apb_address = 1923;
1868 break;
1869 case 0x22:
1870 apb_address = 1924;
1871 break;
1872 case 0x33:
1873 apb_address = 1926;
1874 break;
1875 case 0x34:
1876 apb_address = 1927;
1877 break;
1878 case 0x35:
1879 apb_address = 1928;
1880 break;
1881 case 0x36:
1882 apb_address = 1929;
1883 break;
1884 case 0x37:
1885 apb_address = 1930;
1886 break;
1887 case 0x38:
1888 apb_address = 1931;
1889 break;
1890 case 0x39:
1891 apb_address = 1932;
1892 break;
1893 case 0x2a:
1894 apb_address = 1935;
1895 break;
1896 case 0x2b:
1897 apb_address = 1936;
1898 break;
1899 case 0x2c:
1900 apb_address = 1937;
1901 break;
1902 case 0x2d:
1903 apb_address = 1938;
1904 break;
1905 case 0x2e:
1906 apb_address = 1939;
1907 break;
1908 case 0x2f:
1909 apb_address = 1940;
1910 break;
1911 case 0x30:
1912 apb_address = 1941;
1913 break;
1914 case 0x31:
1915 apb_address = 1942;
1916 break;
1917 case 0x32:
1918 apb_address = 1943;
1919 break;
1920 case 0x3e:
1921 apb_address = 1944;
1922 break;
1923 case 0x3f:
1924 apb_address = 1945;
1925 break;
1926 case 0x40:
1927 apb_address = 1948;
1928 break;
1929 case 0x25:
1930 apb_address = 914;
1931 break;
1932 case 0x26:
1933 apb_address = 915;
1934 break;
1935 case 0x27:
1936 apb_address = 916;
1937 break;
1938 case 0x28:
1939 apb_address = 917;
1940 break;
1941 case 0x1d:
1942 i = ((dib7000p_read_word(state, 72) >> 12) & 0x3);
1943 word = dib7000p_read_word(state, 384 + i);
1944 msg[1].buf[0] = (word >> 8) & 0xff;
1945 msg[1].buf[1] = (word) & 0xff;
1946 return num;
1947 case 0x1f:
1948 if (num == 1) { /* write */
1949 word = (u16) ((msg[0].buf[1] << 8) | msg[0].buf[2]);
1950 word &= 0x3;
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001951 word = (dib7000p_read_word(state, 72) & ~(3 << 12)) | (word << 12);
Olivier Grenie713d54a2011-01-04 04:54:31 -03001952 dib7000p_write_word(state, 72, word); /* Set the proper input */
1953 return num;
1954 }
1955 }
1956
1957 if (apb_address != 0) /* R/W acces via APB */
1958 return dib7090p_rw_on_apb(i2c_adap, msg, num, apb_address);
1959 else /* R/W access via SERPAR */
1960 return w7090p_tuner_rw_serpar(i2c_adap, msg, num);
1961
1962 return 0;
1963}
1964
1965static u32 dib7000p_i2c_func(struct i2c_adapter *adapter)
1966{
1967 return I2C_FUNC_I2C;
1968}
1969
1970static struct i2c_algorithm dib7090_tuner_xfer_algo = {
1971 .master_xfer = dib7090_tuner_xfer,
1972 .functionality = dib7000p_i2c_func,
1973};
1974
1975struct i2c_adapter *dib7090_get_i2c_tuner(struct dvb_frontend *fe)
1976{
1977 struct dib7000p_state *st = fe->demodulator_priv;
1978 return &st->dib7090_tuner_adap;
1979}
1980EXPORT_SYMBOL(dib7090_get_i2c_tuner);
1981
1982static int dib7090_host_bus_drive(struct dib7000p_state *state, u8 drive)
1983{
1984 u16 reg;
1985
1986 /* drive host bus 2, 3, 4 */
1987 reg = dib7000p_read_word(state, 1798) & ~((0x7) | (0x7 << 6) | (0x7 << 12));
1988 reg |= (drive << 12) | (drive << 6) | drive;
1989 dib7000p_write_word(state, 1798, reg);
1990
1991 /* drive host bus 5,6 */
1992 reg = dib7000p_read_word(state, 1799) & ~((0x7 << 2) | (0x7 << 8));
1993 reg |= (drive << 8) | (drive << 2);
1994 dib7000p_write_word(state, 1799, reg);
1995
1996 /* drive host bus 7, 8, 9 */
1997 reg = dib7000p_read_word(state, 1800) & ~((0x7) | (0x7 << 6) | (0x7 << 12));
1998 reg |= (drive << 12) | (drive << 6) | drive;
1999 dib7000p_write_word(state, 1800, reg);
2000
2001 /* drive host bus 10, 11 */
2002 reg = dib7000p_read_word(state, 1801) & ~((0x7 << 2) | (0x7 << 8));
2003 reg |= (drive << 8) | (drive << 2);
2004 dib7000p_write_word(state, 1801, reg);
2005
2006 /* drive host bus 12, 13, 14 */
2007 reg = dib7000p_read_word(state, 1802) & ~((0x7) | (0x7 << 6) | (0x7 << 12));
2008 reg |= (drive << 12) | (drive << 6) | drive;
2009 dib7000p_write_word(state, 1802, reg);
2010
2011 return 0;
2012}
2013
2014static u32 dib7090_calcSyncFreq(u32 P_Kin, u32 P_Kout, u32 insertExtSynchro, u32 syncSize)
2015{
2016 u32 quantif = 3;
2017 u32 nom = (insertExtSynchro * P_Kin + syncSize);
2018 u32 denom = P_Kout;
2019 u32 syncFreq = ((nom << quantif) / denom);
2020
2021 if ((syncFreq & ((1 << quantif) - 1)) != 0)
2022 syncFreq = (syncFreq >> quantif) + 1;
2023 else
2024 syncFreq = (syncFreq >> quantif);
2025
2026 if (syncFreq != 0)
2027 syncFreq = syncFreq - 1;
2028
2029 return syncFreq;
2030}
2031
2032static int dib7090_cfg_DibTx(struct dib7000p_state *state, u32 P_Kin, u32 P_Kout, u32 insertExtSynchro, u32 synchroMode, u32 syncWord, u32 syncSize)
2033{
2034 u8 index_buf;
2035 u16 rx_copy_buf[22];
2036
2037 dprintk("Configure DibStream Tx");
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002038 for (index_buf = 0; index_buf < 22; index_buf++)
Olivier Grenie713d54a2011-01-04 04:54:31 -03002039 rx_copy_buf[index_buf] = dib7000p_read_word(state, 1536+index_buf);
2040
2041 dib7000p_write_word(state, 1615, 1);
2042 dib7000p_write_word(state, 1603, P_Kin);
2043 dib7000p_write_word(state, 1605, P_Kout);
2044 dib7000p_write_word(state, 1606, insertExtSynchro);
2045 dib7000p_write_word(state, 1608, synchroMode);
2046 dib7000p_write_word(state, 1609, (syncWord >> 16) & 0xffff);
2047 dib7000p_write_word(state, 1610, syncWord & 0xffff);
2048 dib7000p_write_word(state, 1612, syncSize);
2049 dib7000p_write_word(state, 1615, 0);
2050
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002051 for (index_buf = 0; index_buf < 22; index_buf++)
Olivier Grenie713d54a2011-01-04 04:54:31 -03002052 dib7000p_write_word(state, 1536+index_buf, rx_copy_buf[index_buf]);
2053
2054 return 0;
2055}
2056
2057static int dib7090_cfg_DibRx(struct dib7000p_state *state, u32 P_Kin, u32 P_Kout, u32 synchroMode, u32 insertExtSynchro, u32 syncWord, u32 syncSize,
2058 u32 dataOutRate)
2059{
2060 u32 syncFreq;
2061
2062 dprintk("Configure DibStream Rx");
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002063 if ((P_Kin != 0) && (P_Kout != 0)) {
Olivier Grenie713d54a2011-01-04 04:54:31 -03002064 syncFreq = dib7090_calcSyncFreq(P_Kin, P_Kout, insertExtSynchro, syncSize);
2065 dib7000p_write_word(state, 1542, syncFreq);
2066 }
2067 dib7000p_write_word(state, 1554, 1);
2068 dib7000p_write_word(state, 1536, P_Kin);
2069 dib7000p_write_word(state, 1537, P_Kout);
2070 dib7000p_write_word(state, 1539, synchroMode);
2071 dib7000p_write_word(state, 1540, (syncWord >> 16) & 0xffff);
2072 dib7000p_write_word(state, 1541, syncWord & 0xffff);
2073 dib7000p_write_word(state, 1543, syncSize);
2074 dib7000p_write_word(state, 1544, dataOutRate);
2075 dib7000p_write_word(state, 1554, 0);
2076
2077 return 0;
2078}
2079
2080static int dib7090_enDivOnHostBus(struct dib7000p_state *state)
2081{
2082 u16 reg;
2083
2084 dprintk("Enable Diversity on host bus");
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002085 reg = (1 << 8) | (1 << 5);
Olivier Grenie713d54a2011-01-04 04:54:31 -03002086 dib7000p_write_word(state, 1288, reg);
2087
2088 return dib7090_cfg_DibTx(state, 5, 5, 0, 0, 0, 0);
2089}
2090
2091static int dib7090_enAdcOnHostBus(struct dib7000p_state *state)
2092{
2093 u16 reg;
2094
2095 dprintk("Enable ADC on host bus");
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002096 reg = (1 << 7) | (1 << 5);
Olivier Grenie713d54a2011-01-04 04:54:31 -03002097 dib7000p_write_word(state, 1288, reg);
2098
2099 return dib7090_cfg_DibTx(state, 20, 5, 10, 0, 0, 0);
2100}
2101
2102static int dib7090_enMpegOnHostBus(struct dib7000p_state *state)
2103{
2104 u16 reg;
2105
2106 dprintk("Enable Mpeg on host bus");
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002107 reg = (1 << 9) | (1 << 5);
Olivier Grenie713d54a2011-01-04 04:54:31 -03002108 dib7000p_write_word(state, 1288, reg);
2109
2110 return dib7090_cfg_DibTx(state, 8, 5, 0, 0, 0, 0);
2111}
2112
2113static int dib7090_enMpegInput(struct dib7000p_state *state)
2114{
2115 dprintk("Enable Mpeg input");
2116 return dib7090_cfg_DibRx(state, 8, 5, 0, 0, 0, 8, 0); /*outputRate = 8 */
2117}
2118
2119static int dib7090_enMpegMux(struct dib7000p_state *state, u16 pulseWidth, u16 enSerialMode, u16 enSerialClkDiv2)
2120{
2121 u16 reg = (1 << 7) | ((pulseWidth & 0x1f) << 2) | ((enSerialMode & 0x1) << 1) | (enSerialClkDiv2 & 0x1);
2122
2123 dprintk("Enable Mpeg mux");
2124 dib7000p_write_word(state, 1287, reg);
2125
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002126 reg &= ~(1 << 7);
Olivier Grenie713d54a2011-01-04 04:54:31 -03002127 dib7000p_write_word(state, 1287, reg);
2128
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002129 reg = (1 << 4);
Olivier Grenie713d54a2011-01-04 04:54:31 -03002130 dib7000p_write_word(state, 1288, reg);
2131
2132 return 0;
2133}
2134
2135static int dib7090_disableMpegMux(struct dib7000p_state *state)
2136{
2137 u16 reg;
2138
2139 dprintk("Disable Mpeg mux");
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002140 dib7000p_write_word(state, 1288, 0);
Olivier Grenie713d54a2011-01-04 04:54:31 -03002141
2142 reg = dib7000p_read_word(state, 1287);
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002143 reg &= ~(1 << 7);
Olivier Grenie713d54a2011-01-04 04:54:31 -03002144 dib7000p_write_word(state, 1287, reg);
2145
2146 return 0;
2147}
2148
2149static int dib7090_set_input_mode(struct dvb_frontend *fe, int mode)
2150{
2151 struct dib7000p_state *state = fe->demodulator_priv;
2152
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002153 switch (mode) {
2154 case INPUT_MODE_DIVERSITY:
Olivier Grenie713d54a2011-01-04 04:54:31 -03002155 dprintk("Enable diversity INPUT");
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002156 dib7090_cfg_DibRx(state, 5, 5, 0, 0, 0, 0, 0);
Olivier Grenie713d54a2011-01-04 04:54:31 -03002157 break;
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002158 case INPUT_MODE_MPEG:
Olivier Grenie713d54a2011-01-04 04:54:31 -03002159 dprintk("Enable Mpeg INPUT");
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002160 dib7090_cfg_DibRx(state, 8, 5, 0, 0, 0, 8, 0); /*outputRate = 8 */
Olivier Grenie713d54a2011-01-04 04:54:31 -03002161 break;
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002162 case INPUT_MODE_OFF:
2163 default:
Olivier Grenie713d54a2011-01-04 04:54:31 -03002164 dprintk("Disable INPUT");
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002165 dib7090_cfg_DibRx(state, 0, 0, 0, 0, 0, 0, 0);
Olivier Grenie713d54a2011-01-04 04:54:31 -03002166 break;
2167 }
2168 return 0;
2169}
2170
2171static int dib7090_set_diversity_in(struct dvb_frontend *fe, int onoff)
2172{
2173 switch (onoff) {
2174 case 0: /* only use the internal way - not the diversity input */
2175 dib7090_set_input_mode(fe, INPUT_MODE_MPEG);
2176 break;
2177 case 1: /* both ways */
2178 case 2: /* only the diversity input */
2179 dib7090_set_input_mode(fe, INPUT_MODE_DIVERSITY);
2180 break;
2181 }
2182
2183 return 0;
2184}
2185
2186static int dib7090_set_output_mode(struct dvb_frontend *fe, int mode)
2187{
2188 struct dib7000p_state *state = fe->demodulator_priv;
2189
2190 u16 outreg, smo_mode, fifo_threshold;
2191 u8 prefer_mpeg_mux_use = 1;
2192 int ret = 0;
2193
2194 dib7090_host_bus_drive(state, 1);
2195
2196 fifo_threshold = 1792;
2197 smo_mode = (dib7000p_read_word(state, 235) & 0x0050) | (1 << 1);
2198 outreg = dib7000p_read_word(state, 1286) & ~((1 << 10) | (0x7 << 6) | (1 << 1));
2199
2200 switch (mode) {
2201 case OUTMODE_HIGH_Z:
2202 outreg = 0;
2203 break;
2204
2205 case OUTMODE_MPEG2_SERIAL:
2206 if (prefer_mpeg_mux_use) {
2207 dprintk("Sip 7090P setting output mode TS_SERIAL using Mpeg Mux");
2208 dib7090_enMpegOnHostBus(state);
2209 dib7090_enMpegInput(state);
2210 if (state->cfg.enMpegOutput == 1)
2211 dib7090_enMpegMux(state, 3, 1, 1);
2212
2213 } else { /* Use Smooth block */
2214 dprintk("Sip 7090P setting output mode TS_SERIAL using Smooth bloc");
2215 dib7090_disableMpegMux(state);
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002216 dib7000p_write_word(state, 1288, (1 << 6));
Olivier Grenie713d54a2011-01-04 04:54:31 -03002217 outreg |= (2 << 6) | (0 << 1);
2218 }
2219 break;
2220
2221 case OUTMODE_MPEG2_PAR_GATED_CLK:
2222 if (prefer_mpeg_mux_use) {
2223 dprintk("Sip 7090P setting output mode TS_PARALLEL_GATED using Mpeg Mux");
2224 dib7090_enMpegOnHostBus(state);
2225 dib7090_enMpegInput(state);
2226 if (state->cfg.enMpegOutput == 1)
2227 dib7090_enMpegMux(state, 2, 0, 0);
2228 } else { /* Use Smooth block */
2229 dprintk("Sip 7090P setting output mode TS_PARALLEL_GATED using Smooth block");
2230 dib7090_disableMpegMux(state);
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002231 dib7000p_write_word(state, 1288, (1 << 6));
Olivier Grenie713d54a2011-01-04 04:54:31 -03002232 outreg |= (0 << 6);
2233 }
2234 break;
2235
2236 case OUTMODE_MPEG2_PAR_CONT_CLK: /* Using Smooth block only */
2237 dprintk("Sip 7090P setting output mode TS_PARALLEL_CONT using Smooth block");
2238 dib7090_disableMpegMux(state);
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002239 dib7000p_write_word(state, 1288, (1 << 6));
Olivier Grenie713d54a2011-01-04 04:54:31 -03002240 outreg |= (1 << 6);
2241 break;
2242
2243 case OUTMODE_MPEG2_FIFO: /* Using Smooth block because not supported by new Mpeg Mux bloc */
2244 dprintk("Sip 7090P setting output mode TS_FIFO using Smooth block");
2245 dib7090_disableMpegMux(state);
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002246 dib7000p_write_word(state, 1288, (1 << 6));
Olivier Grenie713d54a2011-01-04 04:54:31 -03002247 outreg |= (5 << 6);
2248 smo_mode |= (3 << 1);
2249 fifo_threshold = 512;
2250 break;
2251
2252 case OUTMODE_DIVERSITY:
2253 dprintk("Sip 7090P setting output mode MODE_DIVERSITY");
2254 dib7090_disableMpegMux(state);
2255 dib7090_enDivOnHostBus(state);
2256 break;
2257
2258 case OUTMODE_ANALOG_ADC:
2259 dprintk("Sip 7090P setting output mode MODE_ANALOG_ADC");
2260 dib7090_enAdcOnHostBus(state);
2261 break;
2262 }
2263
2264 if (state->cfg.output_mpeg2_in_188_bytes)
2265 smo_mode |= (1 << 5);
2266
2267 ret |= dib7000p_write_word(state, 235, smo_mode);
2268 ret |= dib7000p_write_word(state, 236, fifo_threshold); /* synchronous fread */
2269 ret |= dib7000p_write_word(state, 1286, outreg | (1 << 10)); /* allways set Dout active = 1 !!! */
2270
2271 return ret;
2272}
2273
2274int dib7090_tuner_sleep(struct dvb_frontend *fe, int onoff)
2275{
2276 struct dib7000p_state *state = fe->demodulator_priv;
2277 u16 en_cur_state;
2278
2279 dprintk("sleep dib7090: %d", onoff);
2280
2281 en_cur_state = dib7000p_read_word(state, 1922);
2282
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002283 if (en_cur_state > 0xff)
Olivier Grenie713d54a2011-01-04 04:54:31 -03002284 state->tuner_enable = en_cur_state;
Olivier Grenie713d54a2011-01-04 04:54:31 -03002285
2286 if (onoff)
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002287 en_cur_state &= 0x00ff;
Olivier Grenie713d54a2011-01-04 04:54:31 -03002288 else {
2289 if (state->tuner_enable != 0)
2290 en_cur_state = state->tuner_enable;
2291 }
2292
2293 dib7000p_write_word(state, 1922, en_cur_state);
2294
2295 return 0;
2296}
2297EXPORT_SYMBOL(dib7090_tuner_sleep);
2298
2299int dib7090_agc_restart(struct dvb_frontend *fe, u8 restart)
2300{
2301 dprintk("AGC restart callback: %d", restart);
2302 return 0;
2303}
2304EXPORT_SYMBOL(dib7090_agc_restart);
2305
2306int dib7090_get_adc_power(struct dvb_frontend *fe)
2307{
2308 return dib7000p_get_adc_power(fe);
2309}
2310EXPORT_SYMBOL(dib7090_get_adc_power);
2311
2312int dib7090_slave_reset(struct dvb_frontend *fe)
2313{
2314 struct dib7000p_state *state = fe->demodulator_priv;
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002315 u16 reg;
Olivier Grenie713d54a2011-01-04 04:54:31 -03002316
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002317 reg = dib7000p_read_word(state, 1794);
2318 dib7000p_write_word(state, 1794, reg | (4 << 12));
Olivier Grenie713d54a2011-01-04 04:54:31 -03002319
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002320 dib7000p_write_word(state, 1032, 0xffff);
2321 return 0;
Olivier Grenie713d54a2011-01-04 04:54:31 -03002322}
2323EXPORT_SYMBOL(dib7090_slave_reset);
2324
Patrick Boettchera75763f2006-10-18 08:34:16 -03002325static struct dvb_frontend_ops dib7000p_ops;
Olivier Grenie713d54a2011-01-04 04:54:31 -03002326struct dvb_frontend *dib7000p_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr, struct dib7000p_config *cfg)
Patrick Boettchera75763f2006-10-18 08:34:16 -03002327{
2328 struct dvb_frontend *demod;
2329 struct dib7000p_state *st;
2330 st = kzalloc(sizeof(struct dib7000p_state), GFP_KERNEL);
2331 if (st == NULL)
2332 return NULL;
2333
2334 memcpy(&st->cfg, cfg, sizeof(struct dib7000p_config));
2335 st->i2c_adap = i2c_adap;
2336 st->i2c_addr = i2c_addr;
2337 st->gpio_val = cfg->gpio_val;
2338 st->gpio_dir = cfg->gpio_dir;
2339
Steven Totha38d6e32008-04-22 15:37:01 -03002340 /* Ensure the output mode remains at the previous default if it's
2341 * not specifically set by the caller.
2342 */
Olivier Grenie713d54a2011-01-04 04:54:31 -03002343 if ((st->cfg.output_mode != OUTMODE_MPEG2_SERIAL) && (st->cfg.output_mode != OUTMODE_MPEG2_PAR_GATED_CLK))
Steven Totha38d6e32008-04-22 15:37:01 -03002344 st->cfg.output_mode = OUTMODE_MPEG2_FIFO;
2345
Olivier Grenie713d54a2011-01-04 04:54:31 -03002346 demod = &st->demod;
Patrick Boettchera75763f2006-10-18 08:34:16 -03002347 demod->demodulator_priv = st;
2348 memcpy(&st->demod.ops, &dib7000p_ops, sizeof(struct dvb_frontend_ops));
Patrick Boettcher79fcce32011-08-03 12:08:21 -03002349 mutex_init(&st->i2c_buffer_lock);
Patrick Boettchera75763f2006-10-18 08:34:16 -03002350
Olivier Grenie713d54a2011-01-04 04:54:31 -03002351 dib7000p_write_word(st, 1287, 0x0003); /* sram lead in, rdy */
Olivier Grenieeac1fe12009-09-23 13:41:27 -03002352
Patrick Boettchera75763f2006-10-18 08:34:16 -03002353 if (dib7000p_identify(st) != 0)
2354 goto error;
2355
Olivier Grenie713d54a2011-01-04 04:54:31 -03002356 st->version = dib7000p_read_word(st, 897);
2357
Martin Samek7646b9d2009-09-30 22:59:09 -03002358 /* FIXME: make sure the dev.parent field is initialized, or else
Patrick Boettcher79fcce32011-08-03 12:08:21 -03002359 request_firmware() will hit an OOPS (this should be moved somewhere
2360 more common) */
2361 st->i2c_master.gated_tuner_i2c_adap.dev.parent = i2c_adap->dev.parent;
Martin Samek7646b9d2009-09-30 22:59:09 -03002362
Devin Heitmueller85ec9d72009-07-20 00:45:25 -03002363 /* FIXME: make sure the dev.parent field is initialized, or else
2364 request_firmware() will hit an OOPS (this should be moved somewhere
2365 more common) */
2366 st->i2c_master.gated_tuner_i2c_adap.dev.parent = i2c_adap->dev.parent;
2367
Patrick Boettchera75763f2006-10-18 08:34:16 -03002368 dibx000_init_i2c_master(&st->i2c_master, DIB7000P, st->i2c_adap, st->i2c_addr);
2369
Olivier Grenie713d54a2011-01-04 04:54:31 -03002370 /* init 7090 tuner adapter */
2371 strncpy(st->dib7090_tuner_adap.name, "DiB7090 tuner interface", sizeof(st->dib7090_tuner_adap.name));
2372 st->dib7090_tuner_adap.algo = &dib7090_tuner_xfer_algo;
2373 st->dib7090_tuner_adap.algo_data = NULL;
2374 st->dib7090_tuner_adap.dev.parent = st->i2c_adap->dev.parent;
2375 i2c_set_adapdata(&st->dib7090_tuner_adap, st);
2376 i2c_add_adapter(&st->dib7090_tuner_adap);
2377
Patrick Boettchera75763f2006-10-18 08:34:16 -03002378 dib7000p_demod_reset(st);
2379
Olivier Grenie713d54a2011-01-04 04:54:31 -03002380 if (st->version == SOC7090) {
2381 dib7090_set_output_mode(demod, st->cfg.output_mode);
2382 dib7090_set_diversity_in(demod, 0);
2383 }
2384
Patrick Boettchera75763f2006-10-18 08:34:16 -03002385 return demod;
2386
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002387error:
Patrick Boettchera75763f2006-10-18 08:34:16 -03002388 kfree(st);
2389 return NULL;
2390}
2391EXPORT_SYMBOL(dib7000p_attach);
2392
2393static struct dvb_frontend_ops dib7000p_ops = {
2394 .info = {
Olivier Grenie713d54a2011-01-04 04:54:31 -03002395 .name = "DiBcom 7000PC",
2396 .type = FE_OFDM,
2397 .frequency_min = 44250000,
2398 .frequency_max = 867250000,
2399 .frequency_stepsize = 62500,
2400 .caps = FE_CAN_INVERSION_AUTO |
2401 FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
2402 FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
2403 FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO |
2404 FE_CAN_TRANSMISSION_MODE_AUTO | FE_CAN_GUARD_INTERVAL_AUTO | FE_CAN_RECOVER | FE_CAN_HIERARCHY_AUTO,
2405 },
Patrick Boettchera75763f2006-10-18 08:34:16 -03002406
Olivier Grenie713d54a2011-01-04 04:54:31 -03002407 .release = dib7000p_release,
Patrick Boettchera75763f2006-10-18 08:34:16 -03002408
Olivier Grenie713d54a2011-01-04 04:54:31 -03002409 .init = dib7000p_wakeup,
2410 .sleep = dib7000p_sleep,
Patrick Boettchera75763f2006-10-18 08:34:16 -03002411
Olivier Grenie713d54a2011-01-04 04:54:31 -03002412 .set_frontend = dib7000p_set_frontend,
2413 .get_tune_settings = dib7000p_fe_get_tune_settings,
2414 .get_frontend = dib7000p_get_frontend,
Patrick Boettchera75763f2006-10-18 08:34:16 -03002415
Olivier Grenie713d54a2011-01-04 04:54:31 -03002416 .read_status = dib7000p_read_status,
2417 .read_ber = dib7000p_read_ber,
Patrick Boettchera75763f2006-10-18 08:34:16 -03002418 .read_signal_strength = dib7000p_read_signal_strength,
Olivier Grenie713d54a2011-01-04 04:54:31 -03002419 .read_snr = dib7000p_read_snr,
2420 .read_ucblocks = dib7000p_read_unc_blocks,
Patrick Boettchera75763f2006-10-18 08:34:16 -03002421};
2422
Olivier Grenie713d54a2011-01-04 04:54:31 -03002423MODULE_AUTHOR("Olivier Grenie <ogrenie@dibcom.fr>");
Patrick Boettchera75763f2006-10-18 08:34:16 -03002424MODULE_AUTHOR("Patrick Boettcher <pboettcher@dibcom.fr>");
2425MODULE_DESCRIPTION("Driver for the DiBcom 7000PC COFDM demodulator");
2426MODULE_LICENSE("GPL");