blob: 08e62a4c9603f34c918d245012954d092c0f6bdc [file] [log] [blame]
Patrick Boettchera75763f2006-10-18 08:34:16 -03001/*
2 * Linux-DVB Driver for DiBcom's second generation DiB7000P (PC).
3 *
Patrick Boettcherb6884a12007-07-27 10:08:51 -03004 * Copyright (C) 2005-7 DiBcom (http://www.dibcom.fr/)
Patrick Boettchera75763f2006-10-18 08:34:16 -03005 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License as
8 * published by the Free Software Foundation, version 2.
9 */
10#include <linux/kernel.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090011#include <linux/slab.h>
Patrick Boettchera75763f2006-10-18 08:34:16 -030012#include <linux/i2c.h>
Patrick Boettcher79fcce32011-08-03 12:08:21 -030013#include <linux/mutex.h>
Patrick Boettchera75763f2006-10-18 08:34:16 -030014
Olivier Grenieef801962009-09-15 06:46:52 -030015#include "dvb_math.h"
Patrick Boettchera75763f2006-10-18 08:34:16 -030016#include "dvb_frontend.h"
17
18#include "dib7000p.h"
19
20static int debug;
21module_param(debug, int, 0644);
22MODULE_PARM_DESC(debug, "turn on debugging (default: 0)");
23
Matt Doran8f6956c2007-07-31 07:09:30 -030024static int buggy_sfn_workaround;
25module_param(buggy_sfn_workaround, int, 0644);
Patrick Boettcher8d999962007-07-31 10:36:06 -030026MODULE_PARM_DESC(buggy_sfn_workaround, "Enable work-around for buggy SFNs (default: 0)");
Matt Doran8f6956c2007-07-31 07:09:30 -030027
Patrick Boettcherb6884a12007-07-27 10:08:51 -030028#define dprintk(args...) do { if (debug) { printk(KERN_DEBUG "DiB7000P: "); printk(args); printk("\n"); } } while (0)
Patrick Boettchera75763f2006-10-18 08:34:16 -030029
Olivier Grenie713d54a2011-01-04 04:54:31 -030030struct i2c_device {
31 struct i2c_adapter *i2c_adap;
32 u8 i2c_addr;
33};
34
Patrick Boettchera75763f2006-10-18 08:34:16 -030035struct dib7000p_state {
36 struct dvb_frontend demod;
Olivier Grenie713d54a2011-01-04 04:54:31 -030037 struct dib7000p_config cfg;
Patrick Boettchera75763f2006-10-18 08:34:16 -030038
39 u8 i2c_addr;
Olivier Grenie713d54a2011-01-04 04:54:31 -030040 struct i2c_adapter *i2c_adap;
Patrick Boettchera75763f2006-10-18 08:34:16 -030041
42 struct dibx000_i2c_master i2c_master;
43
44 u16 wbd_ref;
45
Olivier Grenie713d54a2011-01-04 04:54:31 -030046 u8 current_band;
Patrick Boettcher904a82e2008-01-25 07:31:58 -030047 u32 current_bandwidth;
Patrick Boettchera75763f2006-10-18 08:34:16 -030048 struct dibx000_agc_config *current_agc;
49 u32 timf;
50
Olivier Grenie713d54a2011-01-04 04:54:31 -030051 u8 div_force_off:1;
52 u8 div_state:1;
Patrick Boettcher01373a52007-07-30 12:49:04 -030053 u16 div_sync_wait;
Patrick Boettcherb6884a12007-07-27 10:08:51 -030054
55 u8 agc_state;
56
Patrick Boettchera75763f2006-10-18 08:34:16 -030057 u16 gpio_dir;
58 u16 gpio_val;
Matt Doran8f6956c2007-07-31 07:09:30 -030059
Olivier Grenie713d54a2011-01-04 04:54:31 -030060 u8 sfn_workaround_active:1;
61
62#define SOC7090 0x7090
63 u16 version;
64
65 u16 tuner_enable;
66 struct i2c_adapter dib7090_tuner_adap;
Olivier Grenie5a0deee2011-05-03 12:27:33 -030067
68 /* for the I2C transfer */
69 struct i2c_msg msg[2];
70 u8 i2c_write_buffer[4];
71 u8 i2c_read_buffer[2];
Patrick Boettcher79fcce32011-08-03 12:08:21 -030072 struct mutex i2c_buffer_lock;
Olivier Grenie2e802862011-08-05 10:39:15 -030073
74 u8 input_mode_mpeg;
Patrick Boettchera75763f2006-10-18 08:34:16 -030075};
76
77enum dib7000p_power_mode {
78 DIB7000P_POWER_ALL = 0,
Patrick Boettcherb6884a12007-07-27 10:08:51 -030079 DIB7000P_POWER_ANALOG_ADC,
Patrick Boettchera75763f2006-10-18 08:34:16 -030080 DIB7000P_POWER_INTERFACE_ONLY,
81};
82
Olivier Grenie2e802862011-08-05 10:39:15 -030083/* dib7090 specific fonctions */
84#define MPEG_ON_DIBTX 1
85#define DIV_ON_DIBTX 2
86#define ADC_ON_DIBTX 3
87#define DEMOUT_ON_HOSTBUS 4
88#define DIBTX_ON_HOSTBUS 5
89#define MPEG_ON_HOSTBUS 6
90
Olivier Grenie713d54a2011-01-04 04:54:31 -030091static int dib7090_set_output_mode(struct dvb_frontend *fe, int mode);
92static int dib7090_set_diversity_in(struct dvb_frontend *fe, int onoff);
Olivier Grenie2e802862011-08-05 10:39:15 -030093static void dib7090_setDibTxMux(struct dib7000p_state *state, int mode);
94static void dib7090_setHostBusMux(struct dib7000p_state *state, int mode);
Olivier Grenie713d54a2011-01-04 04:54:31 -030095
Patrick Boettchera75763f2006-10-18 08:34:16 -030096static u16 dib7000p_read_word(struct dib7000p_state *state, u16 reg)
97{
Patrick Boettcher79fcce32011-08-03 12:08:21 -030098 u16 ret;
99
100 if (mutex_lock_interruptible(&state->i2c_buffer_lock) < 0) {
101 dprintk("could not acquire lock");
102 return 0;
103 }
104
Olivier Grenie5a0deee2011-05-03 12:27:33 -0300105 state->i2c_write_buffer[0] = reg >> 8;
106 state->i2c_write_buffer[1] = reg & 0xff;
Patrick Boettchera75763f2006-10-18 08:34:16 -0300107
Olivier Grenie5a0deee2011-05-03 12:27:33 -0300108 memset(state->msg, 0, 2 * sizeof(struct i2c_msg));
109 state->msg[0].addr = state->i2c_addr >> 1;
110 state->msg[0].flags = 0;
111 state->msg[0].buf = state->i2c_write_buffer;
112 state->msg[0].len = 2;
113 state->msg[1].addr = state->i2c_addr >> 1;
114 state->msg[1].flags = I2C_M_RD;
115 state->msg[1].buf = state->i2c_read_buffer;
116 state->msg[1].len = 2;
117
118 if (i2c_transfer(state->i2c_adap, state->msg, 2) != 2)
Olivier Grenie713d54a2011-01-04 04:54:31 -0300119 dprintk("i2c read error on %d", reg);
Patrick Boettchera75763f2006-10-18 08:34:16 -0300120
Patrick Boettcher79fcce32011-08-03 12:08:21 -0300121 ret = (state->i2c_read_buffer[0] << 8) | state->i2c_read_buffer[1];
122 mutex_unlock(&state->i2c_buffer_lock);
123 return ret;
Patrick Boettchera75763f2006-10-18 08:34:16 -0300124}
125
126static int dib7000p_write_word(struct dib7000p_state *state, u16 reg, u16 val)
127{
Patrick Boettcher79fcce32011-08-03 12:08:21 -0300128 int ret;
129
130 if (mutex_lock_interruptible(&state->i2c_buffer_lock) < 0) {
131 dprintk("could not acquire lock");
132 return -EINVAL;
133 }
134
Olivier Grenie5a0deee2011-05-03 12:27:33 -0300135 state->i2c_write_buffer[0] = (reg >> 8) & 0xff;
136 state->i2c_write_buffer[1] = reg & 0xff;
137 state->i2c_write_buffer[2] = (val >> 8) & 0xff;
138 state->i2c_write_buffer[3] = val & 0xff;
139
140 memset(&state->msg[0], 0, sizeof(struct i2c_msg));
141 state->msg[0].addr = state->i2c_addr >> 1;
142 state->msg[0].flags = 0;
143 state->msg[0].buf = state->i2c_write_buffer;
144 state->msg[0].len = 4;
145
Patrick Boettcher79fcce32011-08-03 12:08:21 -0300146 ret = (i2c_transfer(state->i2c_adap, state->msg, 1) != 1 ?
147 -EREMOTEIO : 0);
148 mutex_unlock(&state->i2c_buffer_lock);
149 return ret;
Patrick Boettchera75763f2006-10-18 08:34:16 -0300150}
Olivier Grenie713d54a2011-01-04 04:54:31 -0300151
152static void dib7000p_write_tab(struct dib7000p_state *state, u16 * buf)
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300153{
154 u16 l = 0, r, *n;
155 n = buf;
156 l = *n++;
157 while (l) {
158 r = *n++;
159
160 do {
161 dib7000p_write_word(state, r, *n++);
162 r++;
163 } while (--l);
164 l = *n++;
165 }
166}
167
Patrick Boettchera75763f2006-10-18 08:34:16 -0300168static int dib7000p_set_output_mode(struct dib7000p_state *state, int mode)
169{
Olivier Grenie713d54a2011-01-04 04:54:31 -0300170 int ret = 0;
Patrick Boettchera75763f2006-10-18 08:34:16 -0300171 u16 outreg, fifo_threshold, smo_mode;
172
173 outreg = 0;
174 fifo_threshold = 1792;
Olivier Grenieeac1fe12009-09-23 13:41:27 -0300175 smo_mode = (dib7000p_read_word(state, 235) & 0x0050) | (1 << 1);
Patrick Boettchera75763f2006-10-18 08:34:16 -0300176
Olivier Grenie713d54a2011-01-04 04:54:31 -0300177 dprintk("setting output mode for demod %p to %d", &state->demod, mode);
Patrick Boettchera75763f2006-10-18 08:34:16 -0300178
179 switch (mode) {
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300180 case OUTMODE_MPEG2_PAR_GATED_CLK:
Olivier Grenie713d54a2011-01-04 04:54:31 -0300181 outreg = (1 << 10); /* 0x0400 */
182 break;
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300183 case OUTMODE_MPEG2_PAR_CONT_CLK:
Olivier Grenie713d54a2011-01-04 04:54:31 -0300184 outreg = (1 << 10) | (1 << 6); /* 0x0440 */
185 break;
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300186 case OUTMODE_MPEG2_SERIAL:
Olivier Grenie713d54a2011-01-04 04:54:31 -0300187 outreg = (1 << 10) | (2 << 6) | (0 << 1); /* 0x0480 */
188 break;
189 case OUTMODE_DIVERSITY:
190 if (state->cfg.hostbus_diversity)
191 outreg = (1 << 10) | (4 << 6); /* 0x0500 */
192 else
193 outreg = (1 << 11);
194 break;
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300195 case OUTMODE_MPEG2_FIFO:
Olivier Grenie713d54a2011-01-04 04:54:31 -0300196 smo_mode |= (3 << 1);
197 fifo_threshold = 512;
198 outreg = (1 << 10) | (5 << 6);
199 break;
200 case OUTMODE_ANALOG_ADC:
201 outreg = (1 << 10) | (3 << 6);
202 break;
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300203 case OUTMODE_HIGH_Z:
Olivier Grenie713d54a2011-01-04 04:54:31 -0300204 outreg = 0;
205 break;
206 default:
207 dprintk("Unhandled output_mode passed to be set for demod %p", &state->demod);
208 break;
Patrick Boettchera75763f2006-10-18 08:34:16 -0300209 }
210
211 if (state->cfg.output_mpeg2_in_188_bytes)
Olivier Grenie713d54a2011-01-04 04:54:31 -0300212 smo_mode |= (1 << 5);
Patrick Boettchera75763f2006-10-18 08:34:16 -0300213
Olivier Grenie713d54a2011-01-04 04:54:31 -0300214 ret |= dib7000p_write_word(state, 235, smo_mode);
215 ret |= dib7000p_write_word(state, 236, fifo_threshold); /* synchronous fread */
216 if (state->version != SOC7090)
217 ret |= dib7000p_write_word(state, 1286, outreg); /* P_Div_active */
Patrick Boettchera75763f2006-10-18 08:34:16 -0300218
219 return ret;
220}
221
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300222static int dib7000p_set_diversity_in(struct dvb_frontend *demod, int onoff)
223{
224 struct dib7000p_state *state = demod->demodulator_priv;
225
226 if (state->div_force_off) {
Olivier Grenie713d54a2011-01-04 04:54:31 -0300227 dprintk("diversity combination deactivated - forced by COFDM parameters");
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300228 onoff = 0;
Olivier Grenieeac1fe12009-09-23 13:41:27 -0300229 dib7000p_write_word(state, 207, 0);
230 } else
231 dib7000p_write_word(state, 207, (state->div_sync_wait << 4) | (1 << 2) | (2 << 0));
232
Olivier Grenie713d54a2011-01-04 04:54:31 -0300233 state->div_state = (u8) onoff;
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300234
235 if (onoff) {
236 dib7000p_write_word(state, 204, 6);
237 dib7000p_write_word(state, 205, 16);
238 /* P_dvsy_sync_mode = 0, P_dvsy_sync_enable=1, P_dvcb_comb_mode=2 */
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300239 } else {
240 dib7000p_write_word(state, 204, 1);
241 dib7000p_write_word(state, 205, 0);
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300242 }
243
244 return 0;
245}
246
Patrick Boettchera75763f2006-10-18 08:34:16 -0300247static int dib7000p_set_power_mode(struct dib7000p_state *state, enum dib7000p_power_mode mode)
248{
249 /* by default everything is powered off */
Olivier Grenie713d54a2011-01-04 04:54:31 -0300250 u16 reg_774 = 0x3fff, reg_775 = 0xffff, reg_776 = 0x0007, reg_899 = 0x0003, reg_1280 = (0xfe00) | (dib7000p_read_word(state, 1280) & 0x01ff);
Patrick Boettchera75763f2006-10-18 08:34:16 -0300251
252 /* now, depending on the requested mode, we power on */
253 switch (mode) {
254 /* power up everything in the demod */
Olivier Grenie713d54a2011-01-04 04:54:31 -0300255 case DIB7000P_POWER_ALL:
256 reg_774 = 0x0000;
257 reg_775 = 0x0000;
258 reg_776 = 0x0;
259 reg_899 = 0x0;
260 if (state->version == SOC7090)
261 reg_1280 &= 0x001f;
262 else
263 reg_1280 &= 0x01ff;
264 break;
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300265
Olivier Grenie713d54a2011-01-04 04:54:31 -0300266 case DIB7000P_POWER_ANALOG_ADC:
267 /* dem, cfg, iqc, sad, agc */
268 reg_774 &= ~((1 << 15) | (1 << 14) | (1 << 11) | (1 << 10) | (1 << 9));
269 /* nud */
270 reg_776 &= ~((1 << 0));
271 /* Dout */
272 if (state->version != SOC7090)
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300273 reg_1280 &= ~((1 << 11));
Olivier Grenie713d54a2011-01-04 04:54:31 -0300274 reg_1280 &= ~(1 << 6);
275 /* fall through wanted to enable the interfaces */
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300276
Patrick Boettchera75763f2006-10-18 08:34:16 -0300277 /* just leave power on the control-interfaces: GPIO and (I2C or SDIO) */
Olivier Grenie713d54a2011-01-04 04:54:31 -0300278 case DIB7000P_POWER_INTERFACE_ONLY: /* TODO power up either SDIO or I2C */
279 if (state->version == SOC7090)
280 reg_1280 &= ~((1 << 7) | (1 << 5));
281 else
Patrick Boettchera75763f2006-10-18 08:34:16 -0300282 reg_1280 &= ~((1 << 14) | (1 << 13) | (1 << 12) | (1 << 10));
Olivier Grenie713d54a2011-01-04 04:54:31 -0300283 break;
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300284
Patrick Boettchera75763f2006-10-18 08:34:16 -0300285/* TODO following stuff is just converted from the dib7000-driver - check when is used what */
286 }
287
Olivier Grenie713d54a2011-01-04 04:54:31 -0300288 dib7000p_write_word(state, 774, reg_774);
289 dib7000p_write_word(state, 775, reg_775);
290 dib7000p_write_word(state, 776, reg_776);
Patrick Boettchera75763f2006-10-18 08:34:16 -0300291 dib7000p_write_word(state, 1280, reg_1280);
Olivier Grenie2e802862011-08-05 10:39:15 -0300292 if (state->version != SOC7090)
293 dib7000p_write_word(state, 899, reg_899);
Patrick Boettchera75763f2006-10-18 08:34:16 -0300294
295 return 0;
296}
297
298static void dib7000p_set_adc_state(struct dib7000p_state *state, enum dibx000_adc_states no)
299{
Olivier Grenie2e802862011-08-05 10:39:15 -0300300 u16 reg_908 = 0, reg_909 = 0;
Olivier Grenie713d54a2011-01-04 04:54:31 -0300301 u16 reg;
Patrick Boettchera75763f2006-10-18 08:34:16 -0300302
Olivier Grenie2e802862011-08-05 10:39:15 -0300303 if (state->version != SOC7090) {
304 reg_908 = dib7000p_read_word(state, 908);
305 reg_909 = dib7000p_read_word(state, 909);
306 }
307
Patrick Boettchera75763f2006-10-18 08:34:16 -0300308 switch (no) {
Olivier Grenie713d54a2011-01-04 04:54:31 -0300309 case DIBX000_SLOW_ADC_ON:
310 if (state->version == SOC7090) {
311 reg = dib7000p_read_word(state, 1925);
312
313 dib7000p_write_word(state, 1925, reg | (1 << 4) | (1 << 2)); /* en_slowAdc = 1 & reset_sladc = 1 */
314
315 reg = dib7000p_read_word(state, 1925); /* read acces to make it works... strange ... */
316 msleep(200);
317 dib7000p_write_word(state, 1925, reg & ~(1 << 4)); /* en_slowAdc = 1 & reset_sladc = 0 */
318
319 reg = dib7000p_read_word(state, 72) & ~((0x3 << 14) | (0x3 << 12));
320 dib7000p_write_word(state, 72, reg | (1 << 14) | (3 << 12) | 524); /* ref = Vin1 => Vbg ; sel = Vin0 or Vin3 ; (Vin2 = Vcm) */
321 } else {
Patrick Boettchera75763f2006-10-18 08:34:16 -0300322 reg_909 |= (1 << 1) | (1 << 0);
323 dib7000p_write_word(state, 909, reg_909);
324 reg_909 &= ~(1 << 1);
Olivier Grenie713d54a2011-01-04 04:54:31 -0300325 }
326 break;
Patrick Boettchera75763f2006-10-18 08:34:16 -0300327
Olivier Grenie713d54a2011-01-04 04:54:31 -0300328 case DIBX000_SLOW_ADC_OFF:
329 if (state->version == SOC7090) {
330 reg = dib7000p_read_word(state, 1925);
331 dib7000p_write_word(state, 1925, (reg & ~(1 << 2)) | (1 << 4)); /* reset_sladc = 1 en_slowAdc = 0 */
332 } else
333 reg_909 |= (1 << 1) | (1 << 0);
334 break;
Patrick Boettchera75763f2006-10-18 08:34:16 -0300335
Olivier Grenie713d54a2011-01-04 04:54:31 -0300336 case DIBX000_ADC_ON:
337 reg_908 &= 0x0fff;
338 reg_909 &= 0x0003;
339 break;
Patrick Boettchera75763f2006-10-18 08:34:16 -0300340
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300341 case DIBX000_ADC_OFF:
Olivier Grenie713d54a2011-01-04 04:54:31 -0300342 reg_908 |= (1 << 14) | (1 << 13) | (1 << 12);
343 reg_909 |= (1 << 5) | (1 << 4) | (1 << 3) | (1 << 2);
344 break;
Patrick Boettchera75763f2006-10-18 08:34:16 -0300345
Olivier Grenie713d54a2011-01-04 04:54:31 -0300346 case DIBX000_VBG_ENABLE:
347 reg_908 &= ~(1 << 15);
348 break;
Patrick Boettchera75763f2006-10-18 08:34:16 -0300349
Olivier Grenie713d54a2011-01-04 04:54:31 -0300350 case DIBX000_VBG_DISABLE:
351 reg_908 |= (1 << 15);
352 break;
Patrick Boettchera75763f2006-10-18 08:34:16 -0300353
Olivier Grenie713d54a2011-01-04 04:54:31 -0300354 default:
355 break;
Patrick Boettchera75763f2006-10-18 08:34:16 -0300356 }
357
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300358// dprintk( "908: %x, 909: %x\n", reg_908, reg_909);
Patrick Boettchera75763f2006-10-18 08:34:16 -0300359
Olivier Grenie970d14c2010-09-07 12:50:46 -0300360 reg_909 |= (state->cfg.disable_sample_and_hold & 1) << 4;
Olivier Grenie90e12ce2010-09-07 12:50:45 -0300361 reg_908 |= (state->cfg.enable_current_mirror & 1) << 7;
362
Olivier Grenie2e802862011-08-05 10:39:15 -0300363 if (state->version != SOC7090) {
364 dib7000p_write_word(state, 908, reg_908);
365 dib7000p_write_word(state, 909, reg_909);
366 }
Patrick Boettchera75763f2006-10-18 08:34:16 -0300367}
368
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300369static int dib7000p_set_bandwidth(struct dib7000p_state *state, u32 bw)
Patrick Boettchera75763f2006-10-18 08:34:16 -0300370{
Patrick Boettchera75763f2006-10-18 08:34:16 -0300371 u32 timf;
372
373 // store the current bandwidth for later use
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300374 state->current_bandwidth = bw;
Patrick Boettchera75763f2006-10-18 08:34:16 -0300375
376 if (state->timf == 0) {
Olivier Grenie713d54a2011-01-04 04:54:31 -0300377 dprintk("using default timf");
Patrick Boettchera75763f2006-10-18 08:34:16 -0300378 timf = state->cfg.bw->timf;
379 } else {
Olivier Grenie713d54a2011-01-04 04:54:31 -0300380 dprintk("using updated timf");
Patrick Boettchera75763f2006-10-18 08:34:16 -0300381 timf = state->timf;
382 }
383
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300384 timf = timf * (bw / 50) / 160;
Patrick Boettchera75763f2006-10-18 08:34:16 -0300385
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300386 dib7000p_write_word(state, 23, (u16) ((timf >> 16) & 0xffff));
Olivier Grenie713d54a2011-01-04 04:54:31 -0300387 dib7000p_write_word(state, 24, (u16) ((timf) & 0xffff));
Patrick Boettchera75763f2006-10-18 08:34:16 -0300388
389 return 0;
390}
391
392static int dib7000p_sad_calib(struct dib7000p_state *state)
393{
394/* internal */
Patrick Boettchera75763f2006-10-18 08:34:16 -0300395 dib7000p_write_word(state, 73, (0 << 1) | (0 << 0));
Olivier Grenie713d54a2011-01-04 04:54:31 -0300396
397 if (state->version == SOC7090)
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300398 dib7000p_write_word(state, 74, 2048);
Olivier Grenie713d54a2011-01-04 04:54:31 -0300399 else
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300400 dib7000p_write_word(state, 74, 776);
Patrick Boettchera75763f2006-10-18 08:34:16 -0300401
402 /* do the calibration */
403 dib7000p_write_word(state, 73, (1 << 0));
404 dib7000p_write_word(state, 73, (0 << 0));
405
406 msleep(1);
407
408 return 0;
409}
410
Patrick Boettcher01373a52007-07-30 12:49:04 -0300411int dib7000p_set_wbd_ref(struct dvb_frontend *demod, u16 value)
412{
413 struct dib7000p_state *state = demod->demodulator_priv;
414 if (value > 4095)
415 value = 4095;
416 state->wbd_ref = value;
417 return dib7000p_write_word(state, 105, (dib7000p_read_word(state, 105) & 0xf000) | value);
418}
Patrick Boettcher01373a52007-07-30 12:49:04 -0300419EXPORT_SYMBOL(dib7000p_set_wbd_ref);
Olivier Grenie713d54a2011-01-04 04:54:31 -0300420
Patrick Boettchera75763f2006-10-18 08:34:16 -0300421static void dib7000p_reset_pll(struct dib7000p_state *state)
422{
423 struct dibx000_bandwidth_config *bw = &state->cfg.bw[0];
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300424 u16 clk_cfg0;
Patrick Boettchera75763f2006-10-18 08:34:16 -0300425
Olivier Grenie713d54a2011-01-04 04:54:31 -0300426 if (state->version == SOC7090) {
427 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 -0300428
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300429 while (((dib7000p_read_word(state, 1856) >> 15) & 0x1) != 1)
430 ;
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300431
Olivier Grenie713d54a2011-01-04 04:54:31 -0300432 dib7000p_write_word(state, 1857, dib7000p_read_word(state, 1857) | (!bw->pll_bypass << 15));
433 } else {
434 /* force PLL bypass */
435 clk_cfg0 = (1 << 15) | ((bw->pll_ratio & 0x3f) << 9) |
436 (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 -0300437
Olivier Grenie713d54a2011-01-04 04:54:31 -0300438 dib7000p_write_word(state, 900, clk_cfg0);
439
440 /* P_pll_cfg */
441 dib7000p_write_word(state, 903, (bw->pll_prediv << 5) | (((bw->pll_ratio >> 6) & 0x3) << 3) | (bw->pll_range << 1) | bw->pll_reset);
442 clk_cfg0 = (bw->pll_bypass << 15) | (clk_cfg0 & 0x7fff);
443 dib7000p_write_word(state, 900, clk_cfg0);
444 }
445
446 dib7000p_write_word(state, 18, (u16) (((bw->internal * 1000) >> 16) & 0xffff));
447 dib7000p_write_word(state, 19, (u16) ((bw->internal * 1000) & 0xffff));
448 dib7000p_write_word(state, 21, (u16) ((bw->ifreq >> 16) & 0xffff));
449 dib7000p_write_word(state, 22, (u16) ((bw->ifreq) & 0xffff));
Patrick Boettchera75763f2006-10-18 08:34:16 -0300450
451 dib7000p_write_word(state, 72, bw->sad_cfg);
452}
453
Olivier Grenie713d54a2011-01-04 04:54:31 -0300454static u32 dib7000p_get_internal_freq(struct dib7000p_state *state)
455{
456 u32 internal = (u32) dib7000p_read_word(state, 18) << 16;
457 internal |= (u32) dib7000p_read_word(state, 19);
458 internal /= 1000;
459
460 return internal;
461}
462
463int dib7000p_update_pll(struct dvb_frontend *fe, struct dibx000_bandwidth_config *bw)
464{
465 struct dib7000p_state *state = fe->demodulator_priv;
466 u16 reg_1857, reg_1856 = dib7000p_read_word(state, 1856);
467 u8 loopdiv, prediv;
468 u32 internal, xtal;
469
470 /* get back old values */
471 prediv = reg_1856 & 0x3f;
472 loopdiv = (reg_1856 >> 6) & 0x3f;
473
474 if ((bw != NULL) && (bw->pll_prediv != prediv || bw->pll_ratio != loopdiv)) {
475 dprintk("Updating pll (prediv: old = %d new = %d ; loopdiv : old = %d new = %d)", prediv, bw->pll_prediv, loopdiv, bw->pll_ratio);
476 reg_1856 &= 0xf000;
477 reg_1857 = dib7000p_read_word(state, 1857);
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300478 dib7000p_write_word(state, 1857, reg_1857 & ~(1 << 15));
Olivier Grenie713d54a2011-01-04 04:54:31 -0300479
480 dib7000p_write_word(state, 1856, reg_1856 | ((bw->pll_ratio & 0x3f) << 6) | (bw->pll_prediv & 0x3f));
481
482 /* write new system clk into P_sec_len */
483 internal = dib7000p_get_internal_freq(state);
484 xtal = (internal / loopdiv) * prediv;
485 internal = 1000 * (xtal / bw->pll_prediv) * bw->pll_ratio; /* new internal */
486 dib7000p_write_word(state, 18, (u16) ((internal >> 16) & 0xffff));
487 dib7000p_write_word(state, 19, (u16) (internal & 0xffff));
488
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300489 dib7000p_write_word(state, 1857, reg_1857 | (1 << 15));
Olivier Grenie713d54a2011-01-04 04:54:31 -0300490
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300491 while (((dib7000p_read_word(state, 1856) >> 15) & 0x1) != 1)
Olivier Grenie713d54a2011-01-04 04:54:31 -0300492 dprintk("Waiting for PLL to lock");
Olivier Grenie713d54a2011-01-04 04:54:31 -0300493
494 return 0;
495 }
496 return -EIO;
497}
498EXPORT_SYMBOL(dib7000p_update_pll);
499
Patrick Boettchera75763f2006-10-18 08:34:16 -0300500static int dib7000p_reset_gpio(struct dib7000p_state *st)
501{
502 /* reset the GPIOs */
Olivier Grenie713d54a2011-01-04 04:54:31 -0300503 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 -0300504
505 dib7000p_write_word(st, 1029, st->gpio_dir);
506 dib7000p_write_word(st, 1030, st->gpio_val);
507
508 /* TODO 1031 is P_gpio_od */
509
510 dib7000p_write_word(st, 1032, st->cfg.gpio_pwm_pos);
511
512 dib7000p_write_word(st, 1037, st->cfg.pwm_freq_div);
513 return 0;
514}
515
Patrick Boettcher01373a52007-07-30 12:49:04 -0300516static int dib7000p_cfg_gpio(struct dib7000p_state *st, u8 num, u8 dir, u8 val)
517{
518 st->gpio_dir = dib7000p_read_word(st, 1029);
Olivier Grenie713d54a2011-01-04 04:54:31 -0300519 st->gpio_dir &= ~(1 << num); /* reset the direction bit */
520 st->gpio_dir |= (dir & 0x1) << num; /* set the new direction */
Patrick Boettcher01373a52007-07-30 12:49:04 -0300521 dib7000p_write_word(st, 1029, st->gpio_dir);
522
523 st->gpio_val = dib7000p_read_word(st, 1030);
Olivier Grenie713d54a2011-01-04 04:54:31 -0300524 st->gpio_val &= ~(1 << num); /* reset the direction bit */
525 st->gpio_val |= (val & 0x01) << num; /* set the new value */
Patrick Boettcher01373a52007-07-30 12:49:04 -0300526 dib7000p_write_word(st, 1030, st->gpio_val);
527
528 return 0;
529}
530
531int dib7000p_set_gpio(struct dvb_frontend *demod, u8 num, u8 dir, u8 val)
532{
533 struct dib7000p_state *state = demod->demodulator_priv;
534 return dib7000p_cfg_gpio(state, num, dir, val);
535}
Patrick Boettcher01373a52007-07-30 12:49:04 -0300536EXPORT_SYMBOL(dib7000p_set_gpio);
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300537
Olivier Grenie713d54a2011-01-04 04:54:31 -0300538static u16 dib7000p_defaults[] = {
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300539 // auto search configuration
540 3, 2,
Olivier Grenie713d54a2011-01-04 04:54:31 -0300541 0x0004,
Olivier Grenie2e802862011-08-05 10:39:15 -0300542 (1<<3)|(1<<11)|(1<<12)|(1<<13),
Olivier Grenie713d54a2011-01-04 04:54:31 -0300543 0x0814, /* Equal Lock */
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300544
545 12, 6,
Olivier Grenie713d54a2011-01-04 04:54:31 -0300546 0x001b,
547 0x7740,
548 0x005b,
549 0x8d80,
550 0x01c9,
551 0xc380,
552 0x0000,
553 0x0080,
554 0x0000,
555 0x0090,
556 0x0001,
557 0xd4c0,
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300558
559 1, 26,
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300560 0x6680,
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300561
562 /* set ADC level to -16 */
563 11, 79,
Olivier Grenie713d54a2011-01-04 04:54:31 -0300564 (1 << 13) - 825 - 117,
565 (1 << 13) - 837 - 117,
566 (1 << 13) - 811 - 117,
567 (1 << 13) - 766 - 117,
568 (1 << 13) - 737 - 117,
569 (1 << 13) - 693 - 117,
570 (1 << 13) - 648 - 117,
571 (1 << 13) - 619 - 117,
572 (1 << 13) - 575 - 117,
573 (1 << 13) - 531 - 117,
574 (1 << 13) - 501 - 117,
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300575
576 1, 142,
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300577 0x0410,
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300578
579 /* disable power smoothing */
580 8, 145,
Olivier Grenie713d54a2011-01-04 04:54:31 -0300581 0,
582 0,
583 0,
584 0,
585 0,
586 0,
587 0,
588 0,
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300589
590 1, 154,
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300591 1 << 13,
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300592
593 1, 168,
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300594 0x0ccd,
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300595
596 1, 183,
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300597 0x200f,
Olivier Grenie713d54a2011-01-04 04:54:31 -0300598
599 1, 212,
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300600 0x169,
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300601
602 5, 187,
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300603 0x023d,
604 0x00a4,
605 0x00a4,
606 0x7ff0,
607 0x3ccc,
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300608
609 1, 198,
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300610 0x800,
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300611
612 1, 222,
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300613 0x0010,
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300614
615 1, 235,
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300616 0x0062,
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300617
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300618 0,
619};
620
Patrick Boettchera75763f2006-10-18 08:34:16 -0300621static int dib7000p_demod_reset(struct dib7000p_state *state)
622{
623 dib7000p_set_power_mode(state, DIB7000P_POWER_ALL);
624
Olivier Grenie713d54a2011-01-04 04:54:31 -0300625 if (state->version == SOC7090)
626 dibx000_reset_i2c_master(&state->i2c_master);
627
Patrick Boettchera75763f2006-10-18 08:34:16 -0300628 dib7000p_set_adc_state(state, DIBX000_VBG_ENABLE);
629
630 /* restart all parts */
Olivier Grenie713d54a2011-01-04 04:54:31 -0300631 dib7000p_write_word(state, 770, 0xffff);
632 dib7000p_write_word(state, 771, 0xffff);
633 dib7000p_write_word(state, 772, 0x001f);
Olivier Grenie713d54a2011-01-04 04:54:31 -0300634 dib7000p_write_word(state, 1280, 0x001f - ((1 << 4) | (1 << 3)));
Patrick Boettchera75763f2006-10-18 08:34:16 -0300635
Olivier Grenie713d54a2011-01-04 04:54:31 -0300636 dib7000p_write_word(state, 770, 0);
637 dib7000p_write_word(state, 771, 0);
638 dib7000p_write_word(state, 772, 0);
Patrick Boettchera75763f2006-10-18 08:34:16 -0300639 dib7000p_write_word(state, 1280, 0);
640
Olivier Grenie2e802862011-08-05 10:39:15 -0300641 if (state->version != SOC7090) {
642 dib7000p_write_word(state, 898, 0x0003);
643 dib7000p_write_word(state, 898, 0);
644 }
645
Patrick Boettchera75763f2006-10-18 08:34:16 -0300646 /* default */
647 dib7000p_reset_pll(state);
648
649 if (dib7000p_reset_gpio(state) != 0)
Olivier Grenie713d54a2011-01-04 04:54:31 -0300650 dprintk("GPIO reset was not successful.");
Patrick Boettchera75763f2006-10-18 08:34:16 -0300651
Olivier Grenie713d54a2011-01-04 04:54:31 -0300652 if (state->version == SOC7090) {
653 dib7000p_write_word(state, 899, 0);
654
655 /* impulse noise */
656 dib7000p_write_word(state, 42, (1<<5) | 3); /* P_iqc_thsat_ipc = 1 ; P_iqc_win2 = 3 */
657 dib7000p_write_word(state, 43, 0x2d4); /*-300 fag P_iqc_dect_min = -280 */
658 dib7000p_write_word(state, 44, 300); /* 300 fag P_iqc_dect_min = +280 */
Olivier Grenie2e802862011-08-05 10:39:15 -0300659 dib7000p_write_word(state, 273, (0<<6) | 30);
Olivier Grenie713d54a2011-01-04 04:54:31 -0300660 }
Patrick Boettchera75763f2006-10-18 08:34:16 -0300661 if (dib7000p_set_output_mode(state, OUTMODE_HIGH_Z) != 0)
Olivier Grenie713d54a2011-01-04 04:54:31 -0300662 dprintk("OUTPUT_MODE could not be reset.");
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300663
664 dib7000p_set_adc_state(state, DIBX000_SLOW_ADC_ON);
665 dib7000p_sad_calib(state);
666 dib7000p_set_adc_state(state, DIBX000_SLOW_ADC_OFF);
667
Olivier Grenie713d54a2011-01-04 04:54:31 -0300668 /* unforce divstr regardless whether i2c enumeration was done or not */
669 dib7000p_write_word(state, 1285, dib7000p_read_word(state, 1285) & ~(1 << 1));
670
671 dib7000p_set_bandwidth(state, 8000);
672
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300673 if (state->version == SOC7090) {
Olivier Grenie2e802862011-08-05 10:39:15 -0300674 dib7000p_write_word(state, 36, 0x0755);/* P_iqc_impnc_on =1 & P_iqc_corr_inh = 1 for impulsive noise */
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300675 } else {
Olivier Grenie713d54a2011-01-04 04:54:31 -0300676 if (state->cfg.tuner_is_baseband)
677 dib7000p_write_word(state, 36, 0x0755);
678 else
679 dib7000p_write_word(state, 36, 0x1f55);
680 }
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300681
682 dib7000p_write_tab(state, dib7000p_defaults);
Olivier Grenie2e802862011-08-05 10:39:15 -0300683 if (state->version != SOC7090) {
684 dib7000p_write_word(state, 901, 0x0006);
685 dib7000p_write_word(state, 902, (3 << 10) | (1 << 6));
686 dib7000p_write_word(state, 905, 0x2c8e);
687 }
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300688
Patrick Boettchera75763f2006-10-18 08:34:16 -0300689 dib7000p_set_power_mode(state, DIB7000P_POWER_INTERFACE_ONLY);
690
691 return 0;
692}
693
Patrick Boettchera75763f2006-10-18 08:34:16 -0300694static void dib7000p_pll_clk_cfg(struct dib7000p_state *state)
695{
696 u16 tmp = 0;
697 tmp = dib7000p_read_word(state, 903);
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300698 dib7000p_write_word(state, 903, (tmp | 0x1));
Patrick Boettchera75763f2006-10-18 08:34:16 -0300699 tmp = dib7000p_read_word(state, 900);
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300700 dib7000p_write_word(state, 900, (tmp & 0x7fff) | (1 << 6));
Patrick Boettchera75763f2006-10-18 08:34:16 -0300701}
702
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300703static void dib7000p_restart_agc(struct dib7000p_state *state)
Patrick Boettchera75763f2006-10-18 08:34:16 -0300704{
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300705 // P_restart_iqc & P_restart_agc
706 dib7000p_write_word(state, 770, (1 << 11) | (1 << 9));
707 dib7000p_write_word(state, 770, 0x0000);
Patrick Boettchera75763f2006-10-18 08:34:16 -0300708}
709
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300710static int dib7000p_update_lna(struct dib7000p_state *state)
Patrick Boettchera75763f2006-10-18 08:34:16 -0300711{
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300712 u16 dyn_gain;
713
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300714 if (state->cfg.update_lna) {
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300715 dyn_gain = dib7000p_read_word(state, 394);
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300716 if (state->cfg.update_lna(&state->demod, dyn_gain)) {
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300717 dib7000p_restart_agc(state);
718 return 1;
719 }
720 }
721
722 return 0;
723}
724
725static int dib7000p_set_agc_config(struct dib7000p_state *state, u8 band)
726{
727 struct dibx000_agc_config *agc = NULL;
728 int i;
729 if (state->current_band == band && state->current_agc != NULL)
730 return 0;
731 state->current_band = band;
732
733 for (i = 0; i < state->cfg.agc_config_count; i++)
734 if (state->cfg.agc[i].band_caps & band) {
735 agc = &state->cfg.agc[i];
736 break;
737 }
738
739 if (agc == NULL) {
Olivier Grenie713d54a2011-01-04 04:54:31 -0300740 dprintk("no valid AGC configuration found for band 0x%02x", band);
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300741 return -EINVAL;
742 }
743
744 state->current_agc = agc;
745
746 /* AGC */
Olivier Grenie713d54a2011-01-04 04:54:31 -0300747 dib7000p_write_word(state, 75, agc->setup);
748 dib7000p_write_word(state, 76, agc->inv_gain);
749 dib7000p_write_word(state, 77, agc->time_stabiliz);
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300750 dib7000p_write_word(state, 100, (agc->alpha_level << 12) | agc->thlock);
751
752 // Demod AGC loop configuration
753 dib7000p_write_word(state, 101, (agc->alpha_mant << 5) | agc->alpha_exp);
Olivier Grenie713d54a2011-01-04 04:54:31 -0300754 dib7000p_write_word(state, 102, (agc->beta_mant << 6) | agc->beta_exp);
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300755
756 /* AGC continued */
Olivier Grenie713d54a2011-01-04 04:54:31 -0300757 dprintk("WBD: ref: %d, sel: %d, active: %d, alpha: %d",
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300758 state->wbd_ref != 0 ? state->wbd_ref : agc->wbd_ref, agc->wbd_sel, !agc->perform_agc_softsplit, agc->wbd_sel);
759
760 if (state->wbd_ref != 0)
761 dib7000p_write_word(state, 105, (agc->wbd_inv << 12) | state->wbd_ref);
762 else
763 dib7000p_write_word(state, 105, (agc->wbd_inv << 12) | agc->wbd_ref);
764
765 dib7000p_write_word(state, 106, (agc->wbd_sel << 13) | (agc->wbd_alpha << 9) | (agc->perform_agc_softsplit << 8));
766
Olivier Grenie713d54a2011-01-04 04:54:31 -0300767 dib7000p_write_word(state, 107, agc->agc1_max);
768 dib7000p_write_word(state, 108, agc->agc1_min);
769 dib7000p_write_word(state, 109, agc->agc2_max);
770 dib7000p_write_word(state, 110, agc->agc2_min);
771 dib7000p_write_word(state, 111, (agc->agc1_pt1 << 8) | agc->agc1_pt2);
772 dib7000p_write_word(state, 112, agc->agc1_pt3);
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300773 dib7000p_write_word(state, 113, (agc->agc1_slope1 << 8) | agc->agc1_slope2);
Olivier Grenie713d54a2011-01-04 04:54:31 -0300774 dib7000p_write_word(state, 114, (agc->agc2_pt1 << 8) | agc->agc2_pt2);
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300775 dib7000p_write_word(state, 115, (agc->agc2_slope1 << 8) | agc->agc2_slope2);
776 return 0;
777}
778
Olivier Grenie713d54a2011-01-04 04:54:31 -0300779static void dib7000p_set_dds(struct dib7000p_state *state, s32 offset_khz)
780{
781 u32 internal = dib7000p_get_internal_freq(state);
782 s32 unit_khz_dds_val = 67108864 / (internal); /* 2**26 / Fsampling is the unit 1KHz offset */
783 u32 abs_offset_khz = ABS(offset_khz);
784 u32 dds = state->cfg.bw->ifreq & 0x1ffffff;
785 u8 invert = !!(state->cfg.bw->ifreq & (1 << 25));
786
787 dprintk("setting a frequency offset of %dkHz internal freq = %d invert = %d", offset_khz, internal, invert);
788
789 if (offset_khz < 0)
790 unit_khz_dds_val *= -1;
791
792 /* IF tuner */
793 if (invert)
794 dds -= (abs_offset_khz * unit_khz_dds_val); /* /100 because of /100 on the unit_khz_dds_val line calc for better accuracy */
795 else
796 dds += (abs_offset_khz * unit_khz_dds_val);
797
798 if (abs_offset_khz <= (internal / 2)) { /* Max dds offset is the half of the demod freq */
799 dib7000p_write_word(state, 21, (u16) (((dds >> 16) & 0x1ff) | (0 << 10) | (invert << 9)));
800 dib7000p_write_word(state, 22, (u16) (dds & 0xffff));
801 }
802}
803
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300804static int dib7000p_agc_startup(struct dvb_frontend *demod, struct dvb_frontend_parameters *ch)
805{
806 struct dib7000p_state *state = demod->demodulator_priv;
807 int ret = -1;
808 u8 *agc_state = &state->agc_state;
809 u8 agc_split;
Olivier Grenie713d54a2011-01-04 04:54:31 -0300810 u16 reg;
811 u32 upd_demod_gain_period = 0x1000;
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300812
813 switch (state->agc_state) {
Olivier Grenie713d54a2011-01-04 04:54:31 -0300814 case 0:
Olivier Grenie713d54a2011-01-04 04:54:31 -0300815 dib7000p_set_power_mode(state, DIB7000P_POWER_ALL);
816 if (state->version == SOC7090) {
817 reg = dib7000p_read_word(state, 0x79b) & 0xff00;
818 dib7000p_write_word(state, 0x79a, upd_demod_gain_period & 0xFFFF); /* lsb */
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300819 dib7000p_write_word(state, 0x79b, reg | (1 << 14) | ((upd_demod_gain_period >> 16) & 0xFF));
Olivier Grenie713d54a2011-01-04 04:54:31 -0300820
821 /* enable adc i & q */
822 reg = dib7000p_read_word(state, 0x780);
823 dib7000p_write_word(state, 0x780, (reg | (0x3)) & (~(1 << 7)));
824 } else {
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300825 dib7000p_set_adc_state(state, DIBX000_ADC_ON);
826 dib7000p_pll_clk_cfg(state);
Olivier Grenie713d54a2011-01-04 04:54:31 -0300827 }
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300828
Olivier Grenie713d54a2011-01-04 04:54:31 -0300829 if (dib7000p_set_agc_config(state, BAND_OF_FREQUENCY(ch->frequency / 1000)) != 0)
830 return -1;
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300831
Olivier Grenie713d54a2011-01-04 04:54:31 -0300832 dib7000p_set_dds(state, 0);
833 ret = 7;
834 (*agc_state)++;
835 break;
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300836
Olivier Grenie713d54a2011-01-04 04:54:31 -0300837 case 1:
Olivier Grenie713d54a2011-01-04 04:54:31 -0300838 if (state->cfg.agc_control)
839 state->cfg.agc_control(&state->demod, 1);
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300840
Olivier Grenie713d54a2011-01-04 04:54:31 -0300841 dib7000p_write_word(state, 78, 32768);
842 if (!state->current_agc->perform_agc_softsplit) {
843 /* we are using the wbd - so slow AGC startup */
844 /* force 0 split on WBD and restart AGC */
845 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 -0300846 (*agc_state)++;
847 ret = 5;
Olivier Grenie713d54a2011-01-04 04:54:31 -0300848 } else {
849 /* default AGC startup */
850 (*agc_state) = 4;
851 /* wait AGC rough lock time */
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300852 ret = 7;
Olivier Grenie713d54a2011-01-04 04:54:31 -0300853 }
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300854
Olivier Grenie713d54a2011-01-04 04:54:31 -0300855 dib7000p_restart_agc(state);
856 break;
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300857
Olivier Grenie713d54a2011-01-04 04:54:31 -0300858 case 2: /* fast split search path after 5sec */
859 dib7000p_write_word(state, 75, state->current_agc->setup | (1 << 4)); /* freeze AGC loop */
860 dib7000p_write_word(state, 106, (state->current_agc->wbd_sel << 13) | (2 << 9) | (0 << 8)); /* fast split search 0.25kHz */
861 (*agc_state)++;
862 ret = 14;
863 break;
864
865 case 3: /* split search ended */
866 agc_split = (u8) dib7000p_read_word(state, 396); /* store the split value for the next time */
867 dib7000p_write_word(state, 78, dib7000p_read_word(state, 394)); /* set AGC gain start value */
868
869 dib7000p_write_word(state, 75, state->current_agc->setup); /* std AGC loop */
870 dib7000p_write_word(state, 106, (state->current_agc->wbd_sel << 13) | (state->current_agc->wbd_alpha << 9) | agc_split); /* standard split search */
871
872 dib7000p_restart_agc(state);
873
874 dprintk("SPLIT %p: %hd", demod, agc_split);
875
876 (*agc_state)++;
877 ret = 5;
878 break;
879
880 case 4: /* LNA startup */
Olivier Grenie713d54a2011-01-04 04:54:31 -0300881 ret = 7;
882
883 if (dib7000p_update_lna(state))
Olivier Grenie713d54a2011-01-04 04:54:31 -0300884 ret = 5;
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300885 else
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300886 (*agc_state)++;
Olivier Grenie713d54a2011-01-04 04:54:31 -0300887 break;
888
889 case 5:
890 if (state->cfg.agc_control)
891 state->cfg.agc_control(&state->demod, 0);
892 (*agc_state)++;
893 break;
894 default:
895 break;
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300896 }
897 return ret;
898}
899
900static void dib7000p_update_timf(struct dib7000p_state *state)
901{
902 u32 timf = (dib7000p_read_word(state, 427) << 16) | dib7000p_read_word(state, 428);
903 state->timf = timf * 160 / (state->current_bandwidth / 50);
904 dib7000p_write_word(state, 23, (u16) (timf >> 16));
905 dib7000p_write_word(state, 24, (u16) (timf & 0xffff));
Olivier Grenie713d54a2011-01-04 04:54:31 -0300906 dprintk("updated timf_frequency: %d (default: %d)", state->timf, state->cfg.bw->timf);
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300907
908}
909
Olivier Grenie713d54a2011-01-04 04:54:31 -0300910u32 dib7000p_ctrl_timf(struct dvb_frontend *fe, u8 op, u32 timf)
911{
912 struct dib7000p_state *state = fe->demodulator_priv;
913 switch (op) {
914 case DEMOD_TIMF_SET:
915 state->timf = timf;
916 break;
917 case DEMOD_TIMF_UPDATE:
918 dib7000p_update_timf(state);
919 break;
920 case DEMOD_TIMF_GET:
921 break;
922 }
923 dib7000p_set_bandwidth(state, state->current_bandwidth);
924 return state->timf;
925}
926EXPORT_SYMBOL(dib7000p_ctrl_timf);
927
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300928static void dib7000p_set_channel(struct dib7000p_state *state, struct dvb_frontend_parameters *ch, u8 seq)
929{
930 u16 value, est[4];
931
Olivier Grenie713d54a2011-01-04 04:54:31 -0300932 dib7000p_set_bandwidth(state, BANDWIDTH_TO_KHZ(ch->u.ofdm.bandwidth));
Patrick Boettchera75763f2006-10-18 08:34:16 -0300933
934 /* nfft, guard, qam, alpha */
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300935 value = 0;
936 switch (ch->u.ofdm.transmission_mode) {
Olivier Grenie713d54a2011-01-04 04:54:31 -0300937 case TRANSMISSION_MODE_2K:
938 value |= (0 << 7);
939 break;
Mauro Carvalho Chehab46f72962011-01-16 13:01:20 -0200940 case TRANSMISSION_MODE_4K:
Olivier Grenie713d54a2011-01-04 04:54:31 -0300941 value |= (2 << 7);
942 break;
943 default:
944 case TRANSMISSION_MODE_8K:
945 value |= (1 << 7);
946 break;
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300947 }
948 switch (ch->u.ofdm.guard_interval) {
Olivier Grenie713d54a2011-01-04 04:54:31 -0300949 case GUARD_INTERVAL_1_32:
950 value |= (0 << 5);
951 break;
952 case GUARD_INTERVAL_1_16:
953 value |= (1 << 5);
954 break;
955 case GUARD_INTERVAL_1_4:
956 value |= (3 << 5);
957 break;
958 default:
959 case GUARD_INTERVAL_1_8:
960 value |= (2 << 5);
961 break;
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300962 }
963 switch (ch->u.ofdm.constellation) {
Olivier Grenie713d54a2011-01-04 04:54:31 -0300964 case QPSK:
965 value |= (0 << 3);
966 break;
967 case QAM_16:
968 value |= (1 << 3);
969 break;
970 default:
971 case QAM_64:
972 value |= (2 << 3);
973 break;
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300974 }
975 switch (HIERARCHY_1) {
Olivier Grenie713d54a2011-01-04 04:54:31 -0300976 case HIERARCHY_2:
977 value |= 2;
978 break;
979 case HIERARCHY_4:
980 value |= 4;
981 break;
982 default:
983 case HIERARCHY_1:
984 value |= 1;
985 break;
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300986 }
987 dib7000p_write_word(state, 0, value);
Olivier Grenie713d54a2011-01-04 04:54:31 -0300988 dib7000p_write_word(state, 5, (seq << 4) | 1); /* do not force tps, search list 0 */
Patrick Boettchera75763f2006-10-18 08:34:16 -0300989
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300990 /* P_dintl_native, P_dintlv_inv, P_hrch, P_code_rate, P_select_hp */
991 value = 0;
992 if (1 != 0)
993 value |= (1 << 6);
994 if (ch->u.ofdm.hierarchy_information == 1)
995 value |= (1 << 4);
996 if (1 == 1)
997 value |= 1;
998 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 -0300999 case FEC_2_3:
1000 value |= (2 << 1);
1001 break;
1002 case FEC_3_4:
1003 value |= (3 << 1);
1004 break;
1005 case FEC_5_6:
1006 value |= (5 << 1);
1007 break;
1008 case FEC_7_8:
1009 value |= (7 << 1);
1010 break;
1011 default:
1012 case FEC_1_2:
1013 value |= (1 << 1);
1014 break;
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001015 }
1016 dib7000p_write_word(state, 208, value);
1017
1018 /* offset loop parameters */
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001019 dib7000p_write_word(state, 26, 0x6680);
1020 dib7000p_write_word(state, 32, 0x0003);
1021 dib7000p_write_word(state, 29, 0x1273);
1022 dib7000p_write_word(state, 33, 0x0005);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001023
1024 /* P_dvsy_sync_wait */
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001025 switch (ch->u.ofdm.transmission_mode) {
Olivier Grenie713d54a2011-01-04 04:54:31 -03001026 case TRANSMISSION_MODE_8K:
1027 value = 256;
1028 break;
1029 case TRANSMISSION_MODE_4K:
1030 value = 128;
1031 break;
1032 case TRANSMISSION_MODE_2K:
1033 default:
1034 value = 64;
1035 break;
Patrick Boettchera75763f2006-10-18 08:34:16 -03001036 }
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001037 switch (ch->u.ofdm.guard_interval) {
Olivier Grenie713d54a2011-01-04 04:54:31 -03001038 case GUARD_INTERVAL_1_16:
1039 value *= 2;
1040 break;
1041 case GUARD_INTERVAL_1_8:
1042 value *= 4;
1043 break;
1044 case GUARD_INTERVAL_1_4:
1045 value *= 8;
1046 break;
1047 default:
1048 case GUARD_INTERVAL_1_32:
1049 value *= 1;
1050 break;
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001051 }
Olivier Grenie970d14c2010-09-07 12:50:46 -03001052 if (state->cfg.diversity_delay == 0)
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001053 state->div_sync_wait = (value * 3) / 2 + 48;
Olivier Grenie970d14c2010-09-07 12:50:46 -03001054 else
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001055 state->div_sync_wait = (value * 3) / 2 + state->cfg.diversity_delay;
Patrick Boettchera75763f2006-10-18 08:34:16 -03001056
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001057 /* deactive the possibility of diversity reception if extended interleaver */
1058 state->div_force_off = !1 && ch->u.ofdm.transmission_mode != TRANSMISSION_MODE_8K;
1059 dib7000p_set_diversity_in(&state->demod, state->div_state);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001060
1061 /* channel estimation fine configuration */
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001062 switch (ch->u.ofdm.constellation) {
Olivier Grenie713d54a2011-01-04 04:54:31 -03001063 case QAM_64:
1064 est[0] = 0x0148; /* P_adp_regul_cnt 0.04 */
1065 est[1] = 0xfff0; /* P_adp_noise_cnt -0.002 */
1066 est[2] = 0x00a4; /* P_adp_regul_ext 0.02 */
1067 est[3] = 0xfff8; /* P_adp_noise_ext -0.001 */
1068 break;
1069 case QAM_16:
1070 est[0] = 0x023d; /* P_adp_regul_cnt 0.07 */
1071 est[1] = 0xffdf; /* P_adp_noise_cnt -0.004 */
1072 est[2] = 0x00a4; /* P_adp_regul_ext 0.02 */
1073 est[3] = 0xfff0; /* P_adp_noise_ext -0.002 */
1074 break;
1075 default:
1076 est[0] = 0x099a; /* P_adp_regul_cnt 0.3 */
1077 est[1] = 0xffae; /* P_adp_noise_cnt -0.01 */
1078 est[2] = 0x0333; /* P_adp_regul_ext 0.1 */
1079 est[3] = 0xfff8; /* P_adp_noise_ext -0.002 */
1080 break;
Patrick Boettchera75763f2006-10-18 08:34:16 -03001081 }
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001082 for (value = 0; value < 4; value++)
1083 dib7000p_write_word(state, 187 + value, est[value]);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001084}
1085
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001086static int dib7000p_autosearch_start(struct dvb_frontend *demod, struct dvb_frontend_parameters *ch)
Patrick Boettchera75763f2006-10-18 08:34:16 -03001087{
1088 struct dib7000p_state *state = demod->demodulator_priv;
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001089 struct dvb_frontend_parameters schan;
1090 u32 value, factor;
Olivier Grenie713d54a2011-01-04 04:54:31 -03001091 u32 internal = dib7000p_get_internal_freq(state);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001092
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001093 schan = *ch;
1094 schan.u.ofdm.constellation = QAM_64;
Olivier Grenie713d54a2011-01-04 04:54:31 -03001095 schan.u.ofdm.guard_interval = GUARD_INTERVAL_1_32;
1096 schan.u.ofdm.transmission_mode = TRANSMISSION_MODE_8K;
1097 schan.u.ofdm.code_rate_HP = FEC_2_3;
1098 schan.u.ofdm.code_rate_LP = FEC_3_4;
1099 schan.u.ofdm.hierarchy_information = 0;
Patrick Boettchera75763f2006-10-18 08:34:16 -03001100
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001101 dib7000p_set_channel(state, &schan, 7);
1102
1103 factor = BANDWIDTH_TO_KHZ(ch->u.ofdm.bandwidth);
Olivier Grenie2e802862011-08-05 10:39:15 -03001104 if (factor >= 5000) {
1105 if (state->version == SOC7090)
1106 factor = 2;
1107 else
1108 factor = 1;
1109 } else
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001110 factor = 6;
Patrick Boettchera75763f2006-10-18 08:34:16 -03001111
Olivier Grenie713d54a2011-01-04 04:54:31 -03001112 value = 30 * internal * factor;
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001113 dib7000p_write_word(state, 6, (u16) ((value >> 16) & 0xffff));
1114 dib7000p_write_word(state, 7, (u16) (value & 0xffff));
Olivier Grenie713d54a2011-01-04 04:54:31 -03001115 value = 100 * internal * factor;
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001116 dib7000p_write_word(state, 8, (u16) ((value >> 16) & 0xffff));
1117 dib7000p_write_word(state, 9, (u16) (value & 0xffff));
Olivier Grenie713d54a2011-01-04 04:54:31 -03001118 value = 500 * internal * factor;
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001119 dib7000p_write_word(state, 10, (u16) ((value >> 16) & 0xffff));
1120 dib7000p_write_word(state, 11, (u16) (value & 0xffff));
Patrick Boettchera75763f2006-10-18 08:34:16 -03001121
1122 value = dib7000p_read_word(state, 0);
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001123 dib7000p_write_word(state, 0, (u16) ((1 << 9) | value));
Patrick Boettchera75763f2006-10-18 08:34:16 -03001124 dib7000p_read_word(state, 1284);
1125 dib7000p_write_word(state, 0, (u16) value);
1126
1127 return 0;
1128}
1129
1130static int dib7000p_autosearch_is_irq(struct dvb_frontend *demod)
1131{
1132 struct dib7000p_state *state = demod->demodulator_priv;
1133 u16 irq_pending = dib7000p_read_word(state, 1284);
1134
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001135 if (irq_pending & 0x1)
Patrick Boettchera75763f2006-10-18 08:34:16 -03001136 return 1;
1137
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001138 if (irq_pending & 0x2)
Patrick Boettchera75763f2006-10-18 08:34:16 -03001139 return 2;
1140
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001141 return 0;
Patrick Boettchera75763f2006-10-18 08:34:16 -03001142}
1143
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001144static void dib7000p_spur_protect(struct dib7000p_state *state, u32 rf_khz, u32 bw)
1145{
Olivier Grenie713d54a2011-01-04 04:54:31 -03001146 static s16 notch[] = { 16143, 14402, 12238, 9713, 6902, 3888, 759, -2392 };
1147 static u8 sine[] = { 0, 2, 3, 5, 6, 8, 9, 11, 13, 14, 16, 17, 19, 20, 22,
1148 24, 25, 27, 28, 30, 31, 33, 34, 36, 38, 39, 41, 42, 44, 45, 47, 48, 50, 51,
1149 53, 55, 56, 58, 59, 61, 62, 64, 65, 67, 68, 70, 71, 73, 74, 76, 77, 79, 80,
1150 82, 83, 85, 86, 88, 89, 91, 92, 94, 95, 97, 98, 99, 101, 102, 104, 105,
1151 107, 108, 109, 111, 112, 114, 115, 117, 118, 119, 121, 122, 123, 125, 126,
1152 128, 129, 130, 132, 133, 134, 136, 137, 138, 140, 141, 142, 144, 145, 146,
1153 147, 149, 150, 151, 152, 154, 155, 156, 157, 159, 160, 161, 162, 164, 165,
1154 166, 167, 168, 170, 171, 172, 173, 174, 175, 177, 178, 179, 180, 181, 182,
1155 183, 184, 185, 186, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198,
1156 199, 200, 201, 202, 203, 204, 205, 206, 207, 207, 208, 209, 210, 211, 212,
1157 213, 214, 215, 215, 216, 217, 218, 219, 220, 220, 221, 222, 223, 224, 224,
1158 225, 226, 227, 227, 228, 229, 229, 230, 231, 231, 232, 233, 233, 234, 235,
1159 235, 236, 237, 237, 238, 238, 239, 239, 240, 241, 241, 242, 242, 243, 243,
1160 244, 244, 245, 245, 245, 246, 246, 247, 247, 248, 248, 248, 249, 249, 249,
1161 250, 250, 250, 251, 251, 251, 252, 252, 252, 252, 253, 253, 253, 253, 254,
1162 254, 254, 254, 254, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
1163 255, 255, 255, 255, 255, 255
1164 };
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001165
1166 u32 xtal = state->cfg.bw->xtal_hz / 1000;
Julia Lawall75b697f2009-08-01 16:48:41 -03001167 int f_rel = DIV_ROUND_CLOSEST(rf_khz, xtal) * xtal - rf_khz;
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001168 int k;
Olivier Grenie713d54a2011-01-04 04:54:31 -03001169 int coef_re[8], coef_im[8];
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001170 int bw_khz = bw;
1171 u32 pha;
1172
Olivier Grenie713d54a2011-01-04 04:54:31 -03001173 dprintk("relative position of the Spur: %dk (RF: %dk, XTAL: %dk)", f_rel, rf_khz, xtal);
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001174
Olivier Grenie713d54a2011-01-04 04:54:31 -03001175 if (f_rel < -bw_khz / 2 || f_rel > bw_khz / 2)
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001176 return;
1177
1178 bw_khz /= 100;
1179
Olivier Grenie713d54a2011-01-04 04:54:31 -03001180 dib7000p_write_word(state, 142, 0x0610);
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001181
1182 for (k = 0; k < 8; k++) {
Olivier Grenie713d54a2011-01-04 04:54:31 -03001183 pha = ((f_rel * (k + 1) * 112 * 80 / bw_khz) / 1000) & 0x3ff;
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001184
Olivier Grenie713d54a2011-01-04 04:54:31 -03001185 if (pha == 0) {
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001186 coef_re[k] = 256;
1187 coef_im[k] = 0;
Olivier Grenie713d54a2011-01-04 04:54:31 -03001188 } else if (pha < 256) {
1189 coef_re[k] = sine[256 - (pha & 0xff)];
1190 coef_im[k] = sine[pha & 0xff];
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001191 } else if (pha == 256) {
1192 coef_re[k] = 0;
1193 coef_im[k] = 256;
1194 } else if (pha < 512) {
Olivier Grenie713d54a2011-01-04 04:54:31 -03001195 coef_re[k] = -sine[pha & 0xff];
1196 coef_im[k] = sine[256 - (pha & 0xff)];
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001197 } else if (pha == 512) {
1198 coef_re[k] = -256;
1199 coef_im[k] = 0;
1200 } else if (pha < 768) {
Olivier Grenie713d54a2011-01-04 04:54:31 -03001201 coef_re[k] = -sine[256 - (pha & 0xff)];
1202 coef_im[k] = -sine[pha & 0xff];
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001203 } else if (pha == 768) {
1204 coef_re[k] = 0;
1205 coef_im[k] = -256;
1206 } else {
Olivier Grenie713d54a2011-01-04 04:54:31 -03001207 coef_re[k] = sine[pha & 0xff];
1208 coef_im[k] = -sine[256 - (pha & 0xff)];
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001209 }
1210
1211 coef_re[k] *= notch[k];
Olivier Grenie713d54a2011-01-04 04:54:31 -03001212 coef_re[k] += (1 << 14);
1213 if (coef_re[k] >= (1 << 24))
1214 coef_re[k] = (1 << 24) - 1;
1215 coef_re[k] /= (1 << 15);
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001216
1217 coef_im[k] *= notch[k];
Olivier Grenie713d54a2011-01-04 04:54:31 -03001218 coef_im[k] += (1 << 14);
1219 if (coef_im[k] >= (1 << 24))
1220 coef_im[k] = (1 << 24) - 1;
1221 coef_im[k] /= (1 << 15);
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001222
Olivier Grenie713d54a2011-01-04 04:54:31 -03001223 dprintk("PALF COEF: %d re: %d im: %d", k, coef_re[k], coef_im[k]);
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001224
1225 dib7000p_write_word(state, 143, (0 << 14) | (k << 10) | (coef_re[k] & 0x3ff));
1226 dib7000p_write_word(state, 144, coef_im[k] & 0x3ff);
1227 dib7000p_write_word(state, 143, (1 << 14) | (k << 10) | (coef_re[k] & 0x3ff));
1228 }
Olivier Grenie713d54a2011-01-04 04:54:31 -03001229 dib7000p_write_word(state, 143, 0);
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001230}
1231
1232static int dib7000p_tune(struct dvb_frontend *demod, struct dvb_frontend_parameters *ch)
Patrick Boettchera75763f2006-10-18 08:34:16 -03001233{
1234 struct dib7000p_state *state = demod->demodulator_priv;
1235 u16 tmp = 0;
1236
1237 if (ch != NULL)
1238 dib7000p_set_channel(state, ch, 0);
1239 else
1240 return -EINVAL;
1241
1242 // restart demod
1243 dib7000p_write_word(state, 770, 0x4000);
1244 dib7000p_write_word(state, 770, 0x0000);
1245 msleep(45);
1246
1247 /* 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 -03001248 tmp = (0 << 14) | (4 << 10) | (0 << 9) | (3 << 5) | (1 << 4) | (0x3);
1249 if (state->sfn_workaround_active) {
Olivier Grenie713d54a2011-01-04 04:54:31 -03001250 dprintk("SFN workaround is active");
Matt Doran8f6956c2007-07-31 07:09:30 -03001251 tmp |= (1 << 9);
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001252 dib7000p_write_word(state, 166, 0x4000);
Matt Doran8f6956c2007-07-31 07:09:30 -03001253 } else {
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001254 dib7000p_write_word(state, 166, 0x0000);
Matt Doran8f6956c2007-07-31 07:09:30 -03001255 }
1256 dib7000p_write_word(state, 29, tmp);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001257
1258 // never achieved a lock with that bandwidth so far - wait for osc-freq to update
1259 if (state->timf == 0)
1260 msleep(200);
1261
1262 /* offset loop parameters */
1263
1264 /* P_timf_alpha, P_corm_alpha=6, P_corm_thres=0x80 */
1265 tmp = (6 << 8) | 0x80;
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001266 switch (ch->u.ofdm.transmission_mode) {
Olivier Grenie713d54a2011-01-04 04:54:31 -03001267 case TRANSMISSION_MODE_2K:
1268 tmp |= (2 << 12);
1269 break;
Mauro Carvalho Chehab46f72962011-01-16 13:01:20 -02001270 case TRANSMISSION_MODE_4K:
Olivier Grenie713d54a2011-01-04 04:54:31 -03001271 tmp |= (3 << 12);
1272 break;
1273 default:
1274 case TRANSMISSION_MODE_8K:
1275 tmp |= (4 << 12);
1276 break;
Patrick Boettchera75763f2006-10-18 08:34:16 -03001277 }
Olivier Grenie713d54a2011-01-04 04:54:31 -03001278 dib7000p_write_word(state, 26, tmp); /* timf_a(6xxx) */
Patrick Boettchera75763f2006-10-18 08:34:16 -03001279
1280 /* P_ctrl_freeze_pha_shift=0, P_ctrl_pha_off_max */
1281 tmp = (0 << 4);
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001282 switch (ch->u.ofdm.transmission_mode) {
Olivier Grenie713d54a2011-01-04 04:54:31 -03001283 case TRANSMISSION_MODE_2K:
1284 tmp |= 0x6;
1285 break;
Mauro Carvalho Chehab46f72962011-01-16 13:01:20 -02001286 case TRANSMISSION_MODE_4K:
Olivier Grenie713d54a2011-01-04 04:54:31 -03001287 tmp |= 0x7;
1288 break;
1289 default:
1290 case TRANSMISSION_MODE_8K:
1291 tmp |= 0x8;
1292 break;
Patrick Boettchera75763f2006-10-18 08:34:16 -03001293 }
Olivier Grenie713d54a2011-01-04 04:54:31 -03001294 dib7000p_write_word(state, 32, tmp);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001295
1296 /* P_ctrl_sfreq_inh=0, P_ctrl_sfreq_step */
1297 tmp = (0 << 4);
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001298 switch (ch->u.ofdm.transmission_mode) {
Olivier Grenie713d54a2011-01-04 04:54:31 -03001299 case TRANSMISSION_MODE_2K:
1300 tmp |= 0x6;
1301 break;
1302 case TRANSMISSION_MODE_4K:
1303 tmp |= 0x7;
1304 break;
1305 default:
1306 case TRANSMISSION_MODE_8K:
1307 tmp |= 0x8;
1308 break;
Patrick Boettchera75763f2006-10-18 08:34:16 -03001309 }
Olivier Grenie713d54a2011-01-04 04:54:31 -03001310 dib7000p_write_word(state, 33, tmp);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001311
Olivier Grenie713d54a2011-01-04 04:54:31 -03001312 tmp = dib7000p_read_word(state, 509);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001313 if (!((tmp >> 6) & 0x1)) {
1314 /* restart the fec */
Olivier Grenie713d54a2011-01-04 04:54:31 -03001315 tmp = dib7000p_read_word(state, 771);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001316 dib7000p_write_word(state, 771, tmp | (1 << 1));
1317 dib7000p_write_word(state, 771, tmp);
Olivier Grenie713d54a2011-01-04 04:54:31 -03001318 msleep(40);
1319 tmp = dib7000p_read_word(state, 509);
1320 }
1321 // we achieved a lock - it's time to update the osc freq
1322 if ((tmp >> 6) & 0x1) {
1323 dib7000p_update_timf(state);
1324 /* P_timf_alpha += 2 */
1325 tmp = dib7000p_read_word(state, 26);
1326 dib7000p_write_word(state, 26, (tmp & ~(0xf << 12)) | ((((tmp >> 12) & 0xf) + 5) << 12));
Patrick Boettchera75763f2006-10-18 08:34:16 -03001327 }
1328
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001329 if (state->cfg.spur_protect)
Olivier Grenie713d54a2011-01-04 04:54:31 -03001330 dib7000p_spur_protect(state, ch->frequency / 1000, BANDWIDTH_TO_KHZ(ch->u.ofdm.bandwidth));
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001331
Olivier Grenie713d54a2011-01-04 04:54:31 -03001332 dib7000p_set_bandwidth(state, BANDWIDTH_TO_KHZ(ch->u.ofdm.bandwidth));
Patrick Boettchera75763f2006-10-18 08:34:16 -03001333 return 0;
1334}
1335
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001336static int dib7000p_wakeup(struct dvb_frontend *demod)
Patrick Boettchera75763f2006-10-18 08:34:16 -03001337{
Patrick Boettchera75763f2006-10-18 08:34:16 -03001338 struct dib7000p_state *state = demod->demodulator_priv;
Patrick Boettchera75763f2006-10-18 08:34:16 -03001339 dib7000p_set_power_mode(state, DIB7000P_POWER_ALL);
1340 dib7000p_set_adc_state(state, DIBX000_SLOW_ADC_ON);
Olivier Grenie713d54a2011-01-04 04:54:31 -03001341 if (state->version == SOC7090)
1342 dib7000p_sad_calib(state);
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001343 return 0;
Patrick Boettchera75763f2006-10-18 08:34:16 -03001344}
1345
1346static int dib7000p_sleep(struct dvb_frontend *demod)
1347{
1348 struct dib7000p_state *state = demod->demodulator_priv;
Olivier Grenie713d54a2011-01-04 04:54:31 -03001349 if (state->version == SOC7090)
Olivier Grenie2e802862011-08-05 10:39:15 -03001350 return dib7000p_set_power_mode(state, DIB7000P_POWER_INTERFACE_ONLY);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001351 return dib7000p_set_output_mode(state, OUTMODE_HIGH_Z) | dib7000p_set_power_mode(state, DIB7000P_POWER_INTERFACE_ONLY);
1352}
1353
1354static int dib7000p_identify(struct dib7000p_state *st)
1355{
1356 u16 value;
Olivier Grenie713d54a2011-01-04 04:54:31 -03001357 dprintk("checking demod on I2C address: %d (%x)", st->i2c_addr, st->i2c_addr);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001358
1359 if ((value = dib7000p_read_word(st, 768)) != 0x01b3) {
Olivier Grenie713d54a2011-01-04 04:54:31 -03001360 dprintk("wrong Vendor ID (read=0x%x)", value);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001361 return -EREMOTEIO;
1362 }
1363
1364 if ((value = dib7000p_read_word(st, 769)) != 0x4000) {
Olivier Grenie713d54a2011-01-04 04:54:31 -03001365 dprintk("wrong Device ID (%x)", value);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001366 return -EREMOTEIO;
1367 }
1368
1369 return 0;
1370}
1371
Olivier Grenie713d54a2011-01-04 04:54:31 -03001372static int dib7000p_get_frontend(struct dvb_frontend *fe, struct dvb_frontend_parameters *fep)
Patrick Boettchera75763f2006-10-18 08:34:16 -03001373{
1374 struct dib7000p_state *state = fe->demodulator_priv;
Olivier Grenie713d54a2011-01-04 04:54:31 -03001375 u16 tps = dib7000p_read_word(state, 463);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001376
1377 fep->inversion = INVERSION_AUTO;
1378
Patrick Boettcher904a82e2008-01-25 07:31:58 -03001379 fep->u.ofdm.bandwidth = BANDWIDTH_TO_INDEX(state->current_bandwidth);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001380
1381 switch ((tps >> 8) & 0x3) {
Olivier Grenie713d54a2011-01-04 04:54:31 -03001382 case 0:
1383 fep->u.ofdm.transmission_mode = TRANSMISSION_MODE_2K;
1384 break;
1385 case 1:
1386 fep->u.ofdm.transmission_mode = TRANSMISSION_MODE_8K;
1387 break;
Mauro Carvalho Chehab46f72962011-01-16 13:01:20 -02001388 /* case 2: fep->u.ofdm.transmission_mode = TRANSMISSION_MODE_4K; break; */
Patrick Boettchera75763f2006-10-18 08:34:16 -03001389 }
1390
1391 switch (tps & 0x3) {
Olivier Grenie713d54a2011-01-04 04:54:31 -03001392 case 0:
1393 fep->u.ofdm.guard_interval = GUARD_INTERVAL_1_32;
1394 break;
1395 case 1:
1396 fep->u.ofdm.guard_interval = GUARD_INTERVAL_1_16;
1397 break;
1398 case 2:
1399 fep->u.ofdm.guard_interval = GUARD_INTERVAL_1_8;
1400 break;
1401 case 3:
1402 fep->u.ofdm.guard_interval = GUARD_INTERVAL_1_4;
1403 break;
Patrick Boettchera75763f2006-10-18 08:34:16 -03001404 }
1405
1406 switch ((tps >> 14) & 0x3) {
Olivier Grenie713d54a2011-01-04 04:54:31 -03001407 case 0:
1408 fep->u.ofdm.constellation = QPSK;
1409 break;
1410 case 1:
1411 fep->u.ofdm.constellation = QAM_16;
1412 break;
1413 case 2:
1414 default:
1415 fep->u.ofdm.constellation = QAM_64;
1416 break;
Patrick Boettchera75763f2006-10-18 08:34:16 -03001417 }
1418
1419 /* as long as the frontend_param structure is fixed for hierarchical transmission I refuse to use it */
1420 /* (tps >> 13) & 0x1 == hrch is used, (tps >> 10) & 0x7 == alpha */
1421
1422 fep->u.ofdm.hierarchy_information = HIERARCHY_NONE;
1423 switch ((tps >> 5) & 0x7) {
Olivier Grenie713d54a2011-01-04 04:54:31 -03001424 case 1:
1425 fep->u.ofdm.code_rate_HP = FEC_1_2;
1426 break;
1427 case 2:
1428 fep->u.ofdm.code_rate_HP = FEC_2_3;
1429 break;
1430 case 3:
1431 fep->u.ofdm.code_rate_HP = FEC_3_4;
1432 break;
1433 case 5:
1434 fep->u.ofdm.code_rate_HP = FEC_5_6;
1435 break;
1436 case 7:
1437 default:
1438 fep->u.ofdm.code_rate_HP = FEC_7_8;
1439 break;
Patrick Boettchera75763f2006-10-18 08:34:16 -03001440
1441 }
1442
1443 switch ((tps >> 2) & 0x7) {
Olivier Grenie713d54a2011-01-04 04:54:31 -03001444 case 1:
1445 fep->u.ofdm.code_rate_LP = FEC_1_2;
1446 break;
1447 case 2:
1448 fep->u.ofdm.code_rate_LP = FEC_2_3;
1449 break;
1450 case 3:
1451 fep->u.ofdm.code_rate_LP = FEC_3_4;
1452 break;
1453 case 5:
1454 fep->u.ofdm.code_rate_LP = FEC_5_6;
1455 break;
1456 case 7:
1457 default:
1458 fep->u.ofdm.code_rate_LP = FEC_7_8;
1459 break;
Patrick Boettchera75763f2006-10-18 08:34:16 -03001460 }
1461
1462 /* native interleaver: (dib7000p_read_word(state, 464) >> 5) & 0x1 */
1463
1464 return 0;
1465}
1466
Olivier Grenie713d54a2011-01-04 04:54:31 -03001467static int dib7000p_set_frontend(struct dvb_frontend *fe, struct dvb_frontend_parameters *fep)
Patrick Boettchera75763f2006-10-18 08:34:16 -03001468{
1469 struct dib7000p_state *state = fe->demodulator_priv;
Soeren Moch853ea132008-01-25 06:27:06 -03001470 int time, ret;
Patrick Boettchera75763f2006-10-18 08:34:16 -03001471
Olivier Grenie2e802862011-08-05 10:39:15 -03001472 if (state->version == SOC7090)
Olivier Grenie713d54a2011-01-04 04:54:31 -03001473 dib7090_set_diversity_in(fe, 0);
Olivier Grenie2e802862011-08-05 10:39:15 -03001474 else
Olivier Grenie713d54a2011-01-04 04:54:31 -03001475 dib7000p_set_output_mode(state, OUTMODE_HIGH_Z);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001476
Olivier Grenie713d54a2011-01-04 04:54:31 -03001477 /* maybe the parameter has been changed */
Matt Doran8f6956c2007-07-31 07:09:30 -03001478 state->sfn_workaround_active = buggy_sfn_workaround;
1479
Patrick Boettchera75763f2006-10-18 08:34:16 -03001480 if (fe->ops.tuner_ops.set_params)
1481 fe->ops.tuner_ops.set_params(fe, fep);
1482
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001483 /* start up the AGC */
1484 state->agc_state = 0;
1485 do {
1486 time = dib7000p_agc_startup(fe, fep);
1487 if (time != -1)
1488 msleep(time);
1489 } while (time != -1);
1490
Patrick Boettchera75763f2006-10-18 08:34:16 -03001491 if (fep->u.ofdm.transmission_mode == TRANSMISSION_MODE_AUTO ||
Olivier Grenie713d54a2011-01-04 04:54:31 -03001492 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 -03001493 int i = 800, found;
1494
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001495 dib7000p_autosearch_start(fe, fep);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001496 do {
1497 msleep(1);
1498 found = dib7000p_autosearch_is_irq(fe);
1499 } while (found == 0 && i--);
1500
Olivier Grenie713d54a2011-01-04 04:54:31 -03001501 dprintk("autosearch returns: %d", found);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001502 if (found == 0 || found == 1)
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001503 return 0;
Patrick Boettchera75763f2006-10-18 08:34:16 -03001504
1505 dib7000p_get_frontend(fe, fep);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001506 }
1507
Soeren Moch853ea132008-01-25 06:27:06 -03001508 ret = dib7000p_tune(fe, fep);
1509
Patrick Boettchera75763f2006-10-18 08:34:16 -03001510 /* make this a config parameter */
Olivier Grenie2e802862011-08-05 10:39:15 -03001511 if (state->version == SOC7090) {
Olivier Grenie713d54a2011-01-04 04:54:31 -03001512 dib7090_set_output_mode(fe, state->cfg.output_mode);
Olivier Grenie2e802862011-08-05 10:39:15 -03001513 if (state->cfg.enMpegOutput == 0) {
1514 dib7090_setDibTxMux(state, MPEG_ON_DIBTX);
1515 dib7090_setHostBusMux(state, DIBTX_ON_HOSTBUS);
1516 }
1517 } else
Olivier Grenie713d54a2011-01-04 04:54:31 -03001518 dib7000p_set_output_mode(state, state->cfg.output_mode);
1519
1520 return ret;
Patrick Boettchera75763f2006-10-18 08:34:16 -03001521}
1522
Olivier Grenie713d54a2011-01-04 04:54:31 -03001523static int dib7000p_read_status(struct dvb_frontend *fe, fe_status_t * stat)
Patrick Boettchera75763f2006-10-18 08:34:16 -03001524{
1525 struct dib7000p_state *state = fe->demodulator_priv;
1526 u16 lock = dib7000p_read_word(state, 509);
1527
1528 *stat = 0;
1529
1530 if (lock & 0x8000)
1531 *stat |= FE_HAS_SIGNAL;
1532 if (lock & 0x3000)
1533 *stat |= FE_HAS_CARRIER;
1534 if (lock & 0x0100)
1535 *stat |= FE_HAS_VITERBI;
1536 if (lock & 0x0010)
1537 *stat |= FE_HAS_SYNC;
Olivier Grenie713d54a2011-01-04 04:54:31 -03001538 if ((lock & 0x0038) == 0x38)
Patrick Boettchera75763f2006-10-18 08:34:16 -03001539 *stat |= FE_HAS_LOCK;
1540
1541 return 0;
1542}
1543
Olivier Grenie713d54a2011-01-04 04:54:31 -03001544static int dib7000p_read_ber(struct dvb_frontend *fe, u32 * ber)
Patrick Boettchera75763f2006-10-18 08:34:16 -03001545{
1546 struct dib7000p_state *state = fe->demodulator_priv;
1547 *ber = (dib7000p_read_word(state, 500) << 16) | dib7000p_read_word(state, 501);
1548 return 0;
1549}
1550
Olivier Grenie713d54a2011-01-04 04:54:31 -03001551static int dib7000p_read_unc_blocks(struct dvb_frontend *fe, u32 * unc)
Patrick Boettchera75763f2006-10-18 08:34:16 -03001552{
1553 struct dib7000p_state *state = fe->demodulator_priv;
1554 *unc = dib7000p_read_word(state, 506);
1555 return 0;
1556}
1557
Olivier Grenie713d54a2011-01-04 04:54:31 -03001558static int dib7000p_read_signal_strength(struct dvb_frontend *fe, u16 * strength)
Patrick Boettchera75763f2006-10-18 08:34:16 -03001559{
1560 struct dib7000p_state *state = fe->demodulator_priv;
1561 u16 val = dib7000p_read_word(state, 394);
1562 *strength = 65535 - val;
1563 return 0;
1564}
1565
Olivier Grenie713d54a2011-01-04 04:54:31 -03001566static int dib7000p_read_snr(struct dvb_frontend *fe, u16 * snr)
Patrick Boettchera75763f2006-10-18 08:34:16 -03001567{
Olivier Grenieef801962009-09-15 06:46:52 -03001568 struct dib7000p_state *state = fe->demodulator_priv;
1569 u16 val;
1570 s32 signal_mant, signal_exp, noise_mant, noise_exp;
1571 u32 result = 0;
1572
1573 val = dib7000p_read_word(state, 479);
1574 noise_mant = (val >> 4) & 0xff;
1575 noise_exp = ((val & 0xf) << 2);
1576 val = dib7000p_read_word(state, 480);
1577 noise_exp += ((val >> 14) & 0x3);
1578 if ((noise_exp & 0x20) != 0)
1579 noise_exp -= 0x40;
1580
1581 signal_mant = (val >> 6) & 0xFF;
Olivier Grenie713d54a2011-01-04 04:54:31 -03001582 signal_exp = (val & 0x3F);
Olivier Grenieef801962009-09-15 06:46:52 -03001583 if ((signal_exp & 0x20) != 0)
1584 signal_exp -= 0x40;
1585
1586 if (signal_mant != 0)
Olivier Grenie713d54a2011-01-04 04:54:31 -03001587 result = intlog10(2) * 10 * signal_exp + 10 * intlog10(signal_mant);
Olivier Grenieef801962009-09-15 06:46:52 -03001588 else
1589 result = intlog10(2) * 10 * signal_exp - 100;
1590
1591 if (noise_mant != 0)
Olivier Grenie713d54a2011-01-04 04:54:31 -03001592 result -= intlog10(2) * 10 * noise_exp + 10 * intlog10(noise_mant);
Olivier Grenieef801962009-09-15 06:46:52 -03001593 else
1594 result -= intlog10(2) * 10 * noise_exp - 100;
1595
1596 *snr = result / ((1 << 24) / 10);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001597 return 0;
1598}
1599
Olivier Grenie713d54a2011-01-04 04:54:31 -03001600static int dib7000p_fe_get_tune_settings(struct dvb_frontend *fe, struct dvb_frontend_tune_settings *tune)
Patrick Boettchera75763f2006-10-18 08:34:16 -03001601{
1602 tune->min_delay_ms = 1000;
1603 return 0;
1604}
1605
1606static void dib7000p_release(struct dvb_frontend *demod)
1607{
1608 struct dib7000p_state *st = demod->demodulator_priv;
1609 dibx000_exit_i2c_master(&st->i2c_master);
Olivier Grenie713d54a2011-01-04 04:54:31 -03001610 i2c_del_adapter(&st->dib7090_tuner_adap);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001611 kfree(st);
1612}
1613
1614int dib7000pc_detection(struct i2c_adapter *i2c_adap)
1615{
Olivier Grenie5a0deee2011-05-03 12:27:33 -03001616 u8 *tx, *rx;
Patrick Boettchera75763f2006-10-18 08:34:16 -03001617 struct i2c_msg msg[2] = {
Olivier Grenie5a0deee2011-05-03 12:27:33 -03001618 {.addr = 18 >> 1, .flags = 0, .len = 2},
1619 {.addr = 18 >> 1, .flags = I2C_M_RD, .len = 2},
Patrick Boettchera75763f2006-10-18 08:34:16 -03001620 };
Olivier Grenie5a0deee2011-05-03 12:27:33 -03001621 int ret = 0;
1622
1623 tx = kzalloc(2*sizeof(u8), GFP_KERNEL);
1624 if (!tx)
1625 return -ENOMEM;
1626 rx = kzalloc(2*sizeof(u8), GFP_KERNEL);
1627 if (!rx) {
Olivier Grenie5a0deee2011-05-03 12:27:33 -03001628 ret = -ENOMEM;
Dan Carpenter0c61cc3b2011-08-06 05:00:34 -03001629 goto rx_memory_error;
Olivier Grenie5a0deee2011-05-03 12:27:33 -03001630 }
1631
1632 msg[0].buf = tx;
1633 msg[1].buf = rx;
Patrick Boettchera75763f2006-10-18 08:34:16 -03001634
1635 tx[0] = 0x03;
1636 tx[1] = 0x00;
1637
1638 if (i2c_transfer(i2c_adap, msg, 2) == 2)
1639 if (rx[0] == 0x01 && rx[1] == 0xb3) {
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001640 dprintk("-D- DiB7000PC detected");
Patrick Boettchera75763f2006-10-18 08:34:16 -03001641 return 1;
1642 }
1643
1644 msg[0].addr = msg[1].addr = 0x40;
1645
1646 if (i2c_transfer(i2c_adap, msg, 2) == 2)
1647 if (rx[0] == 0x01 && rx[1] == 0xb3) {
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001648 dprintk("-D- DiB7000PC detected");
Patrick Boettchera75763f2006-10-18 08:34:16 -03001649 return 1;
1650 }
1651
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001652 dprintk("-D- DiB7000PC not detected");
Olivier Grenie5a0deee2011-05-03 12:27:33 -03001653
1654 kfree(rx);
1655rx_memory_error:
1656 kfree(tx);
1657 return ret;
Patrick Boettchera75763f2006-10-18 08:34:16 -03001658}
1659EXPORT_SYMBOL(dib7000pc_detection);
1660
Olivier Grenie713d54a2011-01-04 04:54:31 -03001661struct i2c_adapter *dib7000p_get_i2c_master(struct dvb_frontend *demod, enum dibx000_i2c_interface intf, int gating)
Patrick Boettchera75763f2006-10-18 08:34:16 -03001662{
1663 struct dib7000p_state *st = demod->demodulator_priv;
1664 return dibx000_get_i2c_adapter(&st->i2c_master, intf, gating);
1665}
1666EXPORT_SYMBOL(dib7000p_get_i2c_master);
1667
Olivier Grenief8731f42009-09-18 04:08:43 -03001668int dib7000p_pid_filter_ctrl(struct dvb_frontend *fe, u8 onoff)
1669{
Olivier Grenie713d54a2011-01-04 04:54:31 -03001670 struct dib7000p_state *state = fe->demodulator_priv;
1671 u16 val = dib7000p_read_word(state, 235) & 0xffef;
1672 val |= (onoff & 0x1) << 4;
1673 dprintk("PID filter enabled %d", onoff);
1674 return dib7000p_write_word(state, 235, val);
Olivier Grenief8731f42009-09-18 04:08:43 -03001675}
1676EXPORT_SYMBOL(dib7000p_pid_filter_ctrl);
1677
1678int dib7000p_pid_filter(struct dvb_frontend *fe, u8 id, u16 pid, u8 onoff)
1679{
Olivier Grenie713d54a2011-01-04 04:54:31 -03001680 struct dib7000p_state *state = fe->demodulator_priv;
1681 dprintk("PID filter: index %x, PID %d, OnOff %d", id, pid, onoff);
1682 return dib7000p_write_word(state, 241 + id, onoff ? (1 << 13) | pid : 0);
Olivier Grenief8731f42009-09-18 04:08:43 -03001683}
1684EXPORT_SYMBOL(dib7000p_pid_filter);
1685
Patrick Boettchera75763f2006-10-18 08:34:16 -03001686int dib7000p_i2c_enumeration(struct i2c_adapter *i2c, int no_of_demods, u8 default_addr, struct dib7000p_config cfg[])
1687{
Randy Dunlap30d81bb2010-02-08 20:30:44 -03001688 struct dib7000p_state *dpst;
Patrick Boettchera75763f2006-10-18 08:34:16 -03001689 int k = 0;
1690 u8 new_addr = 0;
1691
Randy Dunlap30d81bb2010-02-08 20:30:44 -03001692 dpst = kzalloc(sizeof(struct dib7000p_state), GFP_KERNEL);
1693 if (!dpst)
Andrew Morton0b427602010-04-27 19:09:45 -03001694 return -ENOMEM;
Randy Dunlap30d81bb2010-02-08 20:30:44 -03001695
1696 dpst->i2c_adap = i2c;
Patrick Boettcher79fcce32011-08-03 12:08:21 -03001697 mutex_init(&dpst->i2c_buffer_lock);
Randy Dunlap30d81bb2010-02-08 20:30:44 -03001698
Olivier Grenie713d54a2011-01-04 04:54:31 -03001699 for (k = no_of_demods - 1; k >= 0; k--) {
Randy Dunlap30d81bb2010-02-08 20:30:44 -03001700 dpst->cfg = cfg[k];
Patrick Boettchera75763f2006-10-18 08:34:16 -03001701
1702 /* designated i2c address */
Olivier Grenie713d54a2011-01-04 04:54:31 -03001703 if (cfg[k].default_i2c_addr != 0)
1704 new_addr = cfg[k].default_i2c_addr + (k << 1);
1705 else
1706 new_addr = (0x40 + k) << 1;
Randy Dunlap30d81bb2010-02-08 20:30:44 -03001707 dpst->i2c_addr = new_addr;
Olivier Grenie713d54a2011-01-04 04:54:31 -03001708 dib7000p_write_word(dpst, 1287, 0x0003); /* sram lead in, rdy */
Randy Dunlap30d81bb2010-02-08 20:30:44 -03001709 if (dib7000p_identify(dpst) != 0) {
1710 dpst->i2c_addr = default_addr;
Olivier Grenie713d54a2011-01-04 04:54:31 -03001711 dib7000p_write_word(dpst, 1287, 0x0003); /* sram lead in, rdy */
Randy Dunlap30d81bb2010-02-08 20:30:44 -03001712 if (dib7000p_identify(dpst) != 0) {
Patrick Boettchera75763f2006-10-18 08:34:16 -03001713 dprintk("DiB7000P #%d: not identified\n", k);
Randy Dunlap30d81bb2010-02-08 20:30:44 -03001714 kfree(dpst);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001715 return -EIO;
1716 }
1717 }
1718
1719 /* start diversity to pull_down div_str - just for i2c-enumeration */
Randy Dunlap30d81bb2010-02-08 20:30:44 -03001720 dib7000p_set_output_mode(dpst, OUTMODE_DIVERSITY);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001721
1722 /* set new i2c address and force divstart */
Randy Dunlap30d81bb2010-02-08 20:30:44 -03001723 dib7000p_write_word(dpst, 1285, (new_addr << 2) | 0x2);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001724
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001725 dprintk("IC %d initialized (to i2c_address 0x%x)", k, new_addr);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001726 }
1727
1728 for (k = 0; k < no_of_demods; k++) {
Randy Dunlap30d81bb2010-02-08 20:30:44 -03001729 dpst->cfg = cfg[k];
Olivier Grenie713d54a2011-01-04 04:54:31 -03001730 if (cfg[k].default_i2c_addr != 0)
1731 dpst->i2c_addr = (cfg[k].default_i2c_addr + k) << 1;
1732 else
1733 dpst->i2c_addr = (0x40 + k) << 1;
Patrick Boettchera75763f2006-10-18 08:34:16 -03001734
1735 // unforce divstr
Randy Dunlap30d81bb2010-02-08 20:30:44 -03001736 dib7000p_write_word(dpst, 1285, dpst->i2c_addr << 2);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001737
1738 /* deactivate div - it was just for i2c-enumeration */
Randy Dunlap30d81bb2010-02-08 20:30:44 -03001739 dib7000p_set_output_mode(dpst, OUTMODE_HIGH_Z);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001740 }
1741
Randy Dunlap30d81bb2010-02-08 20:30:44 -03001742 kfree(dpst);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001743 return 0;
1744}
1745EXPORT_SYMBOL(dib7000p_i2c_enumeration);
1746
Olivier Grenie713d54a2011-01-04 04:54:31 -03001747static const s32 lut_1000ln_mant[] = {
1748 6908, 6956, 7003, 7047, 7090, 7131, 7170, 7208, 7244, 7279, 7313, 7346, 7377, 7408, 7438, 7467, 7495, 7523, 7549, 7575, 7600
1749};
1750
1751static s32 dib7000p_get_adc_power(struct dvb_frontend *fe)
1752{
1753 struct dib7000p_state *state = fe->demodulator_priv;
1754 u32 tmp_val = 0, exp = 0, mant = 0;
1755 s32 pow_i;
1756 u16 buf[2];
1757 u8 ix = 0;
1758
1759 buf[0] = dib7000p_read_word(state, 0x184);
1760 buf[1] = dib7000p_read_word(state, 0x185);
1761 pow_i = (buf[0] << 16) | buf[1];
1762 dprintk("raw pow_i = %d", pow_i);
1763
1764 tmp_val = pow_i;
1765 while (tmp_val >>= 1)
1766 exp++;
1767
1768 mant = (pow_i * 1000 / (1 << exp));
1769 dprintk(" mant = %d exp = %d", mant / 1000, exp);
1770
1771 ix = (u8) ((mant - 1000) / 100); /* index of the LUT */
1772 dprintk(" ix = %d", ix);
1773
1774 pow_i = (lut_1000ln_mant[ix] + 693 * (exp - 20) - 6908);
1775 pow_i = (pow_i << 8) / 1000;
1776 dprintk(" pow_i = %d", pow_i);
1777
1778 return pow_i;
1779}
1780
1781static int map_addr_to_serpar_number(struct i2c_msg *msg)
1782{
1783 if ((msg->buf[0] <= 15))
1784 msg->buf[0] -= 1;
1785 else if (msg->buf[0] == 17)
1786 msg->buf[0] = 15;
1787 else if (msg->buf[0] == 16)
1788 msg->buf[0] = 17;
1789 else if (msg->buf[0] == 19)
1790 msg->buf[0] = 16;
1791 else if (msg->buf[0] >= 21 && msg->buf[0] <= 25)
1792 msg->buf[0] -= 3;
1793 else if (msg->buf[0] == 28)
1794 msg->buf[0] = 23;
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001795 else
Olivier Grenie713d54a2011-01-04 04:54:31 -03001796 return -EINVAL;
Olivier Grenie713d54a2011-01-04 04:54:31 -03001797 return 0;
1798}
1799
1800static int w7090p_tuner_write_serpar(struct i2c_adapter *i2c_adap, struct i2c_msg msg[], int num)
1801{
1802 struct dib7000p_state *state = i2c_get_adapdata(i2c_adap);
1803 u8 n_overflow = 1;
1804 u16 i = 1000;
1805 u16 serpar_num = msg[0].buf[0];
1806
1807 while (n_overflow == 1 && i) {
1808 n_overflow = (dib7000p_read_word(state, 1984) >> 1) & 0x1;
1809 i--;
1810 if (i == 0)
1811 dprintk("Tuner ITF: write busy (overflow)");
1812 }
1813 dib7000p_write_word(state, 1985, (1 << 6) | (serpar_num & 0x3f));
1814 dib7000p_write_word(state, 1986, (msg[0].buf[1] << 8) | msg[0].buf[2]);
1815
1816 return num;
1817}
1818
1819static int w7090p_tuner_read_serpar(struct i2c_adapter *i2c_adap, struct i2c_msg msg[], int num)
1820{
1821 struct dib7000p_state *state = i2c_get_adapdata(i2c_adap);
1822 u8 n_overflow = 1, n_empty = 1;
1823 u16 i = 1000;
1824 u16 serpar_num = msg[0].buf[0];
1825 u16 read_word;
1826
1827 while (n_overflow == 1 && i) {
1828 n_overflow = (dib7000p_read_word(state, 1984) >> 1) & 0x1;
1829 i--;
1830 if (i == 0)
1831 dprintk("TunerITF: read busy (overflow)");
1832 }
1833 dib7000p_write_word(state, 1985, (0 << 6) | (serpar_num & 0x3f));
1834
1835 i = 1000;
1836 while (n_empty == 1 && i) {
1837 n_empty = dib7000p_read_word(state, 1984) & 0x1;
1838 i--;
1839 if (i == 0)
1840 dprintk("TunerITF: read busy (empty)");
1841 }
1842 read_word = dib7000p_read_word(state, 1987);
1843 msg[1].buf[0] = (read_word >> 8) & 0xff;
1844 msg[1].buf[1] = (read_word) & 0xff;
1845
1846 return num;
1847}
1848
1849static int w7090p_tuner_rw_serpar(struct i2c_adapter *i2c_adap, struct i2c_msg msg[], int num)
1850{
1851 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... */
1852 if (num == 1) { /* write */
1853 return w7090p_tuner_write_serpar(i2c_adap, msg, 1);
1854 } else { /* read */
1855 return w7090p_tuner_read_serpar(i2c_adap, msg, 2);
1856 }
1857 }
1858 return num;
1859}
1860
1861int dib7090p_rw_on_apb(struct i2c_adapter *i2c_adap, struct i2c_msg msg[], int num, u16 apb_address)
1862{
1863 struct dib7000p_state *state = i2c_get_adapdata(i2c_adap);
1864 u16 word;
1865
1866 if (num == 1) { /* write */
1867 dib7000p_write_word(state, apb_address, ((msg[0].buf[1] << 8) | (msg[0].buf[2])));
1868 } else {
1869 word = dib7000p_read_word(state, apb_address);
1870 msg[1].buf[0] = (word >> 8) & 0xff;
1871 msg[1].buf[1] = (word) & 0xff;
1872 }
1873
1874 return num;
1875}
1876
1877static int dib7090_tuner_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg msg[], int num)
1878{
1879 struct dib7000p_state *state = i2c_get_adapdata(i2c_adap);
1880
1881 u16 apb_address = 0, word;
1882 int i = 0;
1883 switch (msg[0].buf[0]) {
1884 case 0x12:
1885 apb_address = 1920;
1886 break;
1887 case 0x14:
1888 apb_address = 1921;
1889 break;
1890 case 0x24:
1891 apb_address = 1922;
1892 break;
1893 case 0x1a:
1894 apb_address = 1923;
1895 break;
1896 case 0x22:
1897 apb_address = 1924;
1898 break;
1899 case 0x33:
1900 apb_address = 1926;
1901 break;
1902 case 0x34:
1903 apb_address = 1927;
1904 break;
1905 case 0x35:
1906 apb_address = 1928;
1907 break;
1908 case 0x36:
1909 apb_address = 1929;
1910 break;
1911 case 0x37:
1912 apb_address = 1930;
1913 break;
1914 case 0x38:
1915 apb_address = 1931;
1916 break;
1917 case 0x39:
1918 apb_address = 1932;
1919 break;
1920 case 0x2a:
1921 apb_address = 1935;
1922 break;
1923 case 0x2b:
1924 apb_address = 1936;
1925 break;
1926 case 0x2c:
1927 apb_address = 1937;
1928 break;
1929 case 0x2d:
1930 apb_address = 1938;
1931 break;
1932 case 0x2e:
1933 apb_address = 1939;
1934 break;
1935 case 0x2f:
1936 apb_address = 1940;
1937 break;
1938 case 0x30:
1939 apb_address = 1941;
1940 break;
1941 case 0x31:
1942 apb_address = 1942;
1943 break;
1944 case 0x32:
1945 apb_address = 1943;
1946 break;
1947 case 0x3e:
1948 apb_address = 1944;
1949 break;
1950 case 0x3f:
1951 apb_address = 1945;
1952 break;
1953 case 0x40:
1954 apb_address = 1948;
1955 break;
1956 case 0x25:
1957 apb_address = 914;
1958 break;
1959 case 0x26:
1960 apb_address = 915;
1961 break;
1962 case 0x27:
Olivier Grenie2e802862011-08-05 10:39:15 -03001963 apb_address = 917;
Olivier Grenie713d54a2011-01-04 04:54:31 -03001964 break;
1965 case 0x28:
Olivier Grenie2e802862011-08-05 10:39:15 -03001966 apb_address = 916;
Olivier Grenie713d54a2011-01-04 04:54:31 -03001967 break;
1968 case 0x1d:
1969 i = ((dib7000p_read_word(state, 72) >> 12) & 0x3);
1970 word = dib7000p_read_word(state, 384 + i);
1971 msg[1].buf[0] = (word >> 8) & 0xff;
1972 msg[1].buf[1] = (word) & 0xff;
1973 return num;
1974 case 0x1f:
1975 if (num == 1) { /* write */
1976 word = (u16) ((msg[0].buf[1] << 8) | msg[0].buf[2]);
1977 word &= 0x3;
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001978 word = (dib7000p_read_word(state, 72) & ~(3 << 12)) | (word << 12);
Olivier Grenie713d54a2011-01-04 04:54:31 -03001979 dib7000p_write_word(state, 72, word); /* Set the proper input */
1980 return num;
1981 }
1982 }
1983
1984 if (apb_address != 0) /* R/W acces via APB */
1985 return dib7090p_rw_on_apb(i2c_adap, msg, num, apb_address);
1986 else /* R/W access via SERPAR */
1987 return w7090p_tuner_rw_serpar(i2c_adap, msg, num);
1988
1989 return 0;
1990}
1991
1992static u32 dib7000p_i2c_func(struct i2c_adapter *adapter)
1993{
1994 return I2C_FUNC_I2C;
1995}
1996
1997static struct i2c_algorithm dib7090_tuner_xfer_algo = {
1998 .master_xfer = dib7090_tuner_xfer,
1999 .functionality = dib7000p_i2c_func,
2000};
2001
2002struct i2c_adapter *dib7090_get_i2c_tuner(struct dvb_frontend *fe)
2003{
2004 struct dib7000p_state *st = fe->demodulator_priv;
2005 return &st->dib7090_tuner_adap;
2006}
2007EXPORT_SYMBOL(dib7090_get_i2c_tuner);
2008
2009static int dib7090_host_bus_drive(struct dib7000p_state *state, u8 drive)
2010{
2011 u16 reg;
2012
2013 /* drive host bus 2, 3, 4 */
2014 reg = dib7000p_read_word(state, 1798) & ~((0x7) | (0x7 << 6) | (0x7 << 12));
2015 reg |= (drive << 12) | (drive << 6) | drive;
2016 dib7000p_write_word(state, 1798, reg);
2017
2018 /* drive host bus 5,6 */
2019 reg = dib7000p_read_word(state, 1799) & ~((0x7 << 2) | (0x7 << 8));
2020 reg |= (drive << 8) | (drive << 2);
2021 dib7000p_write_word(state, 1799, reg);
2022
2023 /* drive host bus 7, 8, 9 */
2024 reg = dib7000p_read_word(state, 1800) & ~((0x7) | (0x7 << 6) | (0x7 << 12));
2025 reg |= (drive << 12) | (drive << 6) | drive;
2026 dib7000p_write_word(state, 1800, reg);
2027
2028 /* drive host bus 10, 11 */
2029 reg = dib7000p_read_word(state, 1801) & ~((0x7 << 2) | (0x7 << 8));
2030 reg |= (drive << 8) | (drive << 2);
2031 dib7000p_write_word(state, 1801, reg);
2032
2033 /* drive host bus 12, 13, 14 */
2034 reg = dib7000p_read_word(state, 1802) & ~((0x7) | (0x7 << 6) | (0x7 << 12));
2035 reg |= (drive << 12) | (drive << 6) | drive;
2036 dib7000p_write_word(state, 1802, reg);
2037
2038 return 0;
2039}
2040
2041static u32 dib7090_calcSyncFreq(u32 P_Kin, u32 P_Kout, u32 insertExtSynchro, u32 syncSize)
2042{
2043 u32 quantif = 3;
2044 u32 nom = (insertExtSynchro * P_Kin + syncSize);
2045 u32 denom = P_Kout;
2046 u32 syncFreq = ((nom << quantif) / denom);
2047
2048 if ((syncFreq & ((1 << quantif) - 1)) != 0)
2049 syncFreq = (syncFreq >> quantif) + 1;
2050 else
2051 syncFreq = (syncFreq >> quantif);
2052
2053 if (syncFreq != 0)
2054 syncFreq = syncFreq - 1;
2055
2056 return syncFreq;
2057}
2058
2059static int dib7090_cfg_DibTx(struct dib7000p_state *state, u32 P_Kin, u32 P_Kout, u32 insertExtSynchro, u32 synchroMode, u32 syncWord, u32 syncSize)
2060{
Olivier Grenie713d54a2011-01-04 04:54:31 -03002061 dprintk("Configure DibStream Tx");
Olivier Grenie713d54a2011-01-04 04:54:31 -03002062
2063 dib7000p_write_word(state, 1615, 1);
2064 dib7000p_write_word(state, 1603, P_Kin);
2065 dib7000p_write_word(state, 1605, P_Kout);
2066 dib7000p_write_word(state, 1606, insertExtSynchro);
2067 dib7000p_write_word(state, 1608, synchroMode);
2068 dib7000p_write_word(state, 1609, (syncWord >> 16) & 0xffff);
2069 dib7000p_write_word(state, 1610, syncWord & 0xffff);
2070 dib7000p_write_word(state, 1612, syncSize);
2071 dib7000p_write_word(state, 1615, 0);
2072
Olivier Grenie713d54a2011-01-04 04:54:31 -03002073 return 0;
2074}
2075
2076static int dib7090_cfg_DibRx(struct dib7000p_state *state, u32 P_Kin, u32 P_Kout, u32 synchroMode, u32 insertExtSynchro, u32 syncWord, u32 syncSize,
2077 u32 dataOutRate)
2078{
2079 u32 syncFreq;
2080
2081 dprintk("Configure DibStream Rx");
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002082 if ((P_Kin != 0) && (P_Kout != 0)) {
Olivier Grenie713d54a2011-01-04 04:54:31 -03002083 syncFreq = dib7090_calcSyncFreq(P_Kin, P_Kout, insertExtSynchro, syncSize);
2084 dib7000p_write_word(state, 1542, syncFreq);
2085 }
2086 dib7000p_write_word(state, 1554, 1);
2087 dib7000p_write_word(state, 1536, P_Kin);
2088 dib7000p_write_word(state, 1537, P_Kout);
2089 dib7000p_write_word(state, 1539, synchroMode);
2090 dib7000p_write_word(state, 1540, (syncWord >> 16) & 0xffff);
2091 dib7000p_write_word(state, 1541, syncWord & 0xffff);
2092 dib7000p_write_word(state, 1543, syncSize);
2093 dib7000p_write_word(state, 1544, dataOutRate);
2094 dib7000p_write_word(state, 1554, 0);
2095
2096 return 0;
2097}
2098
Olivier Grenie2e802862011-08-05 10:39:15 -03002099static void dib7090_enMpegMux(struct dib7000p_state *state, int onoff)
Olivier Grenie713d54a2011-01-04 04:54:31 -03002100{
Olivier Grenie2e802862011-08-05 10:39:15 -03002101 u16 reg_1287 = dib7000p_read_word(state, 1287);
Olivier Grenie713d54a2011-01-04 04:54:31 -03002102
Olivier Grenie2e802862011-08-05 10:39:15 -03002103 switch (onoff) {
2104 case 1:
2105 reg_1287 &= ~(1<<7);
2106 break;
2107 case 0:
2108 reg_1287 |= (1<<7);
2109 break;
2110 }
Olivier Grenie713d54a2011-01-04 04:54:31 -03002111
Olivier Grenie2e802862011-08-05 10:39:15 -03002112 dib7000p_write_word(state, 1287, reg_1287);
Olivier Grenie713d54a2011-01-04 04:54:31 -03002113}
2114
Olivier Grenie2e802862011-08-05 10:39:15 -03002115static void dib7090_configMpegMux(struct dib7000p_state *state,
2116 u16 pulseWidth, u16 enSerialMode, u16 enSerialClkDiv2)
Olivier Grenie713d54a2011-01-04 04:54:31 -03002117{
Olivier Grenie713d54a2011-01-04 04:54:31 -03002118 dprintk("Enable Mpeg mux");
Olivier Grenie713d54a2011-01-04 04:54:31 -03002119
Olivier Grenie2e802862011-08-05 10:39:15 -03002120 dib7090_enMpegMux(state, 0);
Olivier Grenie713d54a2011-01-04 04:54:31 -03002121
Olivier Grenie2e802862011-08-05 10:39:15 -03002122 /* If the input mode is MPEG do not divide the serial clock */
2123 if ((enSerialMode == 1) && (state->input_mode_mpeg == 1))
2124 enSerialClkDiv2 = 0;
Olivier Grenie713d54a2011-01-04 04:54:31 -03002125
Olivier Grenie2e802862011-08-05 10:39:15 -03002126 dib7000p_write_word(state, 1287, ((pulseWidth & 0x1f) << 2)
2127 | ((enSerialMode & 0x1) << 1)
2128 | (enSerialClkDiv2 & 0x1));
2129
2130 dib7090_enMpegMux(state, 1);
Olivier Grenie713d54a2011-01-04 04:54:31 -03002131}
2132
Olivier Grenie2e802862011-08-05 10:39:15 -03002133static void dib7090_setDibTxMux(struct dib7000p_state *state, int mode)
Olivier Grenie713d54a2011-01-04 04:54:31 -03002134{
Olivier Grenie2e802862011-08-05 10:39:15 -03002135 u16 reg_1288 = dib7000p_read_word(state, 1288) & ~(0x7 << 7);
Olivier Grenie713d54a2011-01-04 04:54:31 -03002136
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002137 switch (mode) {
Olivier Grenie2e802862011-08-05 10:39:15 -03002138 case MPEG_ON_DIBTX:
2139 dprintk("SET MPEG ON DIBSTREAM TX");
2140 dib7090_cfg_DibTx(state, 8, 5, 0, 0, 0, 0);
2141 reg_1288 |= (1<<9);
Olivier Grenie713d54a2011-01-04 04:54:31 -03002142 break;
Olivier Grenie2e802862011-08-05 10:39:15 -03002143 case DIV_ON_DIBTX:
2144 dprintk("SET DIV_OUT ON DIBSTREAM TX");
2145 dib7090_cfg_DibTx(state, 5, 5, 0, 0, 0, 0);
2146 reg_1288 |= (1<<8);
Olivier Grenie713d54a2011-01-04 04:54:31 -03002147 break;
Olivier Grenie2e802862011-08-05 10:39:15 -03002148 case ADC_ON_DIBTX:
2149 dprintk("SET ADC_OUT ON DIBSTREAM TX");
2150 dib7090_cfg_DibTx(state, 20, 5, 10, 0, 0, 0);
2151 reg_1288 |= (1<<7);
2152 break;
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002153 default:
Olivier Grenie713d54a2011-01-04 04:54:31 -03002154 break;
2155 }
Olivier Grenie2e802862011-08-05 10:39:15 -03002156 dib7000p_write_word(state, 1288, reg_1288);
Olivier Grenie713d54a2011-01-04 04:54:31 -03002157}
2158
Olivier Grenie2e802862011-08-05 10:39:15 -03002159static void dib7090_setHostBusMux(struct dib7000p_state *state, int mode)
Olivier Grenie713d54a2011-01-04 04:54:31 -03002160{
Olivier Grenie2e802862011-08-05 10:39:15 -03002161 u16 reg_1288 = dib7000p_read_word(state, 1288) & ~(0x7 << 4);
2162
2163 switch (mode) {
2164 case DEMOUT_ON_HOSTBUS:
2165 dprintk("SET DEM OUT OLD INTERF ON HOST BUS");
2166 dib7090_enMpegMux(state, 0);
2167 reg_1288 |= (1<<6);
2168 break;
2169 case DIBTX_ON_HOSTBUS:
2170 dprintk("SET DIBSTREAM TX ON HOST BUS");
2171 dib7090_enMpegMux(state, 0);
2172 reg_1288 |= (1<<5);
2173 break;
2174 case MPEG_ON_HOSTBUS:
2175 dprintk("SET MPEG MUX ON HOST BUS");
2176 reg_1288 |= (1<<4);
2177 break;
2178 default:
2179 break;
2180 }
2181 dib7000p_write_word(state, 1288, reg_1288);
2182}
2183
2184int dib7090_set_diversity_in(struct dvb_frontend *fe, int onoff)
2185{
2186 struct dib7000p_state *state = fe->demodulator_priv;
2187 u16 reg_1287;
2188
Olivier Grenie713d54a2011-01-04 04:54:31 -03002189 switch (onoff) {
Olivier Grenie2e802862011-08-05 10:39:15 -03002190 case 0: /* only use the internal way - not the diversity input */
2191 dprintk("%s mode OFF : by default Enable Mpeg INPUT", __func__);
2192 dib7090_cfg_DibRx(state, 8, 5, 0, 0, 0, 8, 0);
2193
2194 /* Do not divide the serial clock of MPEG MUX */
2195 /* in SERIAL MODE in case input mode MPEG is used */
2196 reg_1287 = dib7000p_read_word(state, 1287);
2197 /* enSerialClkDiv2 == 1 ? */
2198 if ((reg_1287 & 0x1) == 1) {
2199 /* force enSerialClkDiv2 = 0 */
2200 reg_1287 &= ~0x1;
2201 dib7000p_write_word(state, 1287, reg_1287);
2202 }
2203 state->input_mode_mpeg = 1;
2204 break;
2205 case 1: /* both ways */
2206 case 2: /* only the diversity input */
2207 dprintk("%s ON : Enable diversity INPUT", __func__);
2208 dib7090_cfg_DibRx(state, 5, 5, 0, 0, 0, 0, 0);
2209 state->input_mode_mpeg = 0;
2210 break;
Olivier Grenie713d54a2011-01-04 04:54:31 -03002211 }
2212
Olivier Grenie2e802862011-08-05 10:39:15 -03002213 dib7000p_set_diversity_in(&state->demod, onoff);
Olivier Grenie713d54a2011-01-04 04:54:31 -03002214 return 0;
2215}
2216
2217static int dib7090_set_output_mode(struct dvb_frontend *fe, int mode)
2218{
2219 struct dib7000p_state *state = fe->demodulator_priv;
2220
2221 u16 outreg, smo_mode, fifo_threshold;
2222 u8 prefer_mpeg_mux_use = 1;
2223 int ret = 0;
2224
2225 dib7090_host_bus_drive(state, 1);
2226
2227 fifo_threshold = 1792;
2228 smo_mode = (dib7000p_read_word(state, 235) & 0x0050) | (1 << 1);
2229 outreg = dib7000p_read_word(state, 1286) & ~((1 << 10) | (0x7 << 6) | (1 << 1));
2230
2231 switch (mode) {
2232 case OUTMODE_HIGH_Z:
2233 outreg = 0;
2234 break;
2235
2236 case OUTMODE_MPEG2_SERIAL:
2237 if (prefer_mpeg_mux_use) {
Olivier Grenie2e802862011-08-05 10:39:15 -03002238 dprintk("setting output mode TS_SERIAL using Mpeg Mux");
2239 dib7090_configMpegMux(state, 3, 1, 1);
2240 dib7090_setHostBusMux(state, MPEG_ON_HOSTBUS);
2241 } else {/* Use Smooth block */
2242 dprintk("setting output mode TS_SERIAL using Smooth bloc");
2243 dib7090_setHostBusMux(state, DEMOUT_ON_HOSTBUS);
2244 outreg |= (2<<6) | (0 << 1);
Olivier Grenie713d54a2011-01-04 04:54:31 -03002245 }
2246 break;
2247
2248 case OUTMODE_MPEG2_PAR_GATED_CLK:
2249 if (prefer_mpeg_mux_use) {
Olivier Grenie2e802862011-08-05 10:39:15 -03002250 dprintk("setting output mode TS_PARALLEL_GATED using Mpeg Mux");
2251 dib7090_configMpegMux(state, 2, 0, 0);
2252 dib7090_setHostBusMux(state, MPEG_ON_HOSTBUS);
2253 } else { /* Use Smooth block */
2254 dprintk("setting output mode TS_PARALLEL_GATED using Smooth block");
2255 dib7090_setHostBusMux(state, DEMOUT_ON_HOSTBUS);
2256 outreg |= (0<<6);
Olivier Grenie713d54a2011-01-04 04:54:31 -03002257 }
2258 break;
2259
2260 case OUTMODE_MPEG2_PAR_CONT_CLK: /* Using Smooth block only */
Olivier Grenie2e802862011-08-05 10:39:15 -03002261 dprintk("setting output mode TS_PARALLEL_CONT using Smooth block");
2262 dib7090_setHostBusMux(state, DEMOUT_ON_HOSTBUS);
2263 outreg |= (1<<6);
Olivier Grenie713d54a2011-01-04 04:54:31 -03002264 break;
2265
2266 case OUTMODE_MPEG2_FIFO: /* Using Smooth block because not supported by new Mpeg Mux bloc */
Olivier Grenie2e802862011-08-05 10:39:15 -03002267 dprintk("setting output mode TS_FIFO using Smooth block");
2268 dib7090_setHostBusMux(state, DEMOUT_ON_HOSTBUS);
2269 outreg |= (5<<6);
Olivier Grenie713d54a2011-01-04 04:54:31 -03002270 smo_mode |= (3 << 1);
2271 fifo_threshold = 512;
2272 break;
2273
2274 case OUTMODE_DIVERSITY:
Olivier Grenie2e802862011-08-05 10:39:15 -03002275 dprintk("setting output mode MODE_DIVERSITY");
2276 dib7090_setDibTxMux(state, DIV_ON_DIBTX);
2277 dib7090_setHostBusMux(state, DIBTX_ON_HOSTBUS);
Olivier Grenie713d54a2011-01-04 04:54:31 -03002278 break;
2279
2280 case OUTMODE_ANALOG_ADC:
Olivier Grenie2e802862011-08-05 10:39:15 -03002281 dprintk("setting output mode MODE_ANALOG_ADC");
2282 dib7090_setDibTxMux(state, ADC_ON_DIBTX);
2283 dib7090_setHostBusMux(state, DIBTX_ON_HOSTBUS);
Olivier Grenie713d54a2011-01-04 04:54:31 -03002284 break;
2285 }
Olivier Grenie2e802862011-08-05 10:39:15 -03002286 if (mode != OUTMODE_HIGH_Z)
2287 outreg |= (1 << 10);
Olivier Grenie713d54a2011-01-04 04:54:31 -03002288
2289 if (state->cfg.output_mpeg2_in_188_bytes)
2290 smo_mode |= (1 << 5);
2291
2292 ret |= dib7000p_write_word(state, 235, smo_mode);
2293 ret |= dib7000p_write_word(state, 236, fifo_threshold); /* synchronous fread */
Olivier Grenie2e802862011-08-05 10:39:15 -03002294 ret |= dib7000p_write_word(state, 1286, outreg);
Olivier Grenie713d54a2011-01-04 04:54:31 -03002295
2296 return ret;
2297}
2298
2299int dib7090_tuner_sleep(struct dvb_frontend *fe, int onoff)
2300{
2301 struct dib7000p_state *state = fe->demodulator_priv;
2302 u16 en_cur_state;
2303
2304 dprintk("sleep dib7090: %d", onoff);
2305
2306 en_cur_state = dib7000p_read_word(state, 1922);
2307
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002308 if (en_cur_state > 0xff)
Olivier Grenie713d54a2011-01-04 04:54:31 -03002309 state->tuner_enable = en_cur_state;
Olivier Grenie713d54a2011-01-04 04:54:31 -03002310
2311 if (onoff)
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002312 en_cur_state &= 0x00ff;
Olivier Grenie713d54a2011-01-04 04:54:31 -03002313 else {
2314 if (state->tuner_enable != 0)
2315 en_cur_state = state->tuner_enable;
2316 }
2317
2318 dib7000p_write_word(state, 1922, en_cur_state);
2319
2320 return 0;
2321}
2322EXPORT_SYMBOL(dib7090_tuner_sleep);
2323
Olivier Grenie713d54a2011-01-04 04:54:31 -03002324int dib7090_get_adc_power(struct dvb_frontend *fe)
2325{
2326 return dib7000p_get_adc_power(fe);
2327}
2328EXPORT_SYMBOL(dib7090_get_adc_power);
2329
2330int dib7090_slave_reset(struct dvb_frontend *fe)
2331{
2332 struct dib7000p_state *state = fe->demodulator_priv;
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002333 u16 reg;
Olivier Grenie713d54a2011-01-04 04:54:31 -03002334
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002335 reg = dib7000p_read_word(state, 1794);
2336 dib7000p_write_word(state, 1794, reg | (4 << 12));
Olivier Grenie713d54a2011-01-04 04:54:31 -03002337
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002338 dib7000p_write_word(state, 1032, 0xffff);
2339 return 0;
Olivier Grenie713d54a2011-01-04 04:54:31 -03002340}
2341EXPORT_SYMBOL(dib7090_slave_reset);
2342
Patrick Boettchera75763f2006-10-18 08:34:16 -03002343static struct dvb_frontend_ops dib7000p_ops;
Olivier Grenie713d54a2011-01-04 04:54:31 -03002344struct dvb_frontend *dib7000p_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr, struct dib7000p_config *cfg)
Patrick Boettchera75763f2006-10-18 08:34:16 -03002345{
2346 struct dvb_frontend *demod;
2347 struct dib7000p_state *st;
2348 st = kzalloc(sizeof(struct dib7000p_state), GFP_KERNEL);
2349 if (st == NULL)
2350 return NULL;
2351
2352 memcpy(&st->cfg, cfg, sizeof(struct dib7000p_config));
2353 st->i2c_adap = i2c_adap;
2354 st->i2c_addr = i2c_addr;
2355 st->gpio_val = cfg->gpio_val;
2356 st->gpio_dir = cfg->gpio_dir;
2357
Steven Totha38d6e32008-04-22 15:37:01 -03002358 /* Ensure the output mode remains at the previous default if it's
2359 * not specifically set by the caller.
2360 */
Olivier Grenie713d54a2011-01-04 04:54:31 -03002361 if ((st->cfg.output_mode != OUTMODE_MPEG2_SERIAL) && (st->cfg.output_mode != OUTMODE_MPEG2_PAR_GATED_CLK))
Steven Totha38d6e32008-04-22 15:37:01 -03002362 st->cfg.output_mode = OUTMODE_MPEG2_FIFO;
2363
Olivier Grenie713d54a2011-01-04 04:54:31 -03002364 demod = &st->demod;
Patrick Boettchera75763f2006-10-18 08:34:16 -03002365 demod->demodulator_priv = st;
2366 memcpy(&st->demod.ops, &dib7000p_ops, sizeof(struct dvb_frontend_ops));
Patrick Boettcher79fcce32011-08-03 12:08:21 -03002367 mutex_init(&st->i2c_buffer_lock);
Patrick Boettchera75763f2006-10-18 08:34:16 -03002368
Olivier Grenie713d54a2011-01-04 04:54:31 -03002369 dib7000p_write_word(st, 1287, 0x0003); /* sram lead in, rdy */
Olivier Grenieeac1fe12009-09-23 13:41:27 -03002370
Patrick Boettchera75763f2006-10-18 08:34:16 -03002371 if (dib7000p_identify(st) != 0)
2372 goto error;
2373
Olivier Grenie713d54a2011-01-04 04:54:31 -03002374 st->version = dib7000p_read_word(st, 897);
2375
Martin Samek7646b9d2009-09-30 22:59:09 -03002376 /* FIXME: make sure the dev.parent field is initialized, or else
Patrick Boettcher79fcce32011-08-03 12:08:21 -03002377 request_firmware() will hit an OOPS (this should be moved somewhere
2378 more common) */
2379 st->i2c_master.gated_tuner_i2c_adap.dev.parent = i2c_adap->dev.parent;
Martin Samek7646b9d2009-09-30 22:59:09 -03002380
Devin Heitmueller85ec9d72009-07-20 00:45:25 -03002381 /* FIXME: make sure the dev.parent field is initialized, or else
2382 request_firmware() will hit an OOPS (this should be moved somewhere
2383 more common) */
2384 st->i2c_master.gated_tuner_i2c_adap.dev.parent = i2c_adap->dev.parent;
2385
Patrick Boettchera75763f2006-10-18 08:34:16 -03002386 dibx000_init_i2c_master(&st->i2c_master, DIB7000P, st->i2c_adap, st->i2c_addr);
2387
Olivier Grenie713d54a2011-01-04 04:54:31 -03002388 /* init 7090 tuner adapter */
2389 strncpy(st->dib7090_tuner_adap.name, "DiB7090 tuner interface", sizeof(st->dib7090_tuner_adap.name));
2390 st->dib7090_tuner_adap.algo = &dib7090_tuner_xfer_algo;
2391 st->dib7090_tuner_adap.algo_data = NULL;
2392 st->dib7090_tuner_adap.dev.parent = st->i2c_adap->dev.parent;
2393 i2c_set_adapdata(&st->dib7090_tuner_adap, st);
2394 i2c_add_adapter(&st->dib7090_tuner_adap);
2395
Patrick Boettchera75763f2006-10-18 08:34:16 -03002396 dib7000p_demod_reset(st);
2397
Olivier Grenie713d54a2011-01-04 04:54:31 -03002398 if (st->version == SOC7090) {
2399 dib7090_set_output_mode(demod, st->cfg.output_mode);
2400 dib7090_set_diversity_in(demod, 0);
2401 }
2402
Patrick Boettchera75763f2006-10-18 08:34:16 -03002403 return demod;
2404
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002405error:
Patrick Boettchera75763f2006-10-18 08:34:16 -03002406 kfree(st);
2407 return NULL;
2408}
2409EXPORT_SYMBOL(dib7000p_attach);
2410
2411static struct dvb_frontend_ops dib7000p_ops = {
2412 .info = {
Olivier Grenie713d54a2011-01-04 04:54:31 -03002413 .name = "DiBcom 7000PC",
2414 .type = FE_OFDM,
2415 .frequency_min = 44250000,
2416 .frequency_max = 867250000,
2417 .frequency_stepsize = 62500,
2418 .caps = FE_CAN_INVERSION_AUTO |
2419 FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
2420 FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
2421 FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO |
2422 FE_CAN_TRANSMISSION_MODE_AUTO | FE_CAN_GUARD_INTERVAL_AUTO | FE_CAN_RECOVER | FE_CAN_HIERARCHY_AUTO,
2423 },
Patrick Boettchera75763f2006-10-18 08:34:16 -03002424
Olivier Grenie713d54a2011-01-04 04:54:31 -03002425 .release = dib7000p_release,
Patrick Boettchera75763f2006-10-18 08:34:16 -03002426
Olivier Grenie713d54a2011-01-04 04:54:31 -03002427 .init = dib7000p_wakeup,
2428 .sleep = dib7000p_sleep,
Patrick Boettchera75763f2006-10-18 08:34:16 -03002429
Olivier Grenie713d54a2011-01-04 04:54:31 -03002430 .set_frontend = dib7000p_set_frontend,
2431 .get_tune_settings = dib7000p_fe_get_tune_settings,
2432 .get_frontend = dib7000p_get_frontend,
Patrick Boettchera75763f2006-10-18 08:34:16 -03002433
Olivier Grenie713d54a2011-01-04 04:54:31 -03002434 .read_status = dib7000p_read_status,
2435 .read_ber = dib7000p_read_ber,
Patrick Boettchera75763f2006-10-18 08:34:16 -03002436 .read_signal_strength = dib7000p_read_signal_strength,
Olivier Grenie713d54a2011-01-04 04:54:31 -03002437 .read_snr = dib7000p_read_snr,
2438 .read_ucblocks = dib7000p_read_unc_blocks,
Patrick Boettchera75763f2006-10-18 08:34:16 -03002439};
2440
Olivier Grenie713d54a2011-01-04 04:54:31 -03002441MODULE_AUTHOR("Olivier Grenie <ogrenie@dibcom.fr>");
Patrick Boettchera75763f2006-10-18 08:34:16 -03002442MODULE_AUTHOR("Patrick Boettcher <pboettcher@dibcom.fr>");
2443MODULE_DESCRIPTION("Driver for the DiBcom 7000PC COFDM demodulator");
2444MODULE_LICENSE("GPL");