blob: 0c9f40c2a251fbaad72fe3520e6f6ec48d76cb13 [file] [log] [blame]
Patrick Boettchera75763f2006-10-18 08:34:16 -03001/*
2 * Linux-DVB Driver for DiBcom's second generation DiB7000P (PC).
3 *
Patrick Boettcherb6884a12007-07-27 10:08:51 -03004 * Copyright (C) 2005-7 DiBcom (http://www.dibcom.fr/)
Patrick Boettchera75763f2006-10-18 08:34:16 -03005 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License as
8 * published by the Free Software Foundation, version 2.
9 */
10#include <linux/kernel.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090011#include <linux/slab.h>
Patrick Boettchera75763f2006-10-18 08:34:16 -030012#include <linux/i2c.h>
13
Olivier Grenieef801962009-09-15 06:46:52 -030014#include "dvb_math.h"
Patrick Boettchera75763f2006-10-18 08:34:16 -030015#include "dvb_frontend.h"
16
17#include "dib7000p.h"
18
19static int debug;
20module_param(debug, int, 0644);
21MODULE_PARM_DESC(debug, "turn on debugging (default: 0)");
22
Matt Doran8f6956c2007-07-31 07:09:30 -030023static int buggy_sfn_workaround;
24module_param(buggy_sfn_workaround, int, 0644);
Patrick Boettcher8d999962007-07-31 10:36:06 -030025MODULE_PARM_DESC(buggy_sfn_workaround, "Enable work-around for buggy SFNs (default: 0)");
Matt Doran8f6956c2007-07-31 07:09:30 -030026
Patrick Boettcherb6884a12007-07-27 10:08:51 -030027#define dprintk(args...) do { if (debug) { printk(KERN_DEBUG "DiB7000P: "); printk(args); printk("\n"); } } while (0)
Patrick Boettchera75763f2006-10-18 08:34:16 -030028
Olivier Grenie713d54a2011-01-04 04:54:31 -030029struct i2c_device {
30 struct i2c_adapter *i2c_adap;
31 u8 i2c_addr;
32};
33
Patrick Boettchera75763f2006-10-18 08:34:16 -030034struct dib7000p_state {
35 struct dvb_frontend demod;
Olivier Grenie713d54a2011-01-04 04:54:31 -030036 struct dib7000p_config cfg;
Patrick Boettchera75763f2006-10-18 08:34:16 -030037
38 u8 i2c_addr;
Olivier Grenie713d54a2011-01-04 04:54:31 -030039 struct i2c_adapter *i2c_adap;
Patrick Boettchera75763f2006-10-18 08:34:16 -030040
41 struct dibx000_i2c_master i2c_master;
42
43 u16 wbd_ref;
44
Olivier Grenie713d54a2011-01-04 04:54:31 -030045 u8 current_band;
Patrick Boettcher904a82e2008-01-25 07:31:58 -030046 u32 current_bandwidth;
Patrick Boettchera75763f2006-10-18 08:34:16 -030047 struct dibx000_agc_config *current_agc;
48 u32 timf;
49
Olivier Grenie713d54a2011-01-04 04:54:31 -030050 u8 div_force_off:1;
51 u8 div_state:1;
Patrick Boettcher01373a52007-07-30 12:49:04 -030052 u16 div_sync_wait;
Patrick Boettcherb6884a12007-07-27 10:08:51 -030053
54 u8 agc_state;
55
Patrick Boettchera75763f2006-10-18 08:34:16 -030056 u16 gpio_dir;
57 u16 gpio_val;
Matt Doran8f6956c2007-07-31 07:09:30 -030058
Olivier Grenie713d54a2011-01-04 04:54:31 -030059 u8 sfn_workaround_active:1;
60
61#define SOC7090 0x7090
62 u16 version;
63
64 u16 tuner_enable;
65 struct i2c_adapter dib7090_tuner_adap;
Olivier Grenie5a0deee2011-05-03 12:27:33 -030066
67 /* for the I2C transfer */
68 struct i2c_msg msg[2];
69 u8 i2c_write_buffer[4];
70 u8 i2c_read_buffer[2];
Patrick Boettchera75763f2006-10-18 08:34:16 -030071};
72
73enum dib7000p_power_mode {
74 DIB7000P_POWER_ALL = 0,
Patrick Boettcherb6884a12007-07-27 10:08:51 -030075 DIB7000P_POWER_ANALOG_ADC,
Patrick Boettchera75763f2006-10-18 08:34:16 -030076 DIB7000P_POWER_INTERFACE_ONLY,
77};
78
Olivier Grenie713d54a2011-01-04 04:54:31 -030079static int dib7090_set_output_mode(struct dvb_frontend *fe, int mode);
80static int dib7090_set_diversity_in(struct dvb_frontend *fe, int onoff);
81
Patrick Boettchera75763f2006-10-18 08:34:16 -030082static u16 dib7000p_read_word(struct dib7000p_state *state, u16 reg)
83{
Olivier Grenie5a0deee2011-05-03 12:27:33 -030084 state->i2c_write_buffer[0] = reg >> 8;
85 state->i2c_write_buffer[1] = reg & 0xff;
Patrick Boettchera75763f2006-10-18 08:34:16 -030086
Olivier Grenie5a0deee2011-05-03 12:27:33 -030087 memset(state->msg, 0, 2 * sizeof(struct i2c_msg));
88 state->msg[0].addr = state->i2c_addr >> 1;
89 state->msg[0].flags = 0;
90 state->msg[0].buf = state->i2c_write_buffer;
91 state->msg[0].len = 2;
92 state->msg[1].addr = state->i2c_addr >> 1;
93 state->msg[1].flags = I2C_M_RD;
94 state->msg[1].buf = state->i2c_read_buffer;
95 state->msg[1].len = 2;
96
97 if (i2c_transfer(state->i2c_adap, state->msg, 2) != 2)
Olivier Grenie713d54a2011-01-04 04:54:31 -030098 dprintk("i2c read error on %d", reg);
Patrick Boettchera75763f2006-10-18 08:34:16 -030099
Olivier Grenie5a0deee2011-05-03 12:27:33 -0300100 return (state->i2c_read_buffer[0] << 8) | state->i2c_read_buffer[1];
Patrick Boettchera75763f2006-10-18 08:34:16 -0300101}
102
103static int dib7000p_write_word(struct dib7000p_state *state, u16 reg, u16 val)
104{
Olivier Grenie5a0deee2011-05-03 12:27:33 -0300105 state->i2c_write_buffer[0] = (reg >> 8) & 0xff;
106 state->i2c_write_buffer[1] = reg & 0xff;
107 state->i2c_write_buffer[2] = (val >> 8) & 0xff;
108 state->i2c_write_buffer[3] = val & 0xff;
109
110 memset(&state->msg[0], 0, sizeof(struct i2c_msg));
111 state->msg[0].addr = state->i2c_addr >> 1;
112 state->msg[0].flags = 0;
113 state->msg[0].buf = state->i2c_write_buffer;
114 state->msg[0].len = 4;
115
116 return i2c_transfer(state->i2c_adap, state->msg, 1) != 1 ? -EREMOTEIO : 0;
Patrick Boettchera75763f2006-10-18 08:34:16 -0300117}
Olivier Grenie713d54a2011-01-04 04:54:31 -0300118
119static void dib7000p_write_tab(struct dib7000p_state *state, u16 * buf)
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300120{
121 u16 l = 0, r, *n;
122 n = buf;
123 l = *n++;
124 while (l) {
125 r = *n++;
126
127 do {
128 dib7000p_write_word(state, r, *n++);
129 r++;
130 } while (--l);
131 l = *n++;
132 }
133}
134
Patrick Boettchera75763f2006-10-18 08:34:16 -0300135static int dib7000p_set_output_mode(struct dib7000p_state *state, int mode)
136{
Olivier Grenie713d54a2011-01-04 04:54:31 -0300137 int ret = 0;
Patrick Boettchera75763f2006-10-18 08:34:16 -0300138 u16 outreg, fifo_threshold, smo_mode;
139
140 outreg = 0;
141 fifo_threshold = 1792;
Olivier Grenieeac1fe12009-09-23 13:41:27 -0300142 smo_mode = (dib7000p_read_word(state, 235) & 0x0050) | (1 << 1);
Patrick Boettchera75763f2006-10-18 08:34:16 -0300143
Olivier Grenie713d54a2011-01-04 04:54:31 -0300144 dprintk("setting output mode for demod %p to %d", &state->demod, mode);
Patrick Boettchera75763f2006-10-18 08:34:16 -0300145
146 switch (mode) {
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300147 case OUTMODE_MPEG2_PAR_GATED_CLK:
Olivier Grenie713d54a2011-01-04 04:54:31 -0300148 outreg = (1 << 10); /* 0x0400 */
149 break;
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300150 case OUTMODE_MPEG2_PAR_CONT_CLK:
Olivier Grenie713d54a2011-01-04 04:54:31 -0300151 outreg = (1 << 10) | (1 << 6); /* 0x0440 */
152 break;
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300153 case OUTMODE_MPEG2_SERIAL:
Olivier Grenie713d54a2011-01-04 04:54:31 -0300154 outreg = (1 << 10) | (2 << 6) | (0 << 1); /* 0x0480 */
155 break;
156 case OUTMODE_DIVERSITY:
157 if (state->cfg.hostbus_diversity)
158 outreg = (1 << 10) | (4 << 6); /* 0x0500 */
159 else
160 outreg = (1 << 11);
161 break;
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300162 case OUTMODE_MPEG2_FIFO:
Olivier Grenie713d54a2011-01-04 04:54:31 -0300163 smo_mode |= (3 << 1);
164 fifo_threshold = 512;
165 outreg = (1 << 10) | (5 << 6);
166 break;
167 case OUTMODE_ANALOG_ADC:
168 outreg = (1 << 10) | (3 << 6);
169 break;
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300170 case OUTMODE_HIGH_Z:
Olivier Grenie713d54a2011-01-04 04:54:31 -0300171 outreg = 0;
172 break;
173 default:
174 dprintk("Unhandled output_mode passed to be set for demod %p", &state->demod);
175 break;
Patrick Boettchera75763f2006-10-18 08:34:16 -0300176 }
177
178 if (state->cfg.output_mpeg2_in_188_bytes)
Olivier Grenie713d54a2011-01-04 04:54:31 -0300179 smo_mode |= (1 << 5);
Patrick Boettchera75763f2006-10-18 08:34:16 -0300180
Olivier Grenie713d54a2011-01-04 04:54:31 -0300181 ret |= dib7000p_write_word(state, 235, smo_mode);
182 ret |= dib7000p_write_word(state, 236, fifo_threshold); /* synchronous fread */
183 if (state->version != SOC7090)
184 ret |= dib7000p_write_word(state, 1286, outreg); /* P_Div_active */
Patrick Boettchera75763f2006-10-18 08:34:16 -0300185
186 return ret;
187}
188
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300189static int dib7000p_set_diversity_in(struct dvb_frontend *demod, int onoff)
190{
191 struct dib7000p_state *state = demod->demodulator_priv;
192
193 if (state->div_force_off) {
Olivier Grenie713d54a2011-01-04 04:54:31 -0300194 dprintk("diversity combination deactivated - forced by COFDM parameters");
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300195 onoff = 0;
Olivier Grenieeac1fe12009-09-23 13:41:27 -0300196 dib7000p_write_word(state, 207, 0);
197 } else
198 dib7000p_write_word(state, 207, (state->div_sync_wait << 4) | (1 << 2) | (2 << 0));
199
Olivier Grenie713d54a2011-01-04 04:54:31 -0300200 state->div_state = (u8) onoff;
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300201
202 if (onoff) {
203 dib7000p_write_word(state, 204, 6);
204 dib7000p_write_word(state, 205, 16);
205 /* P_dvsy_sync_mode = 0, P_dvsy_sync_enable=1, P_dvcb_comb_mode=2 */
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300206 } else {
207 dib7000p_write_word(state, 204, 1);
208 dib7000p_write_word(state, 205, 0);
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300209 }
210
211 return 0;
212}
213
Patrick Boettchera75763f2006-10-18 08:34:16 -0300214static int dib7000p_set_power_mode(struct dib7000p_state *state, enum dib7000p_power_mode mode)
215{
216 /* by default everything is powered off */
Olivier Grenie713d54a2011-01-04 04:54:31 -0300217 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 -0300218
219 /* now, depending on the requested mode, we power on */
220 switch (mode) {
221 /* power up everything in the demod */
Olivier Grenie713d54a2011-01-04 04:54:31 -0300222 case DIB7000P_POWER_ALL:
223 reg_774 = 0x0000;
224 reg_775 = 0x0000;
225 reg_776 = 0x0;
226 reg_899 = 0x0;
227 if (state->version == SOC7090)
228 reg_1280 &= 0x001f;
229 else
230 reg_1280 &= 0x01ff;
231 break;
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300232
Olivier Grenie713d54a2011-01-04 04:54:31 -0300233 case DIB7000P_POWER_ANALOG_ADC:
234 /* dem, cfg, iqc, sad, agc */
235 reg_774 &= ~((1 << 15) | (1 << 14) | (1 << 11) | (1 << 10) | (1 << 9));
236 /* nud */
237 reg_776 &= ~((1 << 0));
238 /* Dout */
239 if (state->version != SOC7090)
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300240 reg_1280 &= ~((1 << 11));
Olivier Grenie713d54a2011-01-04 04:54:31 -0300241 reg_1280 &= ~(1 << 6);
242 /* fall through wanted to enable the interfaces */
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300243
Patrick Boettchera75763f2006-10-18 08:34:16 -0300244 /* just leave power on the control-interfaces: GPIO and (I2C or SDIO) */
Olivier Grenie713d54a2011-01-04 04:54:31 -0300245 case DIB7000P_POWER_INTERFACE_ONLY: /* TODO power up either SDIO or I2C */
246 if (state->version == SOC7090)
247 reg_1280 &= ~((1 << 7) | (1 << 5));
248 else
Patrick Boettchera75763f2006-10-18 08:34:16 -0300249 reg_1280 &= ~((1 << 14) | (1 << 13) | (1 << 12) | (1 << 10));
Olivier Grenie713d54a2011-01-04 04:54:31 -0300250 break;
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300251
Patrick Boettchera75763f2006-10-18 08:34:16 -0300252/* TODO following stuff is just converted from the dib7000-driver - check when is used what */
253 }
254
Olivier Grenie713d54a2011-01-04 04:54:31 -0300255 dib7000p_write_word(state, 774, reg_774);
256 dib7000p_write_word(state, 775, reg_775);
257 dib7000p_write_word(state, 776, reg_776);
258 dib7000p_write_word(state, 899, reg_899);
Patrick Boettchera75763f2006-10-18 08:34:16 -0300259 dib7000p_write_word(state, 1280, reg_1280);
260
261 return 0;
262}
263
264static void dib7000p_set_adc_state(struct dib7000p_state *state, enum dibx000_adc_states no)
265{
Olivier Grenie713d54a2011-01-04 04:54:31 -0300266 u16 reg_908 = dib7000p_read_word(state, 908), reg_909 = dib7000p_read_word(state, 909);
267 u16 reg;
Patrick Boettchera75763f2006-10-18 08:34:16 -0300268
269 switch (no) {
Olivier Grenie713d54a2011-01-04 04:54:31 -0300270 case DIBX000_SLOW_ADC_ON:
271 if (state->version == SOC7090) {
272 reg = dib7000p_read_word(state, 1925);
273
274 dib7000p_write_word(state, 1925, reg | (1 << 4) | (1 << 2)); /* en_slowAdc = 1 & reset_sladc = 1 */
275
276 reg = dib7000p_read_word(state, 1925); /* read acces to make it works... strange ... */
277 msleep(200);
278 dib7000p_write_word(state, 1925, reg & ~(1 << 4)); /* en_slowAdc = 1 & reset_sladc = 0 */
279
280 reg = dib7000p_read_word(state, 72) & ~((0x3 << 14) | (0x3 << 12));
281 dib7000p_write_word(state, 72, reg | (1 << 14) | (3 << 12) | 524); /* ref = Vin1 => Vbg ; sel = Vin0 or Vin3 ; (Vin2 = Vcm) */
282 } else {
Patrick Boettchera75763f2006-10-18 08:34:16 -0300283 reg_909 |= (1 << 1) | (1 << 0);
284 dib7000p_write_word(state, 909, reg_909);
285 reg_909 &= ~(1 << 1);
Olivier Grenie713d54a2011-01-04 04:54:31 -0300286 }
287 break;
Patrick Boettchera75763f2006-10-18 08:34:16 -0300288
Olivier Grenie713d54a2011-01-04 04:54:31 -0300289 case DIBX000_SLOW_ADC_OFF:
290 if (state->version == SOC7090) {
291 reg = dib7000p_read_word(state, 1925);
292 dib7000p_write_word(state, 1925, (reg & ~(1 << 2)) | (1 << 4)); /* reset_sladc = 1 en_slowAdc = 0 */
293 } else
294 reg_909 |= (1 << 1) | (1 << 0);
295 break;
Patrick Boettchera75763f2006-10-18 08:34:16 -0300296
Olivier Grenie713d54a2011-01-04 04:54:31 -0300297 case DIBX000_ADC_ON:
298 reg_908 &= 0x0fff;
299 reg_909 &= 0x0003;
300 break;
Patrick Boettchera75763f2006-10-18 08:34:16 -0300301
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300302 case DIBX000_ADC_OFF:
Olivier Grenie713d54a2011-01-04 04:54:31 -0300303 reg_908 |= (1 << 14) | (1 << 13) | (1 << 12);
304 reg_909 |= (1 << 5) | (1 << 4) | (1 << 3) | (1 << 2);
305 break;
Patrick Boettchera75763f2006-10-18 08:34:16 -0300306
Olivier Grenie713d54a2011-01-04 04:54:31 -0300307 case DIBX000_VBG_ENABLE:
308 reg_908 &= ~(1 << 15);
309 break;
Patrick Boettchera75763f2006-10-18 08:34:16 -0300310
Olivier Grenie713d54a2011-01-04 04:54:31 -0300311 case DIBX000_VBG_DISABLE:
312 reg_908 |= (1 << 15);
313 break;
Patrick Boettchera75763f2006-10-18 08:34:16 -0300314
Olivier Grenie713d54a2011-01-04 04:54:31 -0300315 default:
316 break;
Patrick Boettchera75763f2006-10-18 08:34:16 -0300317 }
318
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300319// dprintk( "908: %x, 909: %x\n", reg_908, reg_909);
Patrick Boettchera75763f2006-10-18 08:34:16 -0300320
Olivier Grenie970d14c2010-09-07 12:50:46 -0300321 reg_909 |= (state->cfg.disable_sample_and_hold & 1) << 4;
Olivier Grenie90e12ce2010-09-07 12:50:45 -0300322 reg_908 |= (state->cfg.enable_current_mirror & 1) << 7;
323
Patrick Boettchera75763f2006-10-18 08:34:16 -0300324 dib7000p_write_word(state, 908, reg_908);
325 dib7000p_write_word(state, 909, reg_909);
326}
327
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300328static int dib7000p_set_bandwidth(struct dib7000p_state *state, u32 bw)
Patrick Boettchera75763f2006-10-18 08:34:16 -0300329{
Patrick Boettchera75763f2006-10-18 08:34:16 -0300330 u32 timf;
331
332 // store the current bandwidth for later use
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300333 state->current_bandwidth = bw;
Patrick Boettchera75763f2006-10-18 08:34:16 -0300334
335 if (state->timf == 0) {
Olivier Grenie713d54a2011-01-04 04:54:31 -0300336 dprintk("using default timf");
Patrick Boettchera75763f2006-10-18 08:34:16 -0300337 timf = state->cfg.bw->timf;
338 } else {
Olivier Grenie713d54a2011-01-04 04:54:31 -0300339 dprintk("using updated timf");
Patrick Boettchera75763f2006-10-18 08:34:16 -0300340 timf = state->timf;
341 }
342
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300343 timf = timf * (bw / 50) / 160;
Patrick Boettchera75763f2006-10-18 08:34:16 -0300344
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300345 dib7000p_write_word(state, 23, (u16) ((timf >> 16) & 0xffff));
Olivier Grenie713d54a2011-01-04 04:54:31 -0300346 dib7000p_write_word(state, 24, (u16) ((timf) & 0xffff));
Patrick Boettchera75763f2006-10-18 08:34:16 -0300347
348 return 0;
349}
350
351static int dib7000p_sad_calib(struct dib7000p_state *state)
352{
353/* internal */
Patrick Boettchera75763f2006-10-18 08:34:16 -0300354 dib7000p_write_word(state, 73, (0 << 1) | (0 << 0));
Olivier Grenie713d54a2011-01-04 04:54:31 -0300355
356 if (state->version == SOC7090)
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300357 dib7000p_write_word(state, 74, 2048);
Olivier Grenie713d54a2011-01-04 04:54:31 -0300358 else
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300359 dib7000p_write_word(state, 74, 776);
Patrick Boettchera75763f2006-10-18 08:34:16 -0300360
361 /* do the calibration */
362 dib7000p_write_word(state, 73, (1 << 0));
363 dib7000p_write_word(state, 73, (0 << 0));
364
365 msleep(1);
366
367 return 0;
368}
369
Patrick Boettcher01373a52007-07-30 12:49:04 -0300370int dib7000p_set_wbd_ref(struct dvb_frontend *demod, u16 value)
371{
372 struct dib7000p_state *state = demod->demodulator_priv;
373 if (value > 4095)
374 value = 4095;
375 state->wbd_ref = value;
376 return dib7000p_write_word(state, 105, (dib7000p_read_word(state, 105) & 0xf000) | value);
377}
Patrick Boettcher01373a52007-07-30 12:49:04 -0300378EXPORT_SYMBOL(dib7000p_set_wbd_ref);
Olivier Grenie713d54a2011-01-04 04:54:31 -0300379
Patrick Boettchera75763f2006-10-18 08:34:16 -0300380static void dib7000p_reset_pll(struct dib7000p_state *state)
381{
382 struct dibx000_bandwidth_config *bw = &state->cfg.bw[0];
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300383 u16 clk_cfg0;
Patrick Boettchera75763f2006-10-18 08:34:16 -0300384
Olivier Grenie713d54a2011-01-04 04:54:31 -0300385 if (state->version == SOC7090) {
386 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 -0300387
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300388 while (((dib7000p_read_word(state, 1856) >> 15) & 0x1) != 1)
389 ;
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300390
Olivier Grenie713d54a2011-01-04 04:54:31 -0300391 dib7000p_write_word(state, 1857, dib7000p_read_word(state, 1857) | (!bw->pll_bypass << 15));
392 } else {
393 /* force PLL bypass */
394 clk_cfg0 = (1 << 15) | ((bw->pll_ratio & 0x3f) << 9) |
395 (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 -0300396
Olivier Grenie713d54a2011-01-04 04:54:31 -0300397 dib7000p_write_word(state, 900, clk_cfg0);
398
399 /* P_pll_cfg */
400 dib7000p_write_word(state, 903, (bw->pll_prediv << 5) | (((bw->pll_ratio >> 6) & 0x3) << 3) | (bw->pll_range << 1) | bw->pll_reset);
401 clk_cfg0 = (bw->pll_bypass << 15) | (clk_cfg0 & 0x7fff);
402 dib7000p_write_word(state, 900, clk_cfg0);
403 }
404
405 dib7000p_write_word(state, 18, (u16) (((bw->internal * 1000) >> 16) & 0xffff));
406 dib7000p_write_word(state, 19, (u16) ((bw->internal * 1000) & 0xffff));
407 dib7000p_write_word(state, 21, (u16) ((bw->ifreq >> 16) & 0xffff));
408 dib7000p_write_word(state, 22, (u16) ((bw->ifreq) & 0xffff));
Patrick Boettchera75763f2006-10-18 08:34:16 -0300409
410 dib7000p_write_word(state, 72, bw->sad_cfg);
411}
412
Olivier Grenie713d54a2011-01-04 04:54:31 -0300413static u32 dib7000p_get_internal_freq(struct dib7000p_state *state)
414{
415 u32 internal = (u32) dib7000p_read_word(state, 18) << 16;
416 internal |= (u32) dib7000p_read_word(state, 19);
417 internal /= 1000;
418
419 return internal;
420}
421
422int dib7000p_update_pll(struct dvb_frontend *fe, struct dibx000_bandwidth_config *bw)
423{
424 struct dib7000p_state *state = fe->demodulator_priv;
425 u16 reg_1857, reg_1856 = dib7000p_read_word(state, 1856);
426 u8 loopdiv, prediv;
427 u32 internal, xtal;
428
429 /* get back old values */
430 prediv = reg_1856 & 0x3f;
431 loopdiv = (reg_1856 >> 6) & 0x3f;
432
433 if ((bw != NULL) && (bw->pll_prediv != prediv || bw->pll_ratio != loopdiv)) {
434 dprintk("Updating pll (prediv: old = %d new = %d ; loopdiv : old = %d new = %d)", prediv, bw->pll_prediv, loopdiv, bw->pll_ratio);
435 reg_1856 &= 0xf000;
436 reg_1857 = dib7000p_read_word(state, 1857);
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300437 dib7000p_write_word(state, 1857, reg_1857 & ~(1 << 15));
Olivier Grenie713d54a2011-01-04 04:54:31 -0300438
439 dib7000p_write_word(state, 1856, reg_1856 | ((bw->pll_ratio & 0x3f) << 6) | (bw->pll_prediv & 0x3f));
440
441 /* write new system clk into P_sec_len */
442 internal = dib7000p_get_internal_freq(state);
443 xtal = (internal / loopdiv) * prediv;
444 internal = 1000 * (xtal / bw->pll_prediv) * bw->pll_ratio; /* new internal */
445 dib7000p_write_word(state, 18, (u16) ((internal >> 16) & 0xffff));
446 dib7000p_write_word(state, 19, (u16) (internal & 0xffff));
447
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300448 dib7000p_write_word(state, 1857, reg_1857 | (1 << 15));
Olivier Grenie713d54a2011-01-04 04:54:31 -0300449
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300450 while (((dib7000p_read_word(state, 1856) >> 15) & 0x1) != 1)
Olivier Grenie713d54a2011-01-04 04:54:31 -0300451 dprintk("Waiting for PLL to lock");
Olivier Grenie713d54a2011-01-04 04:54:31 -0300452
453 return 0;
454 }
455 return -EIO;
456}
457EXPORT_SYMBOL(dib7000p_update_pll);
458
Patrick Boettchera75763f2006-10-18 08:34:16 -0300459static int dib7000p_reset_gpio(struct dib7000p_state *st)
460{
461 /* reset the GPIOs */
Olivier Grenie713d54a2011-01-04 04:54:31 -0300462 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 -0300463
464 dib7000p_write_word(st, 1029, st->gpio_dir);
465 dib7000p_write_word(st, 1030, st->gpio_val);
466
467 /* TODO 1031 is P_gpio_od */
468
469 dib7000p_write_word(st, 1032, st->cfg.gpio_pwm_pos);
470
471 dib7000p_write_word(st, 1037, st->cfg.pwm_freq_div);
472 return 0;
473}
474
Patrick Boettcher01373a52007-07-30 12:49:04 -0300475static int dib7000p_cfg_gpio(struct dib7000p_state *st, u8 num, u8 dir, u8 val)
476{
477 st->gpio_dir = dib7000p_read_word(st, 1029);
Olivier Grenie713d54a2011-01-04 04:54:31 -0300478 st->gpio_dir &= ~(1 << num); /* reset the direction bit */
479 st->gpio_dir |= (dir & 0x1) << num; /* set the new direction */
Patrick Boettcher01373a52007-07-30 12:49:04 -0300480 dib7000p_write_word(st, 1029, st->gpio_dir);
481
482 st->gpio_val = dib7000p_read_word(st, 1030);
Olivier Grenie713d54a2011-01-04 04:54:31 -0300483 st->gpio_val &= ~(1 << num); /* reset the direction bit */
484 st->gpio_val |= (val & 0x01) << num; /* set the new value */
Patrick Boettcher01373a52007-07-30 12:49:04 -0300485 dib7000p_write_word(st, 1030, st->gpio_val);
486
487 return 0;
488}
489
490int dib7000p_set_gpio(struct dvb_frontend *demod, u8 num, u8 dir, u8 val)
491{
492 struct dib7000p_state *state = demod->demodulator_priv;
493 return dib7000p_cfg_gpio(state, num, dir, val);
494}
Patrick Boettcher01373a52007-07-30 12:49:04 -0300495EXPORT_SYMBOL(dib7000p_set_gpio);
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300496
Olivier Grenie713d54a2011-01-04 04:54:31 -0300497static u16 dib7000p_defaults[] = {
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300498 // auto search configuration
499 3, 2,
Olivier Grenie713d54a2011-01-04 04:54:31 -0300500 0x0004,
501 0x1000,
502 0x0814, /* Equal Lock */
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300503
504 12, 6,
Olivier Grenie713d54a2011-01-04 04:54:31 -0300505 0x001b,
506 0x7740,
507 0x005b,
508 0x8d80,
509 0x01c9,
510 0xc380,
511 0x0000,
512 0x0080,
513 0x0000,
514 0x0090,
515 0x0001,
516 0xd4c0,
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300517
518 1, 26,
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300519 0x6680,
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300520
521 /* set ADC level to -16 */
522 11, 79,
Olivier Grenie713d54a2011-01-04 04:54:31 -0300523 (1 << 13) - 825 - 117,
524 (1 << 13) - 837 - 117,
525 (1 << 13) - 811 - 117,
526 (1 << 13) - 766 - 117,
527 (1 << 13) - 737 - 117,
528 (1 << 13) - 693 - 117,
529 (1 << 13) - 648 - 117,
530 (1 << 13) - 619 - 117,
531 (1 << 13) - 575 - 117,
532 (1 << 13) - 531 - 117,
533 (1 << 13) - 501 - 117,
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300534
535 1, 142,
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300536 0x0410,
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300537
538 /* disable power smoothing */
539 8, 145,
Olivier Grenie713d54a2011-01-04 04:54:31 -0300540 0,
541 0,
542 0,
543 0,
544 0,
545 0,
546 0,
547 0,
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300548
549 1, 154,
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300550 1 << 13,
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300551
552 1, 168,
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300553 0x0ccd,
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300554
555 1, 183,
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300556 0x200f,
Olivier Grenie713d54a2011-01-04 04:54:31 -0300557
558 1, 212,
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300559 0x169,
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300560
561 5, 187,
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300562 0x023d,
563 0x00a4,
564 0x00a4,
565 0x7ff0,
566 0x3ccc,
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300567
568 1, 198,
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300569 0x800,
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300570
571 1, 222,
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300572 0x0010,
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300573
574 1, 235,
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300575 0x0062,
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300576
577 2, 901,
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300578 0x0006,
579 (3 << 10) | (1 << 6),
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300580
581 1, 905,
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300582 0x2c8e,
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300583
584 0,
585};
586
Patrick Boettchera75763f2006-10-18 08:34:16 -0300587static int dib7000p_demod_reset(struct dib7000p_state *state)
588{
589 dib7000p_set_power_mode(state, DIB7000P_POWER_ALL);
590
Olivier Grenie713d54a2011-01-04 04:54:31 -0300591 if (state->version == SOC7090)
592 dibx000_reset_i2c_master(&state->i2c_master);
593
Patrick Boettchera75763f2006-10-18 08:34:16 -0300594 dib7000p_set_adc_state(state, DIBX000_VBG_ENABLE);
595
596 /* restart all parts */
Olivier Grenie713d54a2011-01-04 04:54:31 -0300597 dib7000p_write_word(state, 770, 0xffff);
598 dib7000p_write_word(state, 771, 0xffff);
599 dib7000p_write_word(state, 772, 0x001f);
600 dib7000p_write_word(state, 898, 0x0003);
601 dib7000p_write_word(state, 1280, 0x001f - ((1 << 4) | (1 << 3)));
Patrick Boettchera75763f2006-10-18 08:34:16 -0300602
Olivier Grenie713d54a2011-01-04 04:54:31 -0300603 dib7000p_write_word(state, 770, 0);
604 dib7000p_write_word(state, 771, 0);
605 dib7000p_write_word(state, 772, 0);
606 dib7000p_write_word(state, 898, 0);
Patrick Boettchera75763f2006-10-18 08:34:16 -0300607 dib7000p_write_word(state, 1280, 0);
608
609 /* default */
610 dib7000p_reset_pll(state);
611
612 if (dib7000p_reset_gpio(state) != 0)
Olivier Grenie713d54a2011-01-04 04:54:31 -0300613 dprintk("GPIO reset was not successful.");
Patrick Boettchera75763f2006-10-18 08:34:16 -0300614
Olivier Grenie713d54a2011-01-04 04:54:31 -0300615 if (state->version == SOC7090) {
616 dib7000p_write_word(state, 899, 0);
617
618 /* impulse noise */
619 dib7000p_write_word(state, 42, (1<<5) | 3); /* P_iqc_thsat_ipc = 1 ; P_iqc_win2 = 3 */
620 dib7000p_write_word(state, 43, 0x2d4); /*-300 fag P_iqc_dect_min = -280 */
621 dib7000p_write_word(state, 44, 300); /* 300 fag P_iqc_dect_min = +280 */
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300622 dib7000p_write_word(state, 273, (1<<6) | 30);
Olivier Grenie713d54a2011-01-04 04:54:31 -0300623 }
Patrick Boettchera75763f2006-10-18 08:34:16 -0300624 if (dib7000p_set_output_mode(state, OUTMODE_HIGH_Z) != 0)
Olivier Grenie713d54a2011-01-04 04:54:31 -0300625 dprintk("OUTPUT_MODE could not be reset.");
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300626
627 dib7000p_set_adc_state(state, DIBX000_SLOW_ADC_ON);
628 dib7000p_sad_calib(state);
629 dib7000p_set_adc_state(state, DIBX000_SLOW_ADC_OFF);
630
Olivier Grenie713d54a2011-01-04 04:54:31 -0300631 /* unforce divstr regardless whether i2c enumeration was done or not */
632 dib7000p_write_word(state, 1285, dib7000p_read_word(state, 1285) & ~(1 << 1));
633
634 dib7000p_set_bandwidth(state, 8000);
635
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300636 if (state->version == SOC7090) {
Olivier Grenie713d54a2011-01-04 04:54:31 -0300637 dib7000p_write_word(state, 36, 0x5755);/* P_iqc_impnc_on =1 & P_iqc_corr_inh = 1 for impulsive noise */
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300638 } else {
Olivier Grenie713d54a2011-01-04 04:54:31 -0300639 if (state->cfg.tuner_is_baseband)
640 dib7000p_write_word(state, 36, 0x0755);
641 else
642 dib7000p_write_word(state, 36, 0x1f55);
643 }
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300644
645 dib7000p_write_tab(state, dib7000p_defaults);
646
Patrick Boettchera75763f2006-10-18 08:34:16 -0300647 dib7000p_set_power_mode(state, DIB7000P_POWER_INTERFACE_ONLY);
648
649 return 0;
650}
651
Patrick Boettchera75763f2006-10-18 08:34:16 -0300652static void dib7000p_pll_clk_cfg(struct dib7000p_state *state)
653{
654 u16 tmp = 0;
655 tmp = dib7000p_read_word(state, 903);
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300656 dib7000p_write_word(state, 903, (tmp | 0x1));
Patrick Boettchera75763f2006-10-18 08:34:16 -0300657 tmp = dib7000p_read_word(state, 900);
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300658 dib7000p_write_word(state, 900, (tmp & 0x7fff) | (1 << 6));
Patrick Boettchera75763f2006-10-18 08:34:16 -0300659}
660
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300661static void dib7000p_restart_agc(struct dib7000p_state *state)
Patrick Boettchera75763f2006-10-18 08:34:16 -0300662{
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300663 // P_restart_iqc & P_restart_agc
664 dib7000p_write_word(state, 770, (1 << 11) | (1 << 9));
665 dib7000p_write_word(state, 770, 0x0000);
Patrick Boettchera75763f2006-10-18 08:34:16 -0300666}
667
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300668static int dib7000p_update_lna(struct dib7000p_state *state)
Patrick Boettchera75763f2006-10-18 08:34:16 -0300669{
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300670 u16 dyn_gain;
671
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300672 if (state->cfg.update_lna) {
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300673 dyn_gain = dib7000p_read_word(state, 394);
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300674 if (state->cfg.update_lna(&state->demod, dyn_gain)) {
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300675 dib7000p_restart_agc(state);
676 return 1;
677 }
678 }
679
680 return 0;
681}
682
683static int dib7000p_set_agc_config(struct dib7000p_state *state, u8 band)
684{
685 struct dibx000_agc_config *agc = NULL;
686 int i;
687 if (state->current_band == band && state->current_agc != NULL)
688 return 0;
689 state->current_band = band;
690
691 for (i = 0; i < state->cfg.agc_config_count; i++)
692 if (state->cfg.agc[i].band_caps & band) {
693 agc = &state->cfg.agc[i];
694 break;
695 }
696
697 if (agc == NULL) {
Olivier Grenie713d54a2011-01-04 04:54:31 -0300698 dprintk("no valid AGC configuration found for band 0x%02x", band);
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300699 return -EINVAL;
700 }
701
702 state->current_agc = agc;
703
704 /* AGC */
Olivier Grenie713d54a2011-01-04 04:54:31 -0300705 dib7000p_write_word(state, 75, agc->setup);
706 dib7000p_write_word(state, 76, agc->inv_gain);
707 dib7000p_write_word(state, 77, agc->time_stabiliz);
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300708 dib7000p_write_word(state, 100, (agc->alpha_level << 12) | agc->thlock);
709
710 // Demod AGC loop configuration
711 dib7000p_write_word(state, 101, (agc->alpha_mant << 5) | agc->alpha_exp);
Olivier Grenie713d54a2011-01-04 04:54:31 -0300712 dib7000p_write_word(state, 102, (agc->beta_mant << 6) | agc->beta_exp);
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300713
714 /* AGC continued */
Olivier Grenie713d54a2011-01-04 04:54:31 -0300715 dprintk("WBD: ref: %d, sel: %d, active: %d, alpha: %d",
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300716 state->wbd_ref != 0 ? state->wbd_ref : agc->wbd_ref, agc->wbd_sel, !agc->perform_agc_softsplit, agc->wbd_sel);
717
718 if (state->wbd_ref != 0)
719 dib7000p_write_word(state, 105, (agc->wbd_inv << 12) | state->wbd_ref);
720 else
721 dib7000p_write_word(state, 105, (agc->wbd_inv << 12) | agc->wbd_ref);
722
723 dib7000p_write_word(state, 106, (agc->wbd_sel << 13) | (agc->wbd_alpha << 9) | (agc->perform_agc_softsplit << 8));
724
Olivier Grenie713d54a2011-01-04 04:54:31 -0300725 dib7000p_write_word(state, 107, agc->agc1_max);
726 dib7000p_write_word(state, 108, agc->agc1_min);
727 dib7000p_write_word(state, 109, agc->agc2_max);
728 dib7000p_write_word(state, 110, agc->agc2_min);
729 dib7000p_write_word(state, 111, (agc->agc1_pt1 << 8) | agc->agc1_pt2);
730 dib7000p_write_word(state, 112, agc->agc1_pt3);
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300731 dib7000p_write_word(state, 113, (agc->agc1_slope1 << 8) | agc->agc1_slope2);
Olivier Grenie713d54a2011-01-04 04:54:31 -0300732 dib7000p_write_word(state, 114, (agc->agc2_pt1 << 8) | agc->agc2_pt2);
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300733 dib7000p_write_word(state, 115, (agc->agc2_slope1 << 8) | agc->agc2_slope2);
734 return 0;
735}
736
Olivier Grenie713d54a2011-01-04 04:54:31 -0300737static void dib7000p_set_dds(struct dib7000p_state *state, s32 offset_khz)
738{
739 u32 internal = dib7000p_get_internal_freq(state);
740 s32 unit_khz_dds_val = 67108864 / (internal); /* 2**26 / Fsampling is the unit 1KHz offset */
741 u32 abs_offset_khz = ABS(offset_khz);
742 u32 dds = state->cfg.bw->ifreq & 0x1ffffff;
743 u8 invert = !!(state->cfg.bw->ifreq & (1 << 25));
744
745 dprintk("setting a frequency offset of %dkHz internal freq = %d invert = %d", offset_khz, internal, invert);
746
747 if (offset_khz < 0)
748 unit_khz_dds_val *= -1;
749
750 /* IF tuner */
751 if (invert)
752 dds -= (abs_offset_khz * unit_khz_dds_val); /* /100 because of /100 on the unit_khz_dds_val line calc for better accuracy */
753 else
754 dds += (abs_offset_khz * unit_khz_dds_val);
755
756 if (abs_offset_khz <= (internal / 2)) { /* Max dds offset is the half of the demod freq */
757 dib7000p_write_word(state, 21, (u16) (((dds >> 16) & 0x1ff) | (0 << 10) | (invert << 9)));
758 dib7000p_write_word(state, 22, (u16) (dds & 0xffff));
759 }
760}
761
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300762static int dib7000p_agc_startup(struct dvb_frontend *demod, struct dvb_frontend_parameters *ch)
763{
764 struct dib7000p_state *state = demod->demodulator_priv;
765 int ret = -1;
766 u8 *agc_state = &state->agc_state;
767 u8 agc_split;
Olivier Grenie713d54a2011-01-04 04:54:31 -0300768 u16 reg;
769 u32 upd_demod_gain_period = 0x1000;
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300770
771 switch (state->agc_state) {
Olivier Grenie713d54a2011-01-04 04:54:31 -0300772 case 0:
Olivier Grenie713d54a2011-01-04 04:54:31 -0300773 dib7000p_set_power_mode(state, DIB7000P_POWER_ALL);
774 if (state->version == SOC7090) {
775 reg = dib7000p_read_word(state, 0x79b) & 0xff00;
776 dib7000p_write_word(state, 0x79a, upd_demod_gain_period & 0xFFFF); /* lsb */
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300777 dib7000p_write_word(state, 0x79b, reg | (1 << 14) | ((upd_demod_gain_period >> 16) & 0xFF));
Olivier Grenie713d54a2011-01-04 04:54:31 -0300778
779 /* enable adc i & q */
780 reg = dib7000p_read_word(state, 0x780);
781 dib7000p_write_word(state, 0x780, (reg | (0x3)) & (~(1 << 7)));
782 } else {
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300783 dib7000p_set_adc_state(state, DIBX000_ADC_ON);
784 dib7000p_pll_clk_cfg(state);
Olivier Grenie713d54a2011-01-04 04:54:31 -0300785 }
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300786
Olivier Grenie713d54a2011-01-04 04:54:31 -0300787 if (dib7000p_set_agc_config(state, BAND_OF_FREQUENCY(ch->frequency / 1000)) != 0)
788 return -1;
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300789
Olivier Grenie713d54a2011-01-04 04:54:31 -0300790 dib7000p_set_dds(state, 0);
791 ret = 7;
792 (*agc_state)++;
793 break;
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300794
Olivier Grenie713d54a2011-01-04 04:54:31 -0300795 case 1:
Olivier Grenie713d54a2011-01-04 04:54:31 -0300796 if (state->cfg.agc_control)
797 state->cfg.agc_control(&state->demod, 1);
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300798
Olivier Grenie713d54a2011-01-04 04:54:31 -0300799 dib7000p_write_word(state, 78, 32768);
800 if (!state->current_agc->perform_agc_softsplit) {
801 /* we are using the wbd - so slow AGC startup */
802 /* force 0 split on WBD and restart AGC */
803 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 -0300804 (*agc_state)++;
805 ret = 5;
Olivier Grenie713d54a2011-01-04 04:54:31 -0300806 } else {
807 /* default AGC startup */
808 (*agc_state) = 4;
809 /* wait AGC rough lock time */
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300810 ret = 7;
Olivier Grenie713d54a2011-01-04 04:54:31 -0300811 }
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300812
Olivier Grenie713d54a2011-01-04 04:54:31 -0300813 dib7000p_restart_agc(state);
814 break;
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300815
Olivier Grenie713d54a2011-01-04 04:54:31 -0300816 case 2: /* fast split search path after 5sec */
817 dib7000p_write_word(state, 75, state->current_agc->setup | (1 << 4)); /* freeze AGC loop */
818 dib7000p_write_word(state, 106, (state->current_agc->wbd_sel << 13) | (2 << 9) | (0 << 8)); /* fast split search 0.25kHz */
819 (*agc_state)++;
820 ret = 14;
821 break;
822
823 case 3: /* split search ended */
824 agc_split = (u8) dib7000p_read_word(state, 396); /* store the split value for the next time */
825 dib7000p_write_word(state, 78, dib7000p_read_word(state, 394)); /* set AGC gain start value */
826
827 dib7000p_write_word(state, 75, state->current_agc->setup); /* std AGC loop */
828 dib7000p_write_word(state, 106, (state->current_agc->wbd_sel << 13) | (state->current_agc->wbd_alpha << 9) | agc_split); /* standard split search */
829
830 dib7000p_restart_agc(state);
831
832 dprintk("SPLIT %p: %hd", demod, agc_split);
833
834 (*agc_state)++;
835 ret = 5;
836 break;
837
838 case 4: /* LNA startup */
Olivier Grenie713d54a2011-01-04 04:54:31 -0300839 ret = 7;
840
841 if (dib7000p_update_lna(state))
Olivier Grenie713d54a2011-01-04 04:54:31 -0300842 ret = 5;
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300843 else
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300844 (*agc_state)++;
Olivier Grenie713d54a2011-01-04 04:54:31 -0300845 break;
846
847 case 5:
848 if (state->cfg.agc_control)
849 state->cfg.agc_control(&state->demod, 0);
850 (*agc_state)++;
851 break;
852 default:
853 break;
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300854 }
855 return ret;
856}
857
858static void dib7000p_update_timf(struct dib7000p_state *state)
859{
860 u32 timf = (dib7000p_read_word(state, 427) << 16) | dib7000p_read_word(state, 428);
861 state->timf = timf * 160 / (state->current_bandwidth / 50);
862 dib7000p_write_word(state, 23, (u16) (timf >> 16));
863 dib7000p_write_word(state, 24, (u16) (timf & 0xffff));
Olivier Grenie713d54a2011-01-04 04:54:31 -0300864 dprintk("updated timf_frequency: %d (default: %d)", state->timf, state->cfg.bw->timf);
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300865
866}
867
Olivier Grenie713d54a2011-01-04 04:54:31 -0300868u32 dib7000p_ctrl_timf(struct dvb_frontend *fe, u8 op, u32 timf)
869{
870 struct dib7000p_state *state = fe->demodulator_priv;
871 switch (op) {
872 case DEMOD_TIMF_SET:
873 state->timf = timf;
874 break;
875 case DEMOD_TIMF_UPDATE:
876 dib7000p_update_timf(state);
877 break;
878 case DEMOD_TIMF_GET:
879 break;
880 }
881 dib7000p_set_bandwidth(state, state->current_bandwidth);
882 return state->timf;
883}
884EXPORT_SYMBOL(dib7000p_ctrl_timf);
885
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300886static void dib7000p_set_channel(struct dib7000p_state *state, struct dvb_frontend_parameters *ch, u8 seq)
887{
888 u16 value, est[4];
889
Olivier Grenie713d54a2011-01-04 04:54:31 -0300890 dib7000p_set_bandwidth(state, BANDWIDTH_TO_KHZ(ch->u.ofdm.bandwidth));
Patrick Boettchera75763f2006-10-18 08:34:16 -0300891
892 /* nfft, guard, qam, alpha */
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300893 value = 0;
894 switch (ch->u.ofdm.transmission_mode) {
Olivier Grenie713d54a2011-01-04 04:54:31 -0300895 case TRANSMISSION_MODE_2K:
896 value |= (0 << 7);
897 break;
Mauro Carvalho Chehab46f72962011-01-16 13:01:20 -0200898 case TRANSMISSION_MODE_4K:
Olivier Grenie713d54a2011-01-04 04:54:31 -0300899 value |= (2 << 7);
900 break;
901 default:
902 case TRANSMISSION_MODE_8K:
903 value |= (1 << 7);
904 break;
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300905 }
906 switch (ch->u.ofdm.guard_interval) {
Olivier Grenie713d54a2011-01-04 04:54:31 -0300907 case GUARD_INTERVAL_1_32:
908 value |= (0 << 5);
909 break;
910 case GUARD_INTERVAL_1_16:
911 value |= (1 << 5);
912 break;
913 case GUARD_INTERVAL_1_4:
914 value |= (3 << 5);
915 break;
916 default:
917 case GUARD_INTERVAL_1_8:
918 value |= (2 << 5);
919 break;
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300920 }
921 switch (ch->u.ofdm.constellation) {
Olivier Grenie713d54a2011-01-04 04:54:31 -0300922 case QPSK:
923 value |= (0 << 3);
924 break;
925 case QAM_16:
926 value |= (1 << 3);
927 break;
928 default:
929 case QAM_64:
930 value |= (2 << 3);
931 break;
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300932 }
933 switch (HIERARCHY_1) {
Olivier Grenie713d54a2011-01-04 04:54:31 -0300934 case HIERARCHY_2:
935 value |= 2;
936 break;
937 case HIERARCHY_4:
938 value |= 4;
939 break;
940 default:
941 case HIERARCHY_1:
942 value |= 1;
943 break;
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300944 }
945 dib7000p_write_word(state, 0, value);
Olivier Grenie713d54a2011-01-04 04:54:31 -0300946 dib7000p_write_word(state, 5, (seq << 4) | 1); /* do not force tps, search list 0 */
Patrick Boettchera75763f2006-10-18 08:34:16 -0300947
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300948 /* P_dintl_native, P_dintlv_inv, P_hrch, P_code_rate, P_select_hp */
949 value = 0;
950 if (1 != 0)
951 value |= (1 << 6);
952 if (ch->u.ofdm.hierarchy_information == 1)
953 value |= (1 << 4);
954 if (1 == 1)
955 value |= 1;
956 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 -0300957 case FEC_2_3:
958 value |= (2 << 1);
959 break;
960 case FEC_3_4:
961 value |= (3 << 1);
962 break;
963 case FEC_5_6:
964 value |= (5 << 1);
965 break;
966 case FEC_7_8:
967 value |= (7 << 1);
968 break;
969 default:
970 case FEC_1_2:
971 value |= (1 << 1);
972 break;
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300973 }
974 dib7000p_write_word(state, 208, value);
975
976 /* offset loop parameters */
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300977 dib7000p_write_word(state, 26, 0x6680);
978 dib7000p_write_word(state, 32, 0x0003);
979 dib7000p_write_word(state, 29, 0x1273);
980 dib7000p_write_word(state, 33, 0x0005);
Patrick Boettchera75763f2006-10-18 08:34:16 -0300981
982 /* P_dvsy_sync_wait */
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300983 switch (ch->u.ofdm.transmission_mode) {
Olivier Grenie713d54a2011-01-04 04:54:31 -0300984 case TRANSMISSION_MODE_8K:
985 value = 256;
986 break;
987 case TRANSMISSION_MODE_4K:
988 value = 128;
989 break;
990 case TRANSMISSION_MODE_2K:
991 default:
992 value = 64;
993 break;
Patrick Boettchera75763f2006-10-18 08:34:16 -0300994 }
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300995 switch (ch->u.ofdm.guard_interval) {
Olivier Grenie713d54a2011-01-04 04:54:31 -0300996 case GUARD_INTERVAL_1_16:
997 value *= 2;
998 break;
999 case GUARD_INTERVAL_1_8:
1000 value *= 4;
1001 break;
1002 case GUARD_INTERVAL_1_4:
1003 value *= 8;
1004 break;
1005 default:
1006 case GUARD_INTERVAL_1_32:
1007 value *= 1;
1008 break;
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001009 }
Olivier Grenie970d14c2010-09-07 12:50:46 -03001010 if (state->cfg.diversity_delay == 0)
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001011 state->div_sync_wait = (value * 3) / 2 + 48;
Olivier Grenie970d14c2010-09-07 12:50:46 -03001012 else
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001013 state->div_sync_wait = (value * 3) / 2 + state->cfg.diversity_delay;
Patrick Boettchera75763f2006-10-18 08:34:16 -03001014
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001015 /* deactive the possibility of diversity reception if extended interleaver */
1016 state->div_force_off = !1 && ch->u.ofdm.transmission_mode != TRANSMISSION_MODE_8K;
1017 dib7000p_set_diversity_in(&state->demod, state->div_state);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001018
1019 /* channel estimation fine configuration */
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001020 switch (ch->u.ofdm.constellation) {
Olivier Grenie713d54a2011-01-04 04:54:31 -03001021 case QAM_64:
1022 est[0] = 0x0148; /* P_adp_regul_cnt 0.04 */
1023 est[1] = 0xfff0; /* P_adp_noise_cnt -0.002 */
1024 est[2] = 0x00a4; /* P_adp_regul_ext 0.02 */
1025 est[3] = 0xfff8; /* P_adp_noise_ext -0.001 */
1026 break;
1027 case QAM_16:
1028 est[0] = 0x023d; /* P_adp_regul_cnt 0.07 */
1029 est[1] = 0xffdf; /* P_adp_noise_cnt -0.004 */
1030 est[2] = 0x00a4; /* P_adp_regul_ext 0.02 */
1031 est[3] = 0xfff0; /* P_adp_noise_ext -0.002 */
1032 break;
1033 default:
1034 est[0] = 0x099a; /* P_adp_regul_cnt 0.3 */
1035 est[1] = 0xffae; /* P_adp_noise_cnt -0.01 */
1036 est[2] = 0x0333; /* P_adp_regul_ext 0.1 */
1037 est[3] = 0xfff8; /* P_adp_noise_ext -0.002 */
1038 break;
Patrick Boettchera75763f2006-10-18 08:34:16 -03001039 }
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001040 for (value = 0; value < 4; value++)
1041 dib7000p_write_word(state, 187 + value, est[value]);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001042}
1043
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001044static int dib7000p_autosearch_start(struct dvb_frontend *demod, struct dvb_frontend_parameters *ch)
Patrick Boettchera75763f2006-10-18 08:34:16 -03001045{
1046 struct dib7000p_state *state = demod->demodulator_priv;
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001047 struct dvb_frontend_parameters schan;
1048 u32 value, factor;
Olivier Grenie713d54a2011-01-04 04:54:31 -03001049 u32 internal = dib7000p_get_internal_freq(state);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001050
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001051 schan = *ch;
1052 schan.u.ofdm.constellation = QAM_64;
Olivier Grenie713d54a2011-01-04 04:54:31 -03001053 schan.u.ofdm.guard_interval = GUARD_INTERVAL_1_32;
1054 schan.u.ofdm.transmission_mode = TRANSMISSION_MODE_8K;
1055 schan.u.ofdm.code_rate_HP = FEC_2_3;
1056 schan.u.ofdm.code_rate_LP = FEC_3_4;
1057 schan.u.ofdm.hierarchy_information = 0;
Patrick Boettchera75763f2006-10-18 08:34:16 -03001058
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001059 dib7000p_set_channel(state, &schan, 7);
1060
1061 factor = BANDWIDTH_TO_KHZ(ch->u.ofdm.bandwidth);
1062 if (factor >= 5000)
1063 factor = 1;
1064 else
1065 factor = 6;
Patrick Boettchera75763f2006-10-18 08:34:16 -03001066
Olivier Grenie713d54a2011-01-04 04:54:31 -03001067 value = 30 * internal * factor;
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001068 dib7000p_write_word(state, 6, (u16) ((value >> 16) & 0xffff));
1069 dib7000p_write_word(state, 7, (u16) (value & 0xffff));
Olivier Grenie713d54a2011-01-04 04:54:31 -03001070 value = 100 * internal * factor;
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001071 dib7000p_write_word(state, 8, (u16) ((value >> 16) & 0xffff));
1072 dib7000p_write_word(state, 9, (u16) (value & 0xffff));
Olivier Grenie713d54a2011-01-04 04:54:31 -03001073 value = 500 * internal * factor;
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001074 dib7000p_write_word(state, 10, (u16) ((value >> 16) & 0xffff));
1075 dib7000p_write_word(state, 11, (u16) (value & 0xffff));
Patrick Boettchera75763f2006-10-18 08:34:16 -03001076
1077 value = dib7000p_read_word(state, 0);
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001078 dib7000p_write_word(state, 0, (u16) ((1 << 9) | value));
Patrick Boettchera75763f2006-10-18 08:34:16 -03001079 dib7000p_read_word(state, 1284);
1080 dib7000p_write_word(state, 0, (u16) value);
1081
1082 return 0;
1083}
1084
1085static int dib7000p_autosearch_is_irq(struct dvb_frontend *demod)
1086{
1087 struct dib7000p_state *state = demod->demodulator_priv;
1088 u16 irq_pending = dib7000p_read_word(state, 1284);
1089
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001090 if (irq_pending & 0x1)
Patrick Boettchera75763f2006-10-18 08:34:16 -03001091 return 1;
1092
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001093 if (irq_pending & 0x2)
Patrick Boettchera75763f2006-10-18 08:34:16 -03001094 return 2;
1095
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001096 return 0;
Patrick Boettchera75763f2006-10-18 08:34:16 -03001097}
1098
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001099static void dib7000p_spur_protect(struct dib7000p_state *state, u32 rf_khz, u32 bw)
1100{
Olivier Grenie713d54a2011-01-04 04:54:31 -03001101 static s16 notch[] = { 16143, 14402, 12238, 9713, 6902, 3888, 759, -2392 };
1102 static u8 sine[] = { 0, 2, 3, 5, 6, 8, 9, 11, 13, 14, 16, 17, 19, 20, 22,
1103 24, 25, 27, 28, 30, 31, 33, 34, 36, 38, 39, 41, 42, 44, 45, 47, 48, 50, 51,
1104 53, 55, 56, 58, 59, 61, 62, 64, 65, 67, 68, 70, 71, 73, 74, 76, 77, 79, 80,
1105 82, 83, 85, 86, 88, 89, 91, 92, 94, 95, 97, 98, 99, 101, 102, 104, 105,
1106 107, 108, 109, 111, 112, 114, 115, 117, 118, 119, 121, 122, 123, 125, 126,
1107 128, 129, 130, 132, 133, 134, 136, 137, 138, 140, 141, 142, 144, 145, 146,
1108 147, 149, 150, 151, 152, 154, 155, 156, 157, 159, 160, 161, 162, 164, 165,
1109 166, 167, 168, 170, 171, 172, 173, 174, 175, 177, 178, 179, 180, 181, 182,
1110 183, 184, 185, 186, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198,
1111 199, 200, 201, 202, 203, 204, 205, 206, 207, 207, 208, 209, 210, 211, 212,
1112 213, 214, 215, 215, 216, 217, 218, 219, 220, 220, 221, 222, 223, 224, 224,
1113 225, 226, 227, 227, 228, 229, 229, 230, 231, 231, 232, 233, 233, 234, 235,
1114 235, 236, 237, 237, 238, 238, 239, 239, 240, 241, 241, 242, 242, 243, 243,
1115 244, 244, 245, 245, 245, 246, 246, 247, 247, 248, 248, 248, 249, 249, 249,
1116 250, 250, 250, 251, 251, 251, 252, 252, 252, 252, 253, 253, 253, 253, 254,
1117 254, 254, 254, 254, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
1118 255, 255, 255, 255, 255, 255
1119 };
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001120
1121 u32 xtal = state->cfg.bw->xtal_hz / 1000;
Julia Lawall75b697f2009-08-01 16:48:41 -03001122 int f_rel = DIV_ROUND_CLOSEST(rf_khz, xtal) * xtal - rf_khz;
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001123 int k;
Olivier Grenie713d54a2011-01-04 04:54:31 -03001124 int coef_re[8], coef_im[8];
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001125 int bw_khz = bw;
1126 u32 pha;
1127
Olivier Grenie713d54a2011-01-04 04:54:31 -03001128 dprintk("relative position of the Spur: %dk (RF: %dk, XTAL: %dk)", f_rel, rf_khz, xtal);
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001129
Olivier Grenie713d54a2011-01-04 04:54:31 -03001130 if (f_rel < -bw_khz / 2 || f_rel > bw_khz / 2)
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001131 return;
1132
1133 bw_khz /= 100;
1134
Olivier Grenie713d54a2011-01-04 04:54:31 -03001135 dib7000p_write_word(state, 142, 0x0610);
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001136
1137 for (k = 0; k < 8; k++) {
Olivier Grenie713d54a2011-01-04 04:54:31 -03001138 pha = ((f_rel * (k + 1) * 112 * 80 / bw_khz) / 1000) & 0x3ff;
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001139
Olivier Grenie713d54a2011-01-04 04:54:31 -03001140 if (pha == 0) {
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001141 coef_re[k] = 256;
1142 coef_im[k] = 0;
Olivier Grenie713d54a2011-01-04 04:54:31 -03001143 } else if (pha < 256) {
1144 coef_re[k] = sine[256 - (pha & 0xff)];
1145 coef_im[k] = sine[pha & 0xff];
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001146 } else if (pha == 256) {
1147 coef_re[k] = 0;
1148 coef_im[k] = 256;
1149 } else if (pha < 512) {
Olivier Grenie713d54a2011-01-04 04:54:31 -03001150 coef_re[k] = -sine[pha & 0xff];
1151 coef_im[k] = sine[256 - (pha & 0xff)];
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001152 } else if (pha == 512) {
1153 coef_re[k] = -256;
1154 coef_im[k] = 0;
1155 } else if (pha < 768) {
Olivier Grenie713d54a2011-01-04 04:54:31 -03001156 coef_re[k] = -sine[256 - (pha & 0xff)];
1157 coef_im[k] = -sine[pha & 0xff];
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001158 } else if (pha == 768) {
1159 coef_re[k] = 0;
1160 coef_im[k] = -256;
1161 } else {
Olivier Grenie713d54a2011-01-04 04:54:31 -03001162 coef_re[k] = sine[pha & 0xff];
1163 coef_im[k] = -sine[256 - (pha & 0xff)];
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001164 }
1165
1166 coef_re[k] *= notch[k];
Olivier Grenie713d54a2011-01-04 04:54:31 -03001167 coef_re[k] += (1 << 14);
1168 if (coef_re[k] >= (1 << 24))
1169 coef_re[k] = (1 << 24) - 1;
1170 coef_re[k] /= (1 << 15);
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001171
1172 coef_im[k] *= notch[k];
Olivier Grenie713d54a2011-01-04 04:54:31 -03001173 coef_im[k] += (1 << 14);
1174 if (coef_im[k] >= (1 << 24))
1175 coef_im[k] = (1 << 24) - 1;
1176 coef_im[k] /= (1 << 15);
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001177
Olivier Grenie713d54a2011-01-04 04:54:31 -03001178 dprintk("PALF COEF: %d re: %d im: %d", k, coef_re[k], coef_im[k]);
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001179
1180 dib7000p_write_word(state, 143, (0 << 14) | (k << 10) | (coef_re[k] & 0x3ff));
1181 dib7000p_write_word(state, 144, coef_im[k] & 0x3ff);
1182 dib7000p_write_word(state, 143, (1 << 14) | (k << 10) | (coef_re[k] & 0x3ff));
1183 }
Olivier Grenie713d54a2011-01-04 04:54:31 -03001184 dib7000p_write_word(state, 143, 0);
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001185}
1186
1187static int dib7000p_tune(struct dvb_frontend *demod, struct dvb_frontend_parameters *ch)
Patrick Boettchera75763f2006-10-18 08:34:16 -03001188{
1189 struct dib7000p_state *state = demod->demodulator_priv;
1190 u16 tmp = 0;
1191
1192 if (ch != NULL)
1193 dib7000p_set_channel(state, ch, 0);
1194 else
1195 return -EINVAL;
1196
1197 // restart demod
1198 dib7000p_write_word(state, 770, 0x4000);
1199 dib7000p_write_word(state, 770, 0x0000);
1200 msleep(45);
1201
1202 /* 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 -03001203 tmp = (0 << 14) | (4 << 10) | (0 << 9) | (3 << 5) | (1 << 4) | (0x3);
1204 if (state->sfn_workaround_active) {
Olivier Grenie713d54a2011-01-04 04:54:31 -03001205 dprintk("SFN workaround is active");
Matt Doran8f6956c2007-07-31 07:09:30 -03001206 tmp |= (1 << 9);
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001207 dib7000p_write_word(state, 166, 0x4000);
Matt Doran8f6956c2007-07-31 07:09:30 -03001208 } else {
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001209 dib7000p_write_word(state, 166, 0x0000);
Matt Doran8f6956c2007-07-31 07:09:30 -03001210 }
1211 dib7000p_write_word(state, 29, tmp);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001212
1213 // never achieved a lock with that bandwidth so far - wait for osc-freq to update
1214 if (state->timf == 0)
1215 msleep(200);
1216
1217 /* offset loop parameters */
1218
1219 /* P_timf_alpha, P_corm_alpha=6, P_corm_thres=0x80 */
1220 tmp = (6 << 8) | 0x80;
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001221 switch (ch->u.ofdm.transmission_mode) {
Olivier Grenie713d54a2011-01-04 04:54:31 -03001222 case TRANSMISSION_MODE_2K:
1223 tmp |= (2 << 12);
1224 break;
Mauro Carvalho Chehab46f72962011-01-16 13:01:20 -02001225 case TRANSMISSION_MODE_4K:
Olivier Grenie713d54a2011-01-04 04:54:31 -03001226 tmp |= (3 << 12);
1227 break;
1228 default:
1229 case TRANSMISSION_MODE_8K:
1230 tmp |= (4 << 12);
1231 break;
Patrick Boettchera75763f2006-10-18 08:34:16 -03001232 }
Olivier Grenie713d54a2011-01-04 04:54:31 -03001233 dib7000p_write_word(state, 26, tmp); /* timf_a(6xxx) */
Patrick Boettchera75763f2006-10-18 08:34:16 -03001234
1235 /* P_ctrl_freeze_pha_shift=0, P_ctrl_pha_off_max */
1236 tmp = (0 << 4);
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001237 switch (ch->u.ofdm.transmission_mode) {
Olivier Grenie713d54a2011-01-04 04:54:31 -03001238 case TRANSMISSION_MODE_2K:
1239 tmp |= 0x6;
1240 break;
Mauro Carvalho Chehab46f72962011-01-16 13:01:20 -02001241 case TRANSMISSION_MODE_4K:
Olivier Grenie713d54a2011-01-04 04:54:31 -03001242 tmp |= 0x7;
1243 break;
1244 default:
1245 case TRANSMISSION_MODE_8K:
1246 tmp |= 0x8;
1247 break;
Patrick Boettchera75763f2006-10-18 08:34:16 -03001248 }
Olivier Grenie713d54a2011-01-04 04:54:31 -03001249 dib7000p_write_word(state, 32, tmp);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001250
1251 /* P_ctrl_sfreq_inh=0, P_ctrl_sfreq_step */
1252 tmp = (0 << 4);
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001253 switch (ch->u.ofdm.transmission_mode) {
Olivier Grenie713d54a2011-01-04 04:54:31 -03001254 case TRANSMISSION_MODE_2K:
1255 tmp |= 0x6;
1256 break;
1257 case TRANSMISSION_MODE_4K:
1258 tmp |= 0x7;
1259 break;
1260 default:
1261 case TRANSMISSION_MODE_8K:
1262 tmp |= 0x8;
1263 break;
Patrick Boettchera75763f2006-10-18 08:34:16 -03001264 }
Olivier Grenie713d54a2011-01-04 04:54:31 -03001265 dib7000p_write_word(state, 33, tmp);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001266
Olivier Grenie713d54a2011-01-04 04:54:31 -03001267 tmp = dib7000p_read_word(state, 509);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001268 if (!((tmp >> 6) & 0x1)) {
1269 /* restart the fec */
Olivier Grenie713d54a2011-01-04 04:54:31 -03001270 tmp = dib7000p_read_word(state, 771);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001271 dib7000p_write_word(state, 771, tmp | (1 << 1));
1272 dib7000p_write_word(state, 771, tmp);
Olivier Grenie713d54a2011-01-04 04:54:31 -03001273 msleep(40);
1274 tmp = dib7000p_read_word(state, 509);
1275 }
1276 // we achieved a lock - it's time to update the osc freq
1277 if ((tmp >> 6) & 0x1) {
1278 dib7000p_update_timf(state);
1279 /* P_timf_alpha += 2 */
1280 tmp = dib7000p_read_word(state, 26);
1281 dib7000p_write_word(state, 26, (tmp & ~(0xf << 12)) | ((((tmp >> 12) & 0xf) + 5) << 12));
Patrick Boettchera75763f2006-10-18 08:34:16 -03001282 }
1283
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001284 if (state->cfg.spur_protect)
Olivier Grenie713d54a2011-01-04 04:54:31 -03001285 dib7000p_spur_protect(state, ch->frequency / 1000, BANDWIDTH_TO_KHZ(ch->u.ofdm.bandwidth));
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001286
Olivier Grenie713d54a2011-01-04 04:54:31 -03001287 dib7000p_set_bandwidth(state, BANDWIDTH_TO_KHZ(ch->u.ofdm.bandwidth));
Patrick Boettchera75763f2006-10-18 08:34:16 -03001288 return 0;
1289}
1290
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001291static int dib7000p_wakeup(struct dvb_frontend *demod)
Patrick Boettchera75763f2006-10-18 08:34:16 -03001292{
Patrick Boettchera75763f2006-10-18 08:34:16 -03001293 struct dib7000p_state *state = demod->demodulator_priv;
Patrick Boettchera75763f2006-10-18 08:34:16 -03001294 dib7000p_set_power_mode(state, DIB7000P_POWER_ALL);
1295 dib7000p_set_adc_state(state, DIBX000_SLOW_ADC_ON);
Olivier Grenie713d54a2011-01-04 04:54:31 -03001296 if (state->version == SOC7090)
1297 dib7000p_sad_calib(state);
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001298 return 0;
Patrick Boettchera75763f2006-10-18 08:34:16 -03001299}
1300
1301static int dib7000p_sleep(struct dvb_frontend *demod)
1302{
1303 struct dib7000p_state *state = demod->demodulator_priv;
Olivier Grenie713d54a2011-01-04 04:54:31 -03001304 if (state->version == SOC7090)
1305 return dib7090_set_output_mode(demod, OUTMODE_HIGH_Z) | dib7000p_set_power_mode(state, DIB7000P_POWER_INTERFACE_ONLY);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001306 return dib7000p_set_output_mode(state, OUTMODE_HIGH_Z) | dib7000p_set_power_mode(state, DIB7000P_POWER_INTERFACE_ONLY);
1307}
1308
1309static int dib7000p_identify(struct dib7000p_state *st)
1310{
1311 u16 value;
Olivier Grenie713d54a2011-01-04 04:54:31 -03001312 dprintk("checking demod on I2C address: %d (%x)", st->i2c_addr, st->i2c_addr);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001313
1314 if ((value = dib7000p_read_word(st, 768)) != 0x01b3) {
Olivier Grenie713d54a2011-01-04 04:54:31 -03001315 dprintk("wrong Vendor ID (read=0x%x)", value);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001316 return -EREMOTEIO;
1317 }
1318
1319 if ((value = dib7000p_read_word(st, 769)) != 0x4000) {
Olivier Grenie713d54a2011-01-04 04:54:31 -03001320 dprintk("wrong Device ID (%x)", value);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001321 return -EREMOTEIO;
1322 }
1323
1324 return 0;
1325}
1326
Olivier Grenie713d54a2011-01-04 04:54:31 -03001327static int dib7000p_get_frontend(struct dvb_frontend *fe, struct dvb_frontend_parameters *fep)
Patrick Boettchera75763f2006-10-18 08:34:16 -03001328{
1329 struct dib7000p_state *state = fe->demodulator_priv;
Olivier Grenie713d54a2011-01-04 04:54:31 -03001330 u16 tps = dib7000p_read_word(state, 463);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001331
1332 fep->inversion = INVERSION_AUTO;
1333
Patrick Boettcher904a82e2008-01-25 07:31:58 -03001334 fep->u.ofdm.bandwidth = BANDWIDTH_TO_INDEX(state->current_bandwidth);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001335
1336 switch ((tps >> 8) & 0x3) {
Olivier Grenie713d54a2011-01-04 04:54:31 -03001337 case 0:
1338 fep->u.ofdm.transmission_mode = TRANSMISSION_MODE_2K;
1339 break;
1340 case 1:
1341 fep->u.ofdm.transmission_mode = TRANSMISSION_MODE_8K;
1342 break;
Mauro Carvalho Chehab46f72962011-01-16 13:01:20 -02001343 /* case 2: fep->u.ofdm.transmission_mode = TRANSMISSION_MODE_4K; break; */
Patrick Boettchera75763f2006-10-18 08:34:16 -03001344 }
1345
1346 switch (tps & 0x3) {
Olivier Grenie713d54a2011-01-04 04:54:31 -03001347 case 0:
1348 fep->u.ofdm.guard_interval = GUARD_INTERVAL_1_32;
1349 break;
1350 case 1:
1351 fep->u.ofdm.guard_interval = GUARD_INTERVAL_1_16;
1352 break;
1353 case 2:
1354 fep->u.ofdm.guard_interval = GUARD_INTERVAL_1_8;
1355 break;
1356 case 3:
1357 fep->u.ofdm.guard_interval = GUARD_INTERVAL_1_4;
1358 break;
Patrick Boettchera75763f2006-10-18 08:34:16 -03001359 }
1360
1361 switch ((tps >> 14) & 0x3) {
Olivier Grenie713d54a2011-01-04 04:54:31 -03001362 case 0:
1363 fep->u.ofdm.constellation = QPSK;
1364 break;
1365 case 1:
1366 fep->u.ofdm.constellation = QAM_16;
1367 break;
1368 case 2:
1369 default:
1370 fep->u.ofdm.constellation = QAM_64;
1371 break;
Patrick Boettchera75763f2006-10-18 08:34:16 -03001372 }
1373
1374 /* as long as the frontend_param structure is fixed for hierarchical transmission I refuse to use it */
1375 /* (tps >> 13) & 0x1 == hrch is used, (tps >> 10) & 0x7 == alpha */
1376
1377 fep->u.ofdm.hierarchy_information = HIERARCHY_NONE;
1378 switch ((tps >> 5) & 0x7) {
Olivier Grenie713d54a2011-01-04 04:54:31 -03001379 case 1:
1380 fep->u.ofdm.code_rate_HP = FEC_1_2;
1381 break;
1382 case 2:
1383 fep->u.ofdm.code_rate_HP = FEC_2_3;
1384 break;
1385 case 3:
1386 fep->u.ofdm.code_rate_HP = FEC_3_4;
1387 break;
1388 case 5:
1389 fep->u.ofdm.code_rate_HP = FEC_5_6;
1390 break;
1391 case 7:
1392 default:
1393 fep->u.ofdm.code_rate_HP = FEC_7_8;
1394 break;
Patrick Boettchera75763f2006-10-18 08:34:16 -03001395
1396 }
1397
1398 switch ((tps >> 2) & 0x7) {
Olivier Grenie713d54a2011-01-04 04:54:31 -03001399 case 1:
1400 fep->u.ofdm.code_rate_LP = FEC_1_2;
1401 break;
1402 case 2:
1403 fep->u.ofdm.code_rate_LP = FEC_2_3;
1404 break;
1405 case 3:
1406 fep->u.ofdm.code_rate_LP = FEC_3_4;
1407 break;
1408 case 5:
1409 fep->u.ofdm.code_rate_LP = FEC_5_6;
1410 break;
1411 case 7:
1412 default:
1413 fep->u.ofdm.code_rate_LP = FEC_7_8;
1414 break;
Patrick Boettchera75763f2006-10-18 08:34:16 -03001415 }
1416
1417 /* native interleaver: (dib7000p_read_word(state, 464) >> 5) & 0x1 */
1418
1419 return 0;
1420}
1421
Olivier Grenie713d54a2011-01-04 04:54:31 -03001422static int dib7000p_set_frontend(struct dvb_frontend *fe, struct dvb_frontend_parameters *fep)
Patrick Boettchera75763f2006-10-18 08:34:16 -03001423{
1424 struct dib7000p_state *state = fe->demodulator_priv;
Soeren Moch853ea132008-01-25 06:27:06 -03001425 int time, ret;
Patrick Boettchera75763f2006-10-18 08:34:16 -03001426
Olivier Grenie713d54a2011-01-04 04:54:31 -03001427 if (state->version == SOC7090) {
1428 dib7090_set_diversity_in(fe, 0);
1429 dib7090_set_output_mode(fe, OUTMODE_HIGH_Z);
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001430 } else
Olivier Grenie713d54a2011-01-04 04:54:31 -03001431 dib7000p_set_output_mode(state, OUTMODE_HIGH_Z);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001432
Olivier Grenie713d54a2011-01-04 04:54:31 -03001433 /* maybe the parameter has been changed */
Matt Doran8f6956c2007-07-31 07:09:30 -03001434 state->sfn_workaround_active = buggy_sfn_workaround;
1435
Patrick Boettchera75763f2006-10-18 08:34:16 -03001436 if (fe->ops.tuner_ops.set_params)
1437 fe->ops.tuner_ops.set_params(fe, fep);
1438
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001439 /* start up the AGC */
1440 state->agc_state = 0;
1441 do {
1442 time = dib7000p_agc_startup(fe, fep);
1443 if (time != -1)
1444 msleep(time);
1445 } while (time != -1);
1446
Patrick Boettchera75763f2006-10-18 08:34:16 -03001447 if (fep->u.ofdm.transmission_mode == TRANSMISSION_MODE_AUTO ||
Olivier Grenie713d54a2011-01-04 04:54:31 -03001448 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 -03001449 int i = 800, found;
1450
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001451 dib7000p_autosearch_start(fe, fep);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001452 do {
1453 msleep(1);
1454 found = dib7000p_autosearch_is_irq(fe);
1455 } while (found == 0 && i--);
1456
Olivier Grenie713d54a2011-01-04 04:54:31 -03001457 dprintk("autosearch returns: %d", found);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001458 if (found == 0 || found == 1)
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001459 return 0;
Patrick Boettchera75763f2006-10-18 08:34:16 -03001460
1461 dib7000p_get_frontend(fe, fep);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001462 }
1463
Soeren Moch853ea132008-01-25 06:27:06 -03001464 ret = dib7000p_tune(fe, fep);
1465
Patrick Boettchera75763f2006-10-18 08:34:16 -03001466 /* make this a config parameter */
Olivier Grenie713d54a2011-01-04 04:54:31 -03001467 if (state->version == SOC7090)
1468 dib7090_set_output_mode(fe, state->cfg.output_mode);
1469 else
1470 dib7000p_set_output_mode(state, state->cfg.output_mode);
1471
1472 return ret;
Patrick Boettchera75763f2006-10-18 08:34:16 -03001473}
1474
Olivier Grenie713d54a2011-01-04 04:54:31 -03001475static int dib7000p_read_status(struct dvb_frontend *fe, fe_status_t * stat)
Patrick Boettchera75763f2006-10-18 08:34:16 -03001476{
1477 struct dib7000p_state *state = fe->demodulator_priv;
1478 u16 lock = dib7000p_read_word(state, 509);
1479
1480 *stat = 0;
1481
1482 if (lock & 0x8000)
1483 *stat |= FE_HAS_SIGNAL;
1484 if (lock & 0x3000)
1485 *stat |= FE_HAS_CARRIER;
1486 if (lock & 0x0100)
1487 *stat |= FE_HAS_VITERBI;
1488 if (lock & 0x0010)
1489 *stat |= FE_HAS_SYNC;
Olivier Grenie713d54a2011-01-04 04:54:31 -03001490 if ((lock & 0x0038) == 0x38)
Patrick Boettchera75763f2006-10-18 08:34:16 -03001491 *stat |= FE_HAS_LOCK;
1492
1493 return 0;
1494}
1495
Olivier Grenie713d54a2011-01-04 04:54:31 -03001496static int dib7000p_read_ber(struct dvb_frontend *fe, u32 * ber)
Patrick Boettchera75763f2006-10-18 08:34:16 -03001497{
1498 struct dib7000p_state *state = fe->demodulator_priv;
1499 *ber = (dib7000p_read_word(state, 500) << 16) | dib7000p_read_word(state, 501);
1500 return 0;
1501}
1502
Olivier Grenie713d54a2011-01-04 04:54:31 -03001503static int dib7000p_read_unc_blocks(struct dvb_frontend *fe, u32 * unc)
Patrick Boettchera75763f2006-10-18 08:34:16 -03001504{
1505 struct dib7000p_state *state = fe->demodulator_priv;
1506 *unc = dib7000p_read_word(state, 506);
1507 return 0;
1508}
1509
Olivier Grenie713d54a2011-01-04 04:54:31 -03001510static int dib7000p_read_signal_strength(struct dvb_frontend *fe, u16 * strength)
Patrick Boettchera75763f2006-10-18 08:34:16 -03001511{
1512 struct dib7000p_state *state = fe->demodulator_priv;
1513 u16 val = dib7000p_read_word(state, 394);
1514 *strength = 65535 - val;
1515 return 0;
1516}
1517
Olivier Grenie713d54a2011-01-04 04:54:31 -03001518static int dib7000p_read_snr(struct dvb_frontend *fe, u16 * snr)
Patrick Boettchera75763f2006-10-18 08:34:16 -03001519{
Olivier Grenieef801962009-09-15 06:46:52 -03001520 struct dib7000p_state *state = fe->demodulator_priv;
1521 u16 val;
1522 s32 signal_mant, signal_exp, noise_mant, noise_exp;
1523 u32 result = 0;
1524
1525 val = dib7000p_read_word(state, 479);
1526 noise_mant = (val >> 4) & 0xff;
1527 noise_exp = ((val & 0xf) << 2);
1528 val = dib7000p_read_word(state, 480);
1529 noise_exp += ((val >> 14) & 0x3);
1530 if ((noise_exp & 0x20) != 0)
1531 noise_exp -= 0x40;
1532
1533 signal_mant = (val >> 6) & 0xFF;
Olivier Grenie713d54a2011-01-04 04:54:31 -03001534 signal_exp = (val & 0x3F);
Olivier Grenieef801962009-09-15 06:46:52 -03001535 if ((signal_exp & 0x20) != 0)
1536 signal_exp -= 0x40;
1537
1538 if (signal_mant != 0)
Olivier Grenie713d54a2011-01-04 04:54:31 -03001539 result = intlog10(2) * 10 * signal_exp + 10 * intlog10(signal_mant);
Olivier Grenieef801962009-09-15 06:46:52 -03001540 else
1541 result = intlog10(2) * 10 * signal_exp - 100;
1542
1543 if (noise_mant != 0)
Olivier Grenie713d54a2011-01-04 04:54:31 -03001544 result -= intlog10(2) * 10 * noise_exp + 10 * intlog10(noise_mant);
Olivier Grenieef801962009-09-15 06:46:52 -03001545 else
1546 result -= intlog10(2) * 10 * noise_exp - 100;
1547
1548 *snr = result / ((1 << 24) / 10);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001549 return 0;
1550}
1551
Olivier Grenie713d54a2011-01-04 04:54:31 -03001552static int dib7000p_fe_get_tune_settings(struct dvb_frontend *fe, struct dvb_frontend_tune_settings *tune)
Patrick Boettchera75763f2006-10-18 08:34:16 -03001553{
1554 tune->min_delay_ms = 1000;
1555 return 0;
1556}
1557
1558static void dib7000p_release(struct dvb_frontend *demod)
1559{
1560 struct dib7000p_state *st = demod->demodulator_priv;
1561 dibx000_exit_i2c_master(&st->i2c_master);
Olivier Grenie713d54a2011-01-04 04:54:31 -03001562 i2c_del_adapter(&st->dib7090_tuner_adap);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001563 kfree(st);
1564}
1565
1566int dib7000pc_detection(struct i2c_adapter *i2c_adap)
1567{
Olivier Grenie5a0deee2011-05-03 12:27:33 -03001568 u8 *tx, *rx;
Patrick Boettchera75763f2006-10-18 08:34:16 -03001569 struct i2c_msg msg[2] = {
Olivier Grenie5a0deee2011-05-03 12:27:33 -03001570 {.addr = 18 >> 1, .flags = 0, .len = 2},
1571 {.addr = 18 >> 1, .flags = I2C_M_RD, .len = 2},
Patrick Boettchera75763f2006-10-18 08:34:16 -03001572 };
Olivier Grenie5a0deee2011-05-03 12:27:33 -03001573 int ret = 0;
1574
1575 tx = kzalloc(2*sizeof(u8), GFP_KERNEL);
1576 if (!tx)
1577 return -ENOMEM;
1578 rx = kzalloc(2*sizeof(u8), GFP_KERNEL);
1579 if (!rx) {
1580 goto rx_memory_error;
1581 ret = -ENOMEM;
1582 }
1583
1584 msg[0].buf = tx;
1585 msg[1].buf = rx;
Patrick Boettchera75763f2006-10-18 08:34:16 -03001586
1587 tx[0] = 0x03;
1588 tx[1] = 0x00;
1589
1590 if (i2c_transfer(i2c_adap, msg, 2) == 2)
1591 if (rx[0] == 0x01 && rx[1] == 0xb3) {
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001592 dprintk("-D- DiB7000PC detected");
Patrick Boettchera75763f2006-10-18 08:34:16 -03001593 return 1;
1594 }
1595
1596 msg[0].addr = msg[1].addr = 0x40;
1597
1598 if (i2c_transfer(i2c_adap, msg, 2) == 2)
1599 if (rx[0] == 0x01 && rx[1] == 0xb3) {
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001600 dprintk("-D- DiB7000PC detected");
Patrick Boettchera75763f2006-10-18 08:34:16 -03001601 return 1;
1602 }
1603
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001604 dprintk("-D- DiB7000PC not detected");
Olivier Grenie5a0deee2011-05-03 12:27:33 -03001605
1606 kfree(rx);
1607rx_memory_error:
1608 kfree(tx);
1609 return ret;
Patrick Boettchera75763f2006-10-18 08:34:16 -03001610}
1611EXPORT_SYMBOL(dib7000pc_detection);
1612
Olivier Grenie713d54a2011-01-04 04:54:31 -03001613struct i2c_adapter *dib7000p_get_i2c_master(struct dvb_frontend *demod, enum dibx000_i2c_interface intf, int gating)
Patrick Boettchera75763f2006-10-18 08:34:16 -03001614{
1615 struct dib7000p_state *st = demod->demodulator_priv;
1616 return dibx000_get_i2c_adapter(&st->i2c_master, intf, gating);
1617}
1618EXPORT_SYMBOL(dib7000p_get_i2c_master);
1619
Olivier Grenief8731f42009-09-18 04:08:43 -03001620int dib7000p_pid_filter_ctrl(struct dvb_frontend *fe, u8 onoff)
1621{
Olivier Grenie713d54a2011-01-04 04:54:31 -03001622 struct dib7000p_state *state = fe->demodulator_priv;
1623 u16 val = dib7000p_read_word(state, 235) & 0xffef;
1624 val |= (onoff & 0x1) << 4;
1625 dprintk("PID filter enabled %d", onoff);
1626 return dib7000p_write_word(state, 235, val);
Olivier Grenief8731f42009-09-18 04:08:43 -03001627}
1628EXPORT_SYMBOL(dib7000p_pid_filter_ctrl);
1629
1630int dib7000p_pid_filter(struct dvb_frontend *fe, u8 id, u16 pid, u8 onoff)
1631{
Olivier Grenie713d54a2011-01-04 04:54:31 -03001632 struct dib7000p_state *state = fe->demodulator_priv;
1633 dprintk("PID filter: index %x, PID %d, OnOff %d", id, pid, onoff);
1634 return dib7000p_write_word(state, 241 + id, onoff ? (1 << 13) | pid : 0);
Olivier Grenief8731f42009-09-18 04:08:43 -03001635}
1636EXPORT_SYMBOL(dib7000p_pid_filter);
1637
Patrick Boettchera75763f2006-10-18 08:34:16 -03001638int dib7000p_i2c_enumeration(struct i2c_adapter *i2c, int no_of_demods, u8 default_addr, struct dib7000p_config cfg[])
1639{
Randy Dunlap30d81bb2010-02-08 20:30:44 -03001640 struct dib7000p_state *dpst;
Patrick Boettchera75763f2006-10-18 08:34:16 -03001641 int k = 0;
1642 u8 new_addr = 0;
1643
Randy Dunlap30d81bb2010-02-08 20:30:44 -03001644 dpst = kzalloc(sizeof(struct dib7000p_state), GFP_KERNEL);
1645 if (!dpst)
Andrew Morton0b427602010-04-27 19:09:45 -03001646 return -ENOMEM;
Randy Dunlap30d81bb2010-02-08 20:30:44 -03001647
1648 dpst->i2c_adap = i2c;
1649
Olivier Grenie713d54a2011-01-04 04:54:31 -03001650 for (k = no_of_demods - 1; k >= 0; k--) {
Randy Dunlap30d81bb2010-02-08 20:30:44 -03001651 dpst->cfg = cfg[k];
Patrick Boettchera75763f2006-10-18 08:34:16 -03001652
1653 /* designated i2c address */
Olivier Grenie713d54a2011-01-04 04:54:31 -03001654 if (cfg[k].default_i2c_addr != 0)
1655 new_addr = cfg[k].default_i2c_addr + (k << 1);
1656 else
1657 new_addr = (0x40 + k) << 1;
Randy Dunlap30d81bb2010-02-08 20:30:44 -03001658 dpst->i2c_addr = new_addr;
Olivier Grenie713d54a2011-01-04 04:54:31 -03001659 dib7000p_write_word(dpst, 1287, 0x0003); /* sram lead in, rdy */
Randy Dunlap30d81bb2010-02-08 20:30:44 -03001660 if (dib7000p_identify(dpst) != 0) {
1661 dpst->i2c_addr = default_addr;
Olivier Grenie713d54a2011-01-04 04:54:31 -03001662 dib7000p_write_word(dpst, 1287, 0x0003); /* sram lead in, rdy */
Randy Dunlap30d81bb2010-02-08 20:30:44 -03001663 if (dib7000p_identify(dpst) != 0) {
Patrick Boettchera75763f2006-10-18 08:34:16 -03001664 dprintk("DiB7000P #%d: not identified\n", k);
Randy Dunlap30d81bb2010-02-08 20:30:44 -03001665 kfree(dpst);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001666 return -EIO;
1667 }
1668 }
1669
1670 /* start diversity to pull_down div_str - just for i2c-enumeration */
Randy Dunlap30d81bb2010-02-08 20:30:44 -03001671 dib7000p_set_output_mode(dpst, OUTMODE_DIVERSITY);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001672
1673 /* set new i2c address and force divstart */
Randy Dunlap30d81bb2010-02-08 20:30:44 -03001674 dib7000p_write_word(dpst, 1285, (new_addr << 2) | 0x2);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001675
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001676 dprintk("IC %d initialized (to i2c_address 0x%x)", k, new_addr);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001677 }
1678
1679 for (k = 0; k < no_of_demods; k++) {
Randy Dunlap30d81bb2010-02-08 20:30:44 -03001680 dpst->cfg = cfg[k];
Olivier Grenie713d54a2011-01-04 04:54:31 -03001681 if (cfg[k].default_i2c_addr != 0)
1682 dpst->i2c_addr = (cfg[k].default_i2c_addr + k) << 1;
1683 else
1684 dpst->i2c_addr = (0x40 + k) << 1;
Patrick Boettchera75763f2006-10-18 08:34:16 -03001685
1686 // unforce divstr
Randy Dunlap30d81bb2010-02-08 20:30:44 -03001687 dib7000p_write_word(dpst, 1285, dpst->i2c_addr << 2);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001688
1689 /* deactivate div - it was just for i2c-enumeration */
Randy Dunlap30d81bb2010-02-08 20:30:44 -03001690 dib7000p_set_output_mode(dpst, OUTMODE_HIGH_Z);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001691 }
1692
Randy Dunlap30d81bb2010-02-08 20:30:44 -03001693 kfree(dpst);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001694 return 0;
1695}
1696EXPORT_SYMBOL(dib7000p_i2c_enumeration);
1697
Olivier Grenie713d54a2011-01-04 04:54:31 -03001698static const s32 lut_1000ln_mant[] = {
1699 6908, 6956, 7003, 7047, 7090, 7131, 7170, 7208, 7244, 7279, 7313, 7346, 7377, 7408, 7438, 7467, 7495, 7523, 7549, 7575, 7600
1700};
1701
1702static s32 dib7000p_get_adc_power(struct dvb_frontend *fe)
1703{
1704 struct dib7000p_state *state = fe->demodulator_priv;
1705 u32 tmp_val = 0, exp = 0, mant = 0;
1706 s32 pow_i;
1707 u16 buf[2];
1708 u8 ix = 0;
1709
1710 buf[0] = dib7000p_read_word(state, 0x184);
1711 buf[1] = dib7000p_read_word(state, 0x185);
1712 pow_i = (buf[0] << 16) | buf[1];
1713 dprintk("raw pow_i = %d", pow_i);
1714
1715 tmp_val = pow_i;
1716 while (tmp_val >>= 1)
1717 exp++;
1718
1719 mant = (pow_i * 1000 / (1 << exp));
1720 dprintk(" mant = %d exp = %d", mant / 1000, exp);
1721
1722 ix = (u8) ((mant - 1000) / 100); /* index of the LUT */
1723 dprintk(" ix = %d", ix);
1724
1725 pow_i = (lut_1000ln_mant[ix] + 693 * (exp - 20) - 6908);
1726 pow_i = (pow_i << 8) / 1000;
1727 dprintk(" pow_i = %d", pow_i);
1728
1729 return pow_i;
1730}
1731
1732static int map_addr_to_serpar_number(struct i2c_msg *msg)
1733{
1734 if ((msg->buf[0] <= 15))
1735 msg->buf[0] -= 1;
1736 else if (msg->buf[0] == 17)
1737 msg->buf[0] = 15;
1738 else if (msg->buf[0] == 16)
1739 msg->buf[0] = 17;
1740 else if (msg->buf[0] == 19)
1741 msg->buf[0] = 16;
1742 else if (msg->buf[0] >= 21 && msg->buf[0] <= 25)
1743 msg->buf[0] -= 3;
1744 else if (msg->buf[0] == 28)
1745 msg->buf[0] = 23;
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001746 else
Olivier Grenie713d54a2011-01-04 04:54:31 -03001747 return -EINVAL;
Olivier Grenie713d54a2011-01-04 04:54:31 -03001748 return 0;
1749}
1750
1751static int w7090p_tuner_write_serpar(struct i2c_adapter *i2c_adap, struct i2c_msg msg[], int num)
1752{
1753 struct dib7000p_state *state = i2c_get_adapdata(i2c_adap);
1754 u8 n_overflow = 1;
1755 u16 i = 1000;
1756 u16 serpar_num = msg[0].buf[0];
1757
1758 while (n_overflow == 1 && i) {
1759 n_overflow = (dib7000p_read_word(state, 1984) >> 1) & 0x1;
1760 i--;
1761 if (i == 0)
1762 dprintk("Tuner ITF: write busy (overflow)");
1763 }
1764 dib7000p_write_word(state, 1985, (1 << 6) | (serpar_num & 0x3f));
1765 dib7000p_write_word(state, 1986, (msg[0].buf[1] << 8) | msg[0].buf[2]);
1766
1767 return num;
1768}
1769
1770static int w7090p_tuner_read_serpar(struct i2c_adapter *i2c_adap, struct i2c_msg msg[], int num)
1771{
1772 struct dib7000p_state *state = i2c_get_adapdata(i2c_adap);
1773 u8 n_overflow = 1, n_empty = 1;
1774 u16 i = 1000;
1775 u16 serpar_num = msg[0].buf[0];
1776 u16 read_word;
1777
1778 while (n_overflow == 1 && i) {
1779 n_overflow = (dib7000p_read_word(state, 1984) >> 1) & 0x1;
1780 i--;
1781 if (i == 0)
1782 dprintk("TunerITF: read busy (overflow)");
1783 }
1784 dib7000p_write_word(state, 1985, (0 << 6) | (serpar_num & 0x3f));
1785
1786 i = 1000;
1787 while (n_empty == 1 && i) {
1788 n_empty = dib7000p_read_word(state, 1984) & 0x1;
1789 i--;
1790 if (i == 0)
1791 dprintk("TunerITF: read busy (empty)");
1792 }
1793 read_word = dib7000p_read_word(state, 1987);
1794 msg[1].buf[0] = (read_word >> 8) & 0xff;
1795 msg[1].buf[1] = (read_word) & 0xff;
1796
1797 return num;
1798}
1799
1800static int w7090p_tuner_rw_serpar(struct i2c_adapter *i2c_adap, struct i2c_msg msg[], int num)
1801{
1802 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... */
1803 if (num == 1) { /* write */
1804 return w7090p_tuner_write_serpar(i2c_adap, msg, 1);
1805 } else { /* read */
1806 return w7090p_tuner_read_serpar(i2c_adap, msg, 2);
1807 }
1808 }
1809 return num;
1810}
1811
1812int dib7090p_rw_on_apb(struct i2c_adapter *i2c_adap, struct i2c_msg msg[], int num, u16 apb_address)
1813{
1814 struct dib7000p_state *state = i2c_get_adapdata(i2c_adap);
1815 u16 word;
1816
1817 if (num == 1) { /* write */
1818 dib7000p_write_word(state, apb_address, ((msg[0].buf[1] << 8) | (msg[0].buf[2])));
1819 } else {
1820 word = dib7000p_read_word(state, apb_address);
1821 msg[1].buf[0] = (word >> 8) & 0xff;
1822 msg[1].buf[1] = (word) & 0xff;
1823 }
1824
1825 return num;
1826}
1827
1828static int dib7090_tuner_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg msg[], int num)
1829{
1830 struct dib7000p_state *state = i2c_get_adapdata(i2c_adap);
1831
1832 u16 apb_address = 0, word;
1833 int i = 0;
1834 switch (msg[0].buf[0]) {
1835 case 0x12:
1836 apb_address = 1920;
1837 break;
1838 case 0x14:
1839 apb_address = 1921;
1840 break;
1841 case 0x24:
1842 apb_address = 1922;
1843 break;
1844 case 0x1a:
1845 apb_address = 1923;
1846 break;
1847 case 0x22:
1848 apb_address = 1924;
1849 break;
1850 case 0x33:
1851 apb_address = 1926;
1852 break;
1853 case 0x34:
1854 apb_address = 1927;
1855 break;
1856 case 0x35:
1857 apb_address = 1928;
1858 break;
1859 case 0x36:
1860 apb_address = 1929;
1861 break;
1862 case 0x37:
1863 apb_address = 1930;
1864 break;
1865 case 0x38:
1866 apb_address = 1931;
1867 break;
1868 case 0x39:
1869 apb_address = 1932;
1870 break;
1871 case 0x2a:
1872 apb_address = 1935;
1873 break;
1874 case 0x2b:
1875 apb_address = 1936;
1876 break;
1877 case 0x2c:
1878 apb_address = 1937;
1879 break;
1880 case 0x2d:
1881 apb_address = 1938;
1882 break;
1883 case 0x2e:
1884 apb_address = 1939;
1885 break;
1886 case 0x2f:
1887 apb_address = 1940;
1888 break;
1889 case 0x30:
1890 apb_address = 1941;
1891 break;
1892 case 0x31:
1893 apb_address = 1942;
1894 break;
1895 case 0x32:
1896 apb_address = 1943;
1897 break;
1898 case 0x3e:
1899 apb_address = 1944;
1900 break;
1901 case 0x3f:
1902 apb_address = 1945;
1903 break;
1904 case 0x40:
1905 apb_address = 1948;
1906 break;
1907 case 0x25:
1908 apb_address = 914;
1909 break;
1910 case 0x26:
1911 apb_address = 915;
1912 break;
1913 case 0x27:
1914 apb_address = 916;
1915 break;
1916 case 0x28:
1917 apb_address = 917;
1918 break;
1919 case 0x1d:
1920 i = ((dib7000p_read_word(state, 72) >> 12) & 0x3);
1921 word = dib7000p_read_word(state, 384 + i);
1922 msg[1].buf[0] = (word >> 8) & 0xff;
1923 msg[1].buf[1] = (word) & 0xff;
1924 return num;
1925 case 0x1f:
1926 if (num == 1) { /* write */
1927 word = (u16) ((msg[0].buf[1] << 8) | msg[0].buf[2]);
1928 word &= 0x3;
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001929 word = (dib7000p_read_word(state, 72) & ~(3 << 12)) | (word << 12);
Olivier Grenie713d54a2011-01-04 04:54:31 -03001930 dib7000p_write_word(state, 72, word); /* Set the proper input */
1931 return num;
1932 }
1933 }
1934
1935 if (apb_address != 0) /* R/W acces via APB */
1936 return dib7090p_rw_on_apb(i2c_adap, msg, num, apb_address);
1937 else /* R/W access via SERPAR */
1938 return w7090p_tuner_rw_serpar(i2c_adap, msg, num);
1939
1940 return 0;
1941}
1942
1943static u32 dib7000p_i2c_func(struct i2c_adapter *adapter)
1944{
1945 return I2C_FUNC_I2C;
1946}
1947
1948static struct i2c_algorithm dib7090_tuner_xfer_algo = {
1949 .master_xfer = dib7090_tuner_xfer,
1950 .functionality = dib7000p_i2c_func,
1951};
1952
1953struct i2c_adapter *dib7090_get_i2c_tuner(struct dvb_frontend *fe)
1954{
1955 struct dib7000p_state *st = fe->demodulator_priv;
1956 return &st->dib7090_tuner_adap;
1957}
1958EXPORT_SYMBOL(dib7090_get_i2c_tuner);
1959
1960static int dib7090_host_bus_drive(struct dib7000p_state *state, u8 drive)
1961{
1962 u16 reg;
1963
1964 /* drive host bus 2, 3, 4 */
1965 reg = dib7000p_read_word(state, 1798) & ~((0x7) | (0x7 << 6) | (0x7 << 12));
1966 reg |= (drive << 12) | (drive << 6) | drive;
1967 dib7000p_write_word(state, 1798, reg);
1968
1969 /* drive host bus 5,6 */
1970 reg = dib7000p_read_word(state, 1799) & ~((0x7 << 2) | (0x7 << 8));
1971 reg |= (drive << 8) | (drive << 2);
1972 dib7000p_write_word(state, 1799, reg);
1973
1974 /* drive host bus 7, 8, 9 */
1975 reg = dib7000p_read_word(state, 1800) & ~((0x7) | (0x7 << 6) | (0x7 << 12));
1976 reg |= (drive << 12) | (drive << 6) | drive;
1977 dib7000p_write_word(state, 1800, reg);
1978
1979 /* drive host bus 10, 11 */
1980 reg = dib7000p_read_word(state, 1801) & ~((0x7 << 2) | (0x7 << 8));
1981 reg |= (drive << 8) | (drive << 2);
1982 dib7000p_write_word(state, 1801, reg);
1983
1984 /* drive host bus 12, 13, 14 */
1985 reg = dib7000p_read_word(state, 1802) & ~((0x7) | (0x7 << 6) | (0x7 << 12));
1986 reg |= (drive << 12) | (drive << 6) | drive;
1987 dib7000p_write_word(state, 1802, reg);
1988
1989 return 0;
1990}
1991
1992static u32 dib7090_calcSyncFreq(u32 P_Kin, u32 P_Kout, u32 insertExtSynchro, u32 syncSize)
1993{
1994 u32 quantif = 3;
1995 u32 nom = (insertExtSynchro * P_Kin + syncSize);
1996 u32 denom = P_Kout;
1997 u32 syncFreq = ((nom << quantif) / denom);
1998
1999 if ((syncFreq & ((1 << quantif) - 1)) != 0)
2000 syncFreq = (syncFreq >> quantif) + 1;
2001 else
2002 syncFreq = (syncFreq >> quantif);
2003
2004 if (syncFreq != 0)
2005 syncFreq = syncFreq - 1;
2006
2007 return syncFreq;
2008}
2009
2010static int dib7090_cfg_DibTx(struct dib7000p_state *state, u32 P_Kin, u32 P_Kout, u32 insertExtSynchro, u32 synchroMode, u32 syncWord, u32 syncSize)
2011{
2012 u8 index_buf;
2013 u16 rx_copy_buf[22];
2014
2015 dprintk("Configure DibStream Tx");
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002016 for (index_buf = 0; index_buf < 22; index_buf++)
Olivier Grenie713d54a2011-01-04 04:54:31 -03002017 rx_copy_buf[index_buf] = dib7000p_read_word(state, 1536+index_buf);
2018
2019 dib7000p_write_word(state, 1615, 1);
2020 dib7000p_write_word(state, 1603, P_Kin);
2021 dib7000p_write_word(state, 1605, P_Kout);
2022 dib7000p_write_word(state, 1606, insertExtSynchro);
2023 dib7000p_write_word(state, 1608, synchroMode);
2024 dib7000p_write_word(state, 1609, (syncWord >> 16) & 0xffff);
2025 dib7000p_write_word(state, 1610, syncWord & 0xffff);
2026 dib7000p_write_word(state, 1612, syncSize);
2027 dib7000p_write_word(state, 1615, 0);
2028
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002029 for (index_buf = 0; index_buf < 22; index_buf++)
Olivier Grenie713d54a2011-01-04 04:54:31 -03002030 dib7000p_write_word(state, 1536+index_buf, rx_copy_buf[index_buf]);
2031
2032 return 0;
2033}
2034
2035static int dib7090_cfg_DibRx(struct dib7000p_state *state, u32 P_Kin, u32 P_Kout, u32 synchroMode, u32 insertExtSynchro, u32 syncWord, u32 syncSize,
2036 u32 dataOutRate)
2037{
2038 u32 syncFreq;
2039
2040 dprintk("Configure DibStream Rx");
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002041 if ((P_Kin != 0) && (P_Kout != 0)) {
Olivier Grenie713d54a2011-01-04 04:54:31 -03002042 syncFreq = dib7090_calcSyncFreq(P_Kin, P_Kout, insertExtSynchro, syncSize);
2043 dib7000p_write_word(state, 1542, syncFreq);
2044 }
2045 dib7000p_write_word(state, 1554, 1);
2046 dib7000p_write_word(state, 1536, P_Kin);
2047 dib7000p_write_word(state, 1537, P_Kout);
2048 dib7000p_write_word(state, 1539, synchroMode);
2049 dib7000p_write_word(state, 1540, (syncWord >> 16) & 0xffff);
2050 dib7000p_write_word(state, 1541, syncWord & 0xffff);
2051 dib7000p_write_word(state, 1543, syncSize);
2052 dib7000p_write_word(state, 1544, dataOutRate);
2053 dib7000p_write_word(state, 1554, 0);
2054
2055 return 0;
2056}
2057
2058static int dib7090_enDivOnHostBus(struct dib7000p_state *state)
2059{
2060 u16 reg;
2061
2062 dprintk("Enable Diversity on host bus");
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002063 reg = (1 << 8) | (1 << 5);
Olivier Grenie713d54a2011-01-04 04:54:31 -03002064 dib7000p_write_word(state, 1288, reg);
2065
2066 return dib7090_cfg_DibTx(state, 5, 5, 0, 0, 0, 0);
2067}
2068
2069static int dib7090_enAdcOnHostBus(struct dib7000p_state *state)
2070{
2071 u16 reg;
2072
2073 dprintk("Enable ADC on host bus");
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002074 reg = (1 << 7) | (1 << 5);
Olivier Grenie713d54a2011-01-04 04:54:31 -03002075 dib7000p_write_word(state, 1288, reg);
2076
2077 return dib7090_cfg_DibTx(state, 20, 5, 10, 0, 0, 0);
2078}
2079
2080static int dib7090_enMpegOnHostBus(struct dib7000p_state *state)
2081{
2082 u16 reg;
2083
2084 dprintk("Enable Mpeg on host bus");
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002085 reg = (1 << 9) | (1 << 5);
Olivier Grenie713d54a2011-01-04 04:54:31 -03002086 dib7000p_write_word(state, 1288, reg);
2087
2088 return dib7090_cfg_DibTx(state, 8, 5, 0, 0, 0, 0);
2089}
2090
2091static int dib7090_enMpegInput(struct dib7000p_state *state)
2092{
2093 dprintk("Enable Mpeg input");
2094 return dib7090_cfg_DibRx(state, 8, 5, 0, 0, 0, 8, 0); /*outputRate = 8 */
2095}
2096
2097static int dib7090_enMpegMux(struct dib7000p_state *state, u16 pulseWidth, u16 enSerialMode, u16 enSerialClkDiv2)
2098{
2099 u16 reg = (1 << 7) | ((pulseWidth & 0x1f) << 2) | ((enSerialMode & 0x1) << 1) | (enSerialClkDiv2 & 0x1);
2100
2101 dprintk("Enable Mpeg mux");
2102 dib7000p_write_word(state, 1287, reg);
2103
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002104 reg &= ~(1 << 7);
Olivier Grenie713d54a2011-01-04 04:54:31 -03002105 dib7000p_write_word(state, 1287, reg);
2106
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002107 reg = (1 << 4);
Olivier Grenie713d54a2011-01-04 04:54:31 -03002108 dib7000p_write_word(state, 1288, reg);
2109
2110 return 0;
2111}
2112
2113static int dib7090_disableMpegMux(struct dib7000p_state *state)
2114{
2115 u16 reg;
2116
2117 dprintk("Disable Mpeg mux");
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002118 dib7000p_write_word(state, 1288, 0);
Olivier Grenie713d54a2011-01-04 04:54:31 -03002119
2120 reg = dib7000p_read_word(state, 1287);
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002121 reg &= ~(1 << 7);
Olivier Grenie713d54a2011-01-04 04:54:31 -03002122 dib7000p_write_word(state, 1287, reg);
2123
2124 return 0;
2125}
2126
2127static int dib7090_set_input_mode(struct dvb_frontend *fe, int mode)
2128{
2129 struct dib7000p_state *state = fe->demodulator_priv;
2130
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002131 switch (mode) {
2132 case INPUT_MODE_DIVERSITY:
Olivier Grenie713d54a2011-01-04 04:54:31 -03002133 dprintk("Enable diversity INPUT");
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002134 dib7090_cfg_DibRx(state, 5, 5, 0, 0, 0, 0, 0);
Olivier Grenie713d54a2011-01-04 04:54:31 -03002135 break;
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002136 case INPUT_MODE_MPEG:
Olivier Grenie713d54a2011-01-04 04:54:31 -03002137 dprintk("Enable Mpeg INPUT");
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002138 dib7090_cfg_DibRx(state, 8, 5, 0, 0, 0, 8, 0); /*outputRate = 8 */
Olivier Grenie713d54a2011-01-04 04:54:31 -03002139 break;
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002140 case INPUT_MODE_OFF:
2141 default:
Olivier Grenie713d54a2011-01-04 04:54:31 -03002142 dprintk("Disable INPUT");
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002143 dib7090_cfg_DibRx(state, 0, 0, 0, 0, 0, 0, 0);
Olivier Grenie713d54a2011-01-04 04:54:31 -03002144 break;
2145 }
2146 return 0;
2147}
2148
2149static int dib7090_set_diversity_in(struct dvb_frontend *fe, int onoff)
2150{
2151 switch (onoff) {
2152 case 0: /* only use the internal way - not the diversity input */
2153 dib7090_set_input_mode(fe, INPUT_MODE_MPEG);
2154 break;
2155 case 1: /* both ways */
2156 case 2: /* only the diversity input */
2157 dib7090_set_input_mode(fe, INPUT_MODE_DIVERSITY);
2158 break;
2159 }
2160
2161 return 0;
2162}
2163
2164static int dib7090_set_output_mode(struct dvb_frontend *fe, int mode)
2165{
2166 struct dib7000p_state *state = fe->demodulator_priv;
2167
2168 u16 outreg, smo_mode, fifo_threshold;
2169 u8 prefer_mpeg_mux_use = 1;
2170 int ret = 0;
2171
2172 dib7090_host_bus_drive(state, 1);
2173
2174 fifo_threshold = 1792;
2175 smo_mode = (dib7000p_read_word(state, 235) & 0x0050) | (1 << 1);
2176 outreg = dib7000p_read_word(state, 1286) & ~((1 << 10) | (0x7 << 6) | (1 << 1));
2177
2178 switch (mode) {
2179 case OUTMODE_HIGH_Z:
2180 outreg = 0;
2181 break;
2182
2183 case OUTMODE_MPEG2_SERIAL:
2184 if (prefer_mpeg_mux_use) {
2185 dprintk("Sip 7090P setting output mode TS_SERIAL using Mpeg Mux");
2186 dib7090_enMpegOnHostBus(state);
2187 dib7090_enMpegInput(state);
2188 if (state->cfg.enMpegOutput == 1)
2189 dib7090_enMpegMux(state, 3, 1, 1);
2190
2191 } else { /* Use Smooth block */
2192 dprintk("Sip 7090P setting output mode TS_SERIAL using Smooth bloc");
2193 dib7090_disableMpegMux(state);
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002194 dib7000p_write_word(state, 1288, (1 << 6));
Olivier Grenie713d54a2011-01-04 04:54:31 -03002195 outreg |= (2 << 6) | (0 << 1);
2196 }
2197 break;
2198
2199 case OUTMODE_MPEG2_PAR_GATED_CLK:
2200 if (prefer_mpeg_mux_use) {
2201 dprintk("Sip 7090P setting output mode TS_PARALLEL_GATED using Mpeg Mux");
2202 dib7090_enMpegOnHostBus(state);
2203 dib7090_enMpegInput(state);
2204 if (state->cfg.enMpegOutput == 1)
2205 dib7090_enMpegMux(state, 2, 0, 0);
2206 } else { /* Use Smooth block */
2207 dprintk("Sip 7090P setting output mode TS_PARALLEL_GATED using Smooth block");
2208 dib7090_disableMpegMux(state);
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002209 dib7000p_write_word(state, 1288, (1 << 6));
Olivier Grenie713d54a2011-01-04 04:54:31 -03002210 outreg |= (0 << 6);
2211 }
2212 break;
2213
2214 case OUTMODE_MPEG2_PAR_CONT_CLK: /* Using Smooth block only */
2215 dprintk("Sip 7090P setting output mode TS_PARALLEL_CONT using Smooth block");
2216 dib7090_disableMpegMux(state);
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002217 dib7000p_write_word(state, 1288, (1 << 6));
Olivier Grenie713d54a2011-01-04 04:54:31 -03002218 outreg |= (1 << 6);
2219 break;
2220
2221 case OUTMODE_MPEG2_FIFO: /* Using Smooth block because not supported by new Mpeg Mux bloc */
2222 dprintk("Sip 7090P setting output mode TS_FIFO using Smooth block");
2223 dib7090_disableMpegMux(state);
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002224 dib7000p_write_word(state, 1288, (1 << 6));
Olivier Grenie713d54a2011-01-04 04:54:31 -03002225 outreg |= (5 << 6);
2226 smo_mode |= (3 << 1);
2227 fifo_threshold = 512;
2228 break;
2229
2230 case OUTMODE_DIVERSITY:
2231 dprintk("Sip 7090P setting output mode MODE_DIVERSITY");
2232 dib7090_disableMpegMux(state);
2233 dib7090_enDivOnHostBus(state);
2234 break;
2235
2236 case OUTMODE_ANALOG_ADC:
2237 dprintk("Sip 7090P setting output mode MODE_ANALOG_ADC");
2238 dib7090_enAdcOnHostBus(state);
2239 break;
2240 }
2241
2242 if (state->cfg.output_mpeg2_in_188_bytes)
2243 smo_mode |= (1 << 5);
2244
2245 ret |= dib7000p_write_word(state, 235, smo_mode);
2246 ret |= dib7000p_write_word(state, 236, fifo_threshold); /* synchronous fread */
2247 ret |= dib7000p_write_word(state, 1286, outreg | (1 << 10)); /* allways set Dout active = 1 !!! */
2248
2249 return ret;
2250}
2251
2252int dib7090_tuner_sleep(struct dvb_frontend *fe, int onoff)
2253{
2254 struct dib7000p_state *state = fe->demodulator_priv;
2255 u16 en_cur_state;
2256
2257 dprintk("sleep dib7090: %d", onoff);
2258
2259 en_cur_state = dib7000p_read_word(state, 1922);
2260
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002261 if (en_cur_state > 0xff)
Olivier Grenie713d54a2011-01-04 04:54:31 -03002262 state->tuner_enable = en_cur_state;
Olivier Grenie713d54a2011-01-04 04:54:31 -03002263
2264 if (onoff)
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002265 en_cur_state &= 0x00ff;
Olivier Grenie713d54a2011-01-04 04:54:31 -03002266 else {
2267 if (state->tuner_enable != 0)
2268 en_cur_state = state->tuner_enable;
2269 }
2270
2271 dib7000p_write_word(state, 1922, en_cur_state);
2272
2273 return 0;
2274}
2275EXPORT_SYMBOL(dib7090_tuner_sleep);
2276
2277int dib7090_agc_restart(struct dvb_frontend *fe, u8 restart)
2278{
2279 dprintk("AGC restart callback: %d", restart);
2280 return 0;
2281}
2282EXPORT_SYMBOL(dib7090_agc_restart);
2283
2284int dib7090_get_adc_power(struct dvb_frontend *fe)
2285{
2286 return dib7000p_get_adc_power(fe);
2287}
2288EXPORT_SYMBOL(dib7090_get_adc_power);
2289
2290int dib7090_slave_reset(struct dvb_frontend *fe)
2291{
2292 struct dib7000p_state *state = fe->demodulator_priv;
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002293 u16 reg;
Olivier Grenie713d54a2011-01-04 04:54:31 -03002294
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002295 reg = dib7000p_read_word(state, 1794);
2296 dib7000p_write_word(state, 1794, reg | (4 << 12));
Olivier Grenie713d54a2011-01-04 04:54:31 -03002297
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002298 dib7000p_write_word(state, 1032, 0xffff);
2299 return 0;
Olivier Grenie713d54a2011-01-04 04:54:31 -03002300}
2301EXPORT_SYMBOL(dib7090_slave_reset);
2302
Patrick Boettchera75763f2006-10-18 08:34:16 -03002303static struct dvb_frontend_ops dib7000p_ops;
Olivier Grenie713d54a2011-01-04 04:54:31 -03002304struct dvb_frontend *dib7000p_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr, struct dib7000p_config *cfg)
Patrick Boettchera75763f2006-10-18 08:34:16 -03002305{
2306 struct dvb_frontend *demod;
2307 struct dib7000p_state *st;
2308 st = kzalloc(sizeof(struct dib7000p_state), GFP_KERNEL);
2309 if (st == NULL)
2310 return NULL;
2311
2312 memcpy(&st->cfg, cfg, sizeof(struct dib7000p_config));
2313 st->i2c_adap = i2c_adap;
2314 st->i2c_addr = i2c_addr;
2315 st->gpio_val = cfg->gpio_val;
2316 st->gpio_dir = cfg->gpio_dir;
2317
Steven Totha38d6e32008-04-22 15:37:01 -03002318 /* Ensure the output mode remains at the previous default if it's
2319 * not specifically set by the caller.
2320 */
Olivier Grenie713d54a2011-01-04 04:54:31 -03002321 if ((st->cfg.output_mode != OUTMODE_MPEG2_SERIAL) && (st->cfg.output_mode != OUTMODE_MPEG2_PAR_GATED_CLK))
Steven Totha38d6e32008-04-22 15:37:01 -03002322 st->cfg.output_mode = OUTMODE_MPEG2_FIFO;
2323
Olivier Grenie713d54a2011-01-04 04:54:31 -03002324 demod = &st->demod;
Patrick Boettchera75763f2006-10-18 08:34:16 -03002325 demod->demodulator_priv = st;
2326 memcpy(&st->demod.ops, &dib7000p_ops, sizeof(struct dvb_frontend_ops));
2327
Olivier Grenie713d54a2011-01-04 04:54:31 -03002328 dib7000p_write_word(st, 1287, 0x0003); /* sram lead in, rdy */
Olivier Grenieeac1fe12009-09-23 13:41:27 -03002329
Patrick Boettchera75763f2006-10-18 08:34:16 -03002330 if (dib7000p_identify(st) != 0)
2331 goto error;
2332
Olivier Grenie713d54a2011-01-04 04:54:31 -03002333 st->version = dib7000p_read_word(st, 897);
2334
Martin Samek7646b9d2009-09-30 22:59:09 -03002335 /* FIXME: make sure the dev.parent field is initialized, or else
Olivier Grenie713d54a2011-01-04 04:54:31 -03002336 request_firmware() will hit an OOPS (this should be moved somewhere
2337 more common) */
Martin Samek7646b9d2009-09-30 22:59:09 -03002338
Patrick Boettchera75763f2006-10-18 08:34:16 -03002339 dibx000_init_i2c_master(&st->i2c_master, DIB7000P, st->i2c_adap, st->i2c_addr);
2340
Olivier Grenie713d54a2011-01-04 04:54:31 -03002341 /* init 7090 tuner adapter */
2342 strncpy(st->dib7090_tuner_adap.name, "DiB7090 tuner interface", sizeof(st->dib7090_tuner_adap.name));
2343 st->dib7090_tuner_adap.algo = &dib7090_tuner_xfer_algo;
2344 st->dib7090_tuner_adap.algo_data = NULL;
2345 st->dib7090_tuner_adap.dev.parent = st->i2c_adap->dev.parent;
2346 i2c_set_adapdata(&st->dib7090_tuner_adap, st);
2347 i2c_add_adapter(&st->dib7090_tuner_adap);
2348
Patrick Boettchera75763f2006-10-18 08:34:16 -03002349 dib7000p_demod_reset(st);
2350
Olivier Grenie713d54a2011-01-04 04:54:31 -03002351 if (st->version == SOC7090) {
2352 dib7090_set_output_mode(demod, st->cfg.output_mode);
2353 dib7090_set_diversity_in(demod, 0);
2354 }
2355
Patrick Boettchera75763f2006-10-18 08:34:16 -03002356 return demod;
2357
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002358error:
Patrick Boettchera75763f2006-10-18 08:34:16 -03002359 kfree(st);
2360 return NULL;
2361}
2362EXPORT_SYMBOL(dib7000p_attach);
2363
2364static struct dvb_frontend_ops dib7000p_ops = {
2365 .info = {
Olivier Grenie713d54a2011-01-04 04:54:31 -03002366 .name = "DiBcom 7000PC",
2367 .type = FE_OFDM,
2368 .frequency_min = 44250000,
2369 .frequency_max = 867250000,
2370 .frequency_stepsize = 62500,
2371 .caps = FE_CAN_INVERSION_AUTO |
2372 FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
2373 FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
2374 FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO |
2375 FE_CAN_TRANSMISSION_MODE_AUTO | FE_CAN_GUARD_INTERVAL_AUTO | FE_CAN_RECOVER | FE_CAN_HIERARCHY_AUTO,
2376 },
Patrick Boettchera75763f2006-10-18 08:34:16 -03002377
Olivier Grenie713d54a2011-01-04 04:54:31 -03002378 .release = dib7000p_release,
Patrick Boettchera75763f2006-10-18 08:34:16 -03002379
Olivier Grenie713d54a2011-01-04 04:54:31 -03002380 .init = dib7000p_wakeup,
2381 .sleep = dib7000p_sleep,
Patrick Boettchera75763f2006-10-18 08:34:16 -03002382
Olivier Grenie713d54a2011-01-04 04:54:31 -03002383 .set_frontend = dib7000p_set_frontend,
2384 .get_tune_settings = dib7000p_fe_get_tune_settings,
2385 .get_frontend = dib7000p_get_frontend,
Patrick Boettchera75763f2006-10-18 08:34:16 -03002386
Olivier Grenie713d54a2011-01-04 04:54:31 -03002387 .read_status = dib7000p_read_status,
2388 .read_ber = dib7000p_read_ber,
Patrick Boettchera75763f2006-10-18 08:34:16 -03002389 .read_signal_strength = dib7000p_read_signal_strength,
Olivier Grenie713d54a2011-01-04 04:54:31 -03002390 .read_snr = dib7000p_read_snr,
2391 .read_ucblocks = dib7000p_read_unc_blocks,
Patrick Boettchera75763f2006-10-18 08:34:16 -03002392};
2393
Olivier Grenie713d54a2011-01-04 04:54:31 -03002394MODULE_AUTHOR("Olivier Grenie <ogrenie@dibcom.fr>");
Patrick Boettchera75763f2006-10-18 08:34:16 -03002395MODULE_AUTHOR("Patrick Boettcher <pboettcher@dibcom.fr>");
2396MODULE_DESCRIPTION("Driver for the DiBcom 7000PC COFDM demodulator");
2397MODULE_LICENSE("GPL");