blob: 18495bd166e66ca6a3be631e258cc3a51f09f0d1 [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;
Patrick Boettchera75763f2006-10-18 08:34:16 -030066};
67
68enum dib7000p_power_mode {
69 DIB7000P_POWER_ALL = 0,
Patrick Boettcherb6884a12007-07-27 10:08:51 -030070 DIB7000P_POWER_ANALOG_ADC,
Patrick Boettchera75763f2006-10-18 08:34:16 -030071 DIB7000P_POWER_INTERFACE_ONLY,
72};
73
Olivier Grenie713d54a2011-01-04 04:54:31 -030074static int dib7090_set_output_mode(struct dvb_frontend *fe, int mode);
75static int dib7090_set_diversity_in(struct dvb_frontend *fe, int onoff);
76
Patrick Boettchera75763f2006-10-18 08:34:16 -030077static u16 dib7000p_read_word(struct dib7000p_state *state, u16 reg)
78{
79 u8 wb[2] = { reg >> 8, reg & 0xff };
80 u8 rb[2];
81 struct i2c_msg msg[2] = {
Olivier Grenie713d54a2011-01-04 04:54:31 -030082 {.addr = state->i2c_addr >> 1,.flags = 0,.buf = wb,.len = 2},
83 {.addr = state->i2c_addr >> 1,.flags = I2C_M_RD,.buf = rb,.len = 2},
Patrick Boettchera75763f2006-10-18 08:34:16 -030084 };
85
86 if (i2c_transfer(state->i2c_adap, msg, 2) != 2)
Olivier Grenie713d54a2011-01-04 04:54:31 -030087 dprintk("i2c read error on %d", reg);
Patrick Boettchera75763f2006-10-18 08:34:16 -030088
89 return (rb[0] << 8) | rb[1];
90}
91
92static int dib7000p_write_word(struct dib7000p_state *state, u16 reg, u16 val)
93{
94 u8 b[4] = {
95 (reg >> 8) & 0xff, reg & 0xff,
96 (val >> 8) & 0xff, val & 0xff,
97 };
98 struct i2c_msg msg = {
Olivier Grenie713d54a2011-01-04 04:54:31 -030099 .addr = state->i2c_addr >> 1,.flags = 0,.buf = b,.len = 4
Patrick Boettchera75763f2006-10-18 08:34:16 -0300100 };
101 return i2c_transfer(state->i2c_adap, &msg, 1) != 1 ? -EREMOTEIO : 0;
102}
Olivier Grenie713d54a2011-01-04 04:54:31 -0300103
104static void dib7000p_write_tab(struct dib7000p_state *state, u16 * buf)
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300105{
106 u16 l = 0, r, *n;
107 n = buf;
108 l = *n++;
109 while (l) {
110 r = *n++;
111
112 do {
113 dib7000p_write_word(state, r, *n++);
114 r++;
115 } while (--l);
116 l = *n++;
117 }
118}
119
Patrick Boettchera75763f2006-10-18 08:34:16 -0300120static int dib7000p_set_output_mode(struct dib7000p_state *state, int mode)
121{
Olivier Grenie713d54a2011-01-04 04:54:31 -0300122 int ret = 0;
Patrick Boettchera75763f2006-10-18 08:34:16 -0300123 u16 outreg, fifo_threshold, smo_mode;
124
125 outreg = 0;
126 fifo_threshold = 1792;
Olivier Grenieeac1fe12009-09-23 13:41:27 -0300127 smo_mode = (dib7000p_read_word(state, 235) & 0x0050) | (1 << 1);
Patrick Boettchera75763f2006-10-18 08:34:16 -0300128
Olivier Grenie713d54a2011-01-04 04:54:31 -0300129 dprintk("setting output mode for demod %p to %d", &state->demod, mode);
Patrick Boettchera75763f2006-10-18 08:34:16 -0300130
131 switch (mode) {
Olivier Grenie713d54a2011-01-04 04:54:31 -0300132 case OUTMODE_MPEG2_PAR_GATED_CLK: // STBs with parallel gated clock
133 outreg = (1 << 10); /* 0x0400 */
134 break;
135 case OUTMODE_MPEG2_PAR_CONT_CLK: // STBs with parallel continues clock
136 outreg = (1 << 10) | (1 << 6); /* 0x0440 */
137 break;
138 case OUTMODE_MPEG2_SERIAL: // STBs with serial input
139 outreg = (1 << 10) | (2 << 6) | (0 << 1); /* 0x0480 */
140 break;
141 case OUTMODE_DIVERSITY:
142 if (state->cfg.hostbus_diversity)
143 outreg = (1 << 10) | (4 << 6); /* 0x0500 */
144 else
145 outreg = (1 << 11);
146 break;
147 case OUTMODE_MPEG2_FIFO: // e.g. USB feeding
148 smo_mode |= (3 << 1);
149 fifo_threshold = 512;
150 outreg = (1 << 10) | (5 << 6);
151 break;
152 case OUTMODE_ANALOG_ADC:
153 outreg = (1 << 10) | (3 << 6);
154 break;
155 case OUTMODE_HIGH_Z: // disable
156 outreg = 0;
157 break;
158 default:
159 dprintk("Unhandled output_mode passed to be set for demod %p", &state->demod);
160 break;
Patrick Boettchera75763f2006-10-18 08:34:16 -0300161 }
162
163 if (state->cfg.output_mpeg2_in_188_bytes)
Olivier Grenie713d54a2011-01-04 04:54:31 -0300164 smo_mode |= (1 << 5);
Patrick Boettchera75763f2006-10-18 08:34:16 -0300165
Olivier Grenie713d54a2011-01-04 04:54:31 -0300166 ret |= dib7000p_write_word(state, 235, smo_mode);
167 ret |= dib7000p_write_word(state, 236, fifo_threshold); /* synchronous fread */
168 if (state->version != SOC7090)
169 ret |= dib7000p_write_word(state, 1286, outreg); /* P_Div_active */
Patrick Boettchera75763f2006-10-18 08:34:16 -0300170
171 return ret;
172}
173
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300174static int dib7000p_set_diversity_in(struct dvb_frontend *demod, int onoff)
175{
176 struct dib7000p_state *state = demod->demodulator_priv;
177
178 if (state->div_force_off) {
Olivier Grenie713d54a2011-01-04 04:54:31 -0300179 dprintk("diversity combination deactivated - forced by COFDM parameters");
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300180 onoff = 0;
Olivier Grenieeac1fe12009-09-23 13:41:27 -0300181 dib7000p_write_word(state, 207, 0);
182 } else
183 dib7000p_write_word(state, 207, (state->div_sync_wait << 4) | (1 << 2) | (2 << 0));
184
Olivier Grenie713d54a2011-01-04 04:54:31 -0300185 state->div_state = (u8) onoff;
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300186
187 if (onoff) {
188 dib7000p_write_word(state, 204, 6);
189 dib7000p_write_word(state, 205, 16);
190 /* P_dvsy_sync_mode = 0, P_dvsy_sync_enable=1, P_dvcb_comb_mode=2 */
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300191 } else {
192 dib7000p_write_word(state, 204, 1);
193 dib7000p_write_word(state, 205, 0);
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300194 }
195
196 return 0;
197}
198
Patrick Boettchera75763f2006-10-18 08:34:16 -0300199static int dib7000p_set_power_mode(struct dib7000p_state *state, enum dib7000p_power_mode mode)
200{
201 /* by default everything is powered off */
Olivier Grenie713d54a2011-01-04 04:54:31 -0300202 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 -0300203
204 /* now, depending on the requested mode, we power on */
205 switch (mode) {
206 /* power up everything in the demod */
Olivier Grenie713d54a2011-01-04 04:54:31 -0300207 case DIB7000P_POWER_ALL:
208 reg_774 = 0x0000;
209 reg_775 = 0x0000;
210 reg_776 = 0x0;
211 reg_899 = 0x0;
212 if (state->version == SOC7090)
213 reg_1280 &= 0x001f;
214 else
215 reg_1280 &= 0x01ff;
216 break;
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300217
Olivier Grenie713d54a2011-01-04 04:54:31 -0300218 case DIB7000P_POWER_ANALOG_ADC:
219 /* dem, cfg, iqc, sad, agc */
220 reg_774 &= ~((1 << 15) | (1 << 14) | (1 << 11) | (1 << 10) | (1 << 9));
221 /* nud */
222 reg_776 &= ~((1 << 0));
223 /* Dout */
224 if (state->version != SOC7090)
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300225 reg_1280 &= ~((1 << 11));
Olivier Grenie713d54a2011-01-04 04:54:31 -0300226 reg_1280 &= ~(1 << 6);
227 /* fall through wanted to enable the interfaces */
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300228
Patrick Boettchera75763f2006-10-18 08:34:16 -0300229 /* just leave power on the control-interfaces: GPIO and (I2C or SDIO) */
Olivier Grenie713d54a2011-01-04 04:54:31 -0300230 case DIB7000P_POWER_INTERFACE_ONLY: /* TODO power up either SDIO or I2C */
231 if (state->version == SOC7090)
232 reg_1280 &= ~((1 << 7) | (1 << 5));
233 else
Patrick Boettchera75763f2006-10-18 08:34:16 -0300234 reg_1280 &= ~((1 << 14) | (1 << 13) | (1 << 12) | (1 << 10));
Olivier Grenie713d54a2011-01-04 04:54:31 -0300235 break;
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300236
Patrick Boettchera75763f2006-10-18 08:34:16 -0300237/* TODO following stuff is just converted from the dib7000-driver - check when is used what */
238 }
239
Olivier Grenie713d54a2011-01-04 04:54:31 -0300240 dib7000p_write_word(state, 774, reg_774);
241 dib7000p_write_word(state, 775, reg_775);
242 dib7000p_write_word(state, 776, reg_776);
243 dib7000p_write_word(state, 899, reg_899);
Patrick Boettchera75763f2006-10-18 08:34:16 -0300244 dib7000p_write_word(state, 1280, reg_1280);
245
246 return 0;
247}
248
249static void dib7000p_set_adc_state(struct dib7000p_state *state, enum dibx000_adc_states no)
250{
Olivier Grenie713d54a2011-01-04 04:54:31 -0300251 u16 reg_908 = dib7000p_read_word(state, 908), reg_909 = dib7000p_read_word(state, 909);
252 u16 reg;
Patrick Boettchera75763f2006-10-18 08:34:16 -0300253
254 switch (no) {
Olivier Grenie713d54a2011-01-04 04:54:31 -0300255 case DIBX000_SLOW_ADC_ON:
256 if (state->version == SOC7090) {
257 reg = dib7000p_read_word(state, 1925);
258
259 dib7000p_write_word(state, 1925, reg | (1 << 4) | (1 << 2)); /* en_slowAdc = 1 & reset_sladc = 1 */
260
261 reg = dib7000p_read_word(state, 1925); /* read acces to make it works... strange ... */
262 msleep(200);
263 dib7000p_write_word(state, 1925, reg & ~(1 << 4)); /* en_slowAdc = 1 & reset_sladc = 0 */
264
265 reg = dib7000p_read_word(state, 72) & ~((0x3 << 14) | (0x3 << 12));
266 dib7000p_write_word(state, 72, reg | (1 << 14) | (3 << 12) | 524); /* ref = Vin1 => Vbg ; sel = Vin0 or Vin3 ; (Vin2 = Vcm) */
267 } else {
Patrick Boettchera75763f2006-10-18 08:34:16 -0300268 reg_909 |= (1 << 1) | (1 << 0);
269 dib7000p_write_word(state, 909, reg_909);
270 reg_909 &= ~(1 << 1);
Olivier Grenie713d54a2011-01-04 04:54:31 -0300271 }
272 break;
Patrick Boettchera75763f2006-10-18 08:34:16 -0300273
Olivier Grenie713d54a2011-01-04 04:54:31 -0300274 case DIBX000_SLOW_ADC_OFF:
275 if (state->version == SOC7090) {
276 reg = dib7000p_read_word(state, 1925);
277 dib7000p_write_word(state, 1925, (reg & ~(1 << 2)) | (1 << 4)); /* reset_sladc = 1 en_slowAdc = 0 */
278 } else
279 reg_909 |= (1 << 1) | (1 << 0);
280 break;
Patrick Boettchera75763f2006-10-18 08:34:16 -0300281
Olivier Grenie713d54a2011-01-04 04:54:31 -0300282 case DIBX000_ADC_ON:
283 reg_908 &= 0x0fff;
284 reg_909 &= 0x0003;
285 break;
Patrick Boettchera75763f2006-10-18 08:34:16 -0300286
Olivier Grenie713d54a2011-01-04 04:54:31 -0300287 case DIBX000_ADC_OFF: // leave the VBG voltage on
288 reg_908 |= (1 << 14) | (1 << 13) | (1 << 12);
289 reg_909 |= (1 << 5) | (1 << 4) | (1 << 3) | (1 << 2);
290 break;
Patrick Boettchera75763f2006-10-18 08:34:16 -0300291
Olivier Grenie713d54a2011-01-04 04:54:31 -0300292 case DIBX000_VBG_ENABLE:
293 reg_908 &= ~(1 << 15);
294 break;
Patrick Boettchera75763f2006-10-18 08:34:16 -0300295
Olivier Grenie713d54a2011-01-04 04:54:31 -0300296 case DIBX000_VBG_DISABLE:
297 reg_908 |= (1 << 15);
298 break;
Patrick Boettchera75763f2006-10-18 08:34:16 -0300299
Olivier Grenie713d54a2011-01-04 04:54:31 -0300300 default:
301 break;
Patrick Boettchera75763f2006-10-18 08:34:16 -0300302 }
303
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300304// dprintk( "908: %x, 909: %x\n", reg_908, reg_909);
Patrick Boettchera75763f2006-10-18 08:34:16 -0300305
Olivier Grenie970d14c2010-09-07 12:50:46 -0300306 reg_909 |= (state->cfg.disable_sample_and_hold & 1) << 4;
Olivier Grenie90e12ce2010-09-07 12:50:45 -0300307 reg_908 |= (state->cfg.enable_current_mirror & 1) << 7;
308
Patrick Boettchera75763f2006-10-18 08:34:16 -0300309 dib7000p_write_word(state, 908, reg_908);
310 dib7000p_write_word(state, 909, reg_909);
311}
312
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300313static int dib7000p_set_bandwidth(struct dib7000p_state *state, u32 bw)
Patrick Boettchera75763f2006-10-18 08:34:16 -0300314{
Patrick Boettchera75763f2006-10-18 08:34:16 -0300315 u32 timf;
316
317 // store the current bandwidth for later use
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300318 state->current_bandwidth = bw;
Patrick Boettchera75763f2006-10-18 08:34:16 -0300319
320 if (state->timf == 0) {
Olivier Grenie713d54a2011-01-04 04:54:31 -0300321 dprintk("using default timf");
Patrick Boettchera75763f2006-10-18 08:34:16 -0300322 timf = state->cfg.bw->timf;
323 } else {
Olivier Grenie713d54a2011-01-04 04:54:31 -0300324 dprintk("using updated timf");
Patrick Boettchera75763f2006-10-18 08:34:16 -0300325 timf = state->timf;
326 }
327
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300328 timf = timf * (bw / 50) / 160;
Patrick Boettchera75763f2006-10-18 08:34:16 -0300329
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300330 dib7000p_write_word(state, 23, (u16) ((timf >> 16) & 0xffff));
Olivier Grenie713d54a2011-01-04 04:54:31 -0300331 dib7000p_write_word(state, 24, (u16) ((timf) & 0xffff));
Patrick Boettchera75763f2006-10-18 08:34:16 -0300332
333 return 0;
334}
335
336static int dib7000p_sad_calib(struct dib7000p_state *state)
337{
338/* internal */
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300339// dib7000p_write_word(state, 72, (3 << 14) | (1 << 12) | (524 << 0)); // sampling clock of the SAD is writting in set_bandwidth
Patrick Boettchera75763f2006-10-18 08:34:16 -0300340 dib7000p_write_word(state, 73, (0 << 1) | (0 << 0));
Olivier Grenie713d54a2011-01-04 04:54:31 -0300341
342 if (state->version == SOC7090)
343 dib7000p_write_word(state, 74, 2048); // P_sad_calib_value = (0.9/1.8)*4096
344 else
345 dib7000p_write_word(state, 74, 776); // P_sad_calib_value = 0.625*3.3 / 4096
Patrick Boettchera75763f2006-10-18 08:34:16 -0300346
347 /* do the calibration */
348 dib7000p_write_word(state, 73, (1 << 0));
349 dib7000p_write_word(state, 73, (0 << 0));
350
351 msleep(1);
352
353 return 0;
354}
355
Patrick Boettcher01373a52007-07-30 12:49:04 -0300356int dib7000p_set_wbd_ref(struct dvb_frontend *demod, u16 value)
357{
358 struct dib7000p_state *state = demod->demodulator_priv;
359 if (value > 4095)
360 value = 4095;
361 state->wbd_ref = value;
362 return dib7000p_write_word(state, 105, (dib7000p_read_word(state, 105) & 0xf000) | value);
363}
Patrick Boettcher01373a52007-07-30 12:49:04 -0300364EXPORT_SYMBOL(dib7000p_set_wbd_ref);
Olivier Grenie713d54a2011-01-04 04:54:31 -0300365
Patrick Boettchera75763f2006-10-18 08:34:16 -0300366static void dib7000p_reset_pll(struct dib7000p_state *state)
367{
368 struct dibx000_bandwidth_config *bw = &state->cfg.bw[0];
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300369 u16 clk_cfg0;
Patrick Boettchera75763f2006-10-18 08:34:16 -0300370
Olivier Grenie713d54a2011-01-04 04:54:31 -0300371 if (state->version == SOC7090) {
372 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 -0300373
Olivier Grenie713d54a2011-01-04 04:54:31 -0300374 while (((dib7000p_read_word(state, 1856) >> 15) & 0x1) != 1) {
375 }
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300376
Olivier Grenie713d54a2011-01-04 04:54:31 -0300377 dib7000p_write_word(state, 1857, dib7000p_read_word(state, 1857) | (!bw->pll_bypass << 15));
378 } else {
379 /* force PLL bypass */
380 clk_cfg0 = (1 << 15) | ((bw->pll_ratio & 0x3f) << 9) |
381 (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 -0300382
Olivier Grenie713d54a2011-01-04 04:54:31 -0300383 dib7000p_write_word(state, 900, clk_cfg0);
384
385 /* P_pll_cfg */
386 dib7000p_write_word(state, 903, (bw->pll_prediv << 5) | (((bw->pll_ratio >> 6) & 0x3) << 3) | (bw->pll_range << 1) | bw->pll_reset);
387 clk_cfg0 = (bw->pll_bypass << 15) | (clk_cfg0 & 0x7fff);
388 dib7000p_write_word(state, 900, clk_cfg0);
389 }
390
391 dib7000p_write_word(state, 18, (u16) (((bw->internal * 1000) >> 16) & 0xffff));
392 dib7000p_write_word(state, 19, (u16) ((bw->internal * 1000) & 0xffff));
393 dib7000p_write_word(state, 21, (u16) ((bw->ifreq >> 16) & 0xffff));
394 dib7000p_write_word(state, 22, (u16) ((bw->ifreq) & 0xffff));
Patrick Boettchera75763f2006-10-18 08:34:16 -0300395
396 dib7000p_write_word(state, 72, bw->sad_cfg);
397}
398
Olivier Grenie713d54a2011-01-04 04:54:31 -0300399static u32 dib7000p_get_internal_freq(struct dib7000p_state *state)
400{
401 u32 internal = (u32) dib7000p_read_word(state, 18) << 16;
402 internal |= (u32) dib7000p_read_word(state, 19);
403 internal /= 1000;
404
405 return internal;
406}
407
408int dib7000p_update_pll(struct dvb_frontend *fe, struct dibx000_bandwidth_config *bw)
409{
410 struct dib7000p_state *state = fe->demodulator_priv;
411 u16 reg_1857, reg_1856 = dib7000p_read_word(state, 1856);
412 u8 loopdiv, prediv;
413 u32 internal, xtal;
414
415 /* get back old values */
416 prediv = reg_1856 & 0x3f;
417 loopdiv = (reg_1856 >> 6) & 0x3f;
418
419 if ((bw != NULL) && (bw->pll_prediv != prediv || bw->pll_ratio != loopdiv)) {
420 dprintk("Updating pll (prediv: old = %d new = %d ; loopdiv : old = %d new = %d)", prediv, bw->pll_prediv, loopdiv, bw->pll_ratio);
421 reg_1856 &= 0xf000;
422 reg_1857 = dib7000p_read_word(state, 1857);
423 dib7000p_write_word(state, 1857, reg_1857 & ~(1 << 15)); // desable pll
424
425 dib7000p_write_word(state, 1856, reg_1856 | ((bw->pll_ratio & 0x3f) << 6) | (bw->pll_prediv & 0x3f));
426
427 /* write new system clk into P_sec_len */
428 internal = dib7000p_get_internal_freq(state);
429 xtal = (internal / loopdiv) * prediv;
430 internal = 1000 * (xtal / bw->pll_prediv) * bw->pll_ratio; /* new internal */
431 dib7000p_write_word(state, 18, (u16) ((internal >> 16) & 0xffff));
432 dib7000p_write_word(state, 19, (u16) (internal & 0xffff));
433
434 dib7000p_write_word(state, 1857, reg_1857 | (1 << 15)); // enable pll
435
436 while (((dib7000p_read_word(state, 1856) >> 15) & 0x1) != 1) {
437 dprintk("Waiting for PLL to lock");
438 }
439
440 return 0;
441 }
442 return -EIO;
443}
444EXPORT_SYMBOL(dib7000p_update_pll);
445
Patrick Boettchera75763f2006-10-18 08:34:16 -0300446static int dib7000p_reset_gpio(struct dib7000p_state *st)
447{
448 /* reset the GPIOs */
Olivier Grenie713d54a2011-01-04 04:54:31 -0300449 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 -0300450
451 dib7000p_write_word(st, 1029, st->gpio_dir);
452 dib7000p_write_word(st, 1030, st->gpio_val);
453
454 /* TODO 1031 is P_gpio_od */
455
456 dib7000p_write_word(st, 1032, st->cfg.gpio_pwm_pos);
457
458 dib7000p_write_word(st, 1037, st->cfg.pwm_freq_div);
459 return 0;
460}
461
Patrick Boettcher01373a52007-07-30 12:49:04 -0300462static int dib7000p_cfg_gpio(struct dib7000p_state *st, u8 num, u8 dir, u8 val)
463{
464 st->gpio_dir = dib7000p_read_word(st, 1029);
Olivier Grenie713d54a2011-01-04 04:54:31 -0300465 st->gpio_dir &= ~(1 << num); /* reset the direction bit */
466 st->gpio_dir |= (dir & 0x1) << num; /* set the new direction */
Patrick Boettcher01373a52007-07-30 12:49:04 -0300467 dib7000p_write_word(st, 1029, st->gpio_dir);
468
469 st->gpio_val = dib7000p_read_word(st, 1030);
Olivier Grenie713d54a2011-01-04 04:54:31 -0300470 st->gpio_val &= ~(1 << num); /* reset the direction bit */
471 st->gpio_val |= (val & 0x01) << num; /* set the new value */
Patrick Boettcher01373a52007-07-30 12:49:04 -0300472 dib7000p_write_word(st, 1030, st->gpio_val);
473
474 return 0;
475}
476
477int dib7000p_set_gpio(struct dvb_frontend *demod, u8 num, u8 dir, u8 val)
478{
479 struct dib7000p_state *state = demod->demodulator_priv;
480 return dib7000p_cfg_gpio(state, num, dir, val);
481}
Patrick Boettcher01373a52007-07-30 12:49:04 -0300482EXPORT_SYMBOL(dib7000p_set_gpio);
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300483
Olivier Grenie713d54a2011-01-04 04:54:31 -0300484static u16 dib7000p_defaults[] = {
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300485 // auto search configuration
486 3, 2,
Olivier Grenie713d54a2011-01-04 04:54:31 -0300487 0x0004,
488 0x1000,
489 0x0814, /* Equal Lock */
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300490
491 12, 6,
Olivier Grenie713d54a2011-01-04 04:54:31 -0300492 0x001b,
493 0x7740,
494 0x005b,
495 0x8d80,
496 0x01c9,
497 0xc380,
498 0x0000,
499 0x0080,
500 0x0000,
501 0x0090,
502 0x0001,
503 0xd4c0,
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300504
505 1, 26,
Olivier Grenie713d54a2011-01-04 04:54:31 -0300506 0x6680, // P_timf_alpha=6, P_corm_alpha=6, P_corm_thres=128 default: 6,4,26
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300507
508 /* set ADC level to -16 */
509 11, 79,
Olivier Grenie713d54a2011-01-04 04:54:31 -0300510 (1 << 13) - 825 - 117,
511 (1 << 13) - 837 - 117,
512 (1 << 13) - 811 - 117,
513 (1 << 13) - 766 - 117,
514 (1 << 13) - 737 - 117,
515 (1 << 13) - 693 - 117,
516 (1 << 13) - 648 - 117,
517 (1 << 13) - 619 - 117,
518 (1 << 13) - 575 - 117,
519 (1 << 13) - 531 - 117,
520 (1 << 13) - 501 - 117,
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300521
522 1, 142,
Olivier Grenie713d54a2011-01-04 04:54:31 -0300523 0x0410, // P_palf_filter_on=1, P_palf_filter_freeze=0, P_palf_alpha_regul=16
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300524
525 /* disable power smoothing */
526 8, 145,
Olivier Grenie713d54a2011-01-04 04:54:31 -0300527 0,
528 0,
529 0,
530 0,
531 0,
532 0,
533 0,
534 0,
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300535
536 1, 154,
Olivier Grenie713d54a2011-01-04 04:54:31 -0300537 1 << 13, // P_fft_freq_dir=1, P_fft_nb_to_cut=0
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300538
539 1, 168,
Olivier Grenie713d54a2011-01-04 04:54:31 -0300540 0x0ccd, // P_pha3_thres, default 0x3000
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300541
542// 1, 169,
543// 0x0010, // P_cti_use_cpe=0, P_cti_use_prog=0, P_cti_win_len=16, default: 0x0010
544
545 1, 183,
Olivier Grenie713d54a2011-01-04 04:54:31 -0300546 0x200f, // P_cspu_regul=512, P_cspu_win_cut=15, default: 0x2005
547
548 1, 212,
549 0x169, // P_vit_ksi_dwn = 5 P_vit_ksi_up = 5 0x1e1, // P_vit_ksi_dwn = 4 P_vit_ksi_up = 7
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300550
551 5, 187,
Olivier Grenie713d54a2011-01-04 04:54:31 -0300552 0x023d, // P_adp_regul_cnt=573, default: 410
553 0x00a4, // P_adp_noise_cnt=
554 0x00a4, // P_adp_regul_ext
555 0x7ff0, // P_adp_noise_ext
556 0x3ccc, // P_adp_fil
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300557
558 1, 198,
Olivier Grenie713d54a2011-01-04 04:54:31 -0300559 0x800, // P_equal_thres_wgn
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300560
561 1, 222,
Olivier Grenie713d54a2011-01-04 04:54:31 -0300562 0x0010, // P_fec_ber_rs_len=2
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300563
564 1, 235,
Olivier Grenie713d54a2011-01-04 04:54:31 -0300565 0x0062, // P_smo_mode, P_smo_rs_discard, P_smo_fifo_flush, P_smo_pid_parse, P_smo_error_discard
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300566
567 2, 901,
Olivier Grenie713d54a2011-01-04 04:54:31 -0300568 0x0006, // P_clk_cfg1
569 (3 << 10) | (1 << 6), // P_divclksel=3 P_divbitsel=1
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300570
571 1, 905,
Olivier Grenie713d54a2011-01-04 04:54:31 -0300572 0x2c8e, // Tuner IO bank: max drive (14mA) + divout pads max drive
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300573
574 0,
575};
576
Patrick Boettchera75763f2006-10-18 08:34:16 -0300577static int dib7000p_demod_reset(struct dib7000p_state *state)
578{
579 dib7000p_set_power_mode(state, DIB7000P_POWER_ALL);
580
Olivier Grenie713d54a2011-01-04 04:54:31 -0300581 if (state->version == SOC7090)
582 dibx000_reset_i2c_master(&state->i2c_master);
583
Patrick Boettchera75763f2006-10-18 08:34:16 -0300584 dib7000p_set_adc_state(state, DIBX000_VBG_ENABLE);
585
586 /* restart all parts */
Olivier Grenie713d54a2011-01-04 04:54:31 -0300587 dib7000p_write_word(state, 770, 0xffff);
588 dib7000p_write_word(state, 771, 0xffff);
589 dib7000p_write_word(state, 772, 0x001f);
590 dib7000p_write_word(state, 898, 0x0003);
591 dib7000p_write_word(state, 1280, 0x001f - ((1 << 4) | (1 << 3)));
Patrick Boettchera75763f2006-10-18 08:34:16 -0300592
Olivier Grenie713d54a2011-01-04 04:54:31 -0300593 dib7000p_write_word(state, 770, 0);
594 dib7000p_write_word(state, 771, 0);
595 dib7000p_write_word(state, 772, 0);
596 dib7000p_write_word(state, 898, 0);
Patrick Boettchera75763f2006-10-18 08:34:16 -0300597 dib7000p_write_word(state, 1280, 0);
598
599 /* default */
600 dib7000p_reset_pll(state);
601
602 if (dib7000p_reset_gpio(state) != 0)
Olivier Grenie713d54a2011-01-04 04:54:31 -0300603 dprintk("GPIO reset was not successful.");
Patrick Boettchera75763f2006-10-18 08:34:16 -0300604
Olivier Grenie713d54a2011-01-04 04:54:31 -0300605 if (state->version == SOC7090) {
606 dib7000p_write_word(state, 899, 0);
607
608 /* impulse noise */
609 dib7000p_write_word(state, 42, (1<<5) | 3); /* P_iqc_thsat_ipc = 1 ; P_iqc_win2 = 3 */
610 dib7000p_write_word(state, 43, 0x2d4); /*-300 fag P_iqc_dect_min = -280 */
611 dib7000p_write_word(state, 44, 300); /* 300 fag P_iqc_dect_min = +280 */
612 //dib7000p_write_word(state, 273, (1<<6) | 10); /* P_vit_inoise_sel = 1, P_vit_inoise_gain = 10*/
613 dib7000p_write_word(state, 273, (1<<6) | 30); //26/* P_vit_inoise_sel = 1, P_vit_inoise_gain = 26*/// FAG
614 }
Patrick Boettchera75763f2006-10-18 08:34:16 -0300615 if (dib7000p_set_output_mode(state, OUTMODE_HIGH_Z) != 0)
Olivier Grenie713d54a2011-01-04 04:54:31 -0300616 dprintk("OUTPUT_MODE could not be reset.");
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300617
618 dib7000p_set_adc_state(state, DIBX000_SLOW_ADC_ON);
619 dib7000p_sad_calib(state);
620 dib7000p_set_adc_state(state, DIBX000_SLOW_ADC_OFF);
621
Olivier Grenie713d54a2011-01-04 04:54:31 -0300622 /* unforce divstr regardless whether i2c enumeration was done or not */
623 dib7000p_write_word(state, 1285, dib7000p_read_word(state, 1285) & ~(1 << 1));
624
625 dib7000p_set_bandwidth(state, 8000);
626
627 if(state->version == SOC7090) {
628 dib7000p_write_word(state, 36, 0x5755);/* P_iqc_impnc_on =1 & P_iqc_corr_inh = 1 for impulsive noise */
629 } else { // P_iqc_alpha_pha, P_iqc_alpha_amp_dcc_alpha, ...
630 if (state->cfg.tuner_is_baseband)
631 dib7000p_write_word(state, 36, 0x0755);
632 else
633 dib7000p_write_word(state, 36, 0x1f55);
634 }
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300635
636 dib7000p_write_tab(state, dib7000p_defaults);
637
Patrick Boettchera75763f2006-10-18 08:34:16 -0300638 dib7000p_set_power_mode(state, DIB7000P_POWER_INTERFACE_ONLY);
639
640 return 0;
641}
642
Patrick Boettchera75763f2006-10-18 08:34:16 -0300643static void dib7000p_pll_clk_cfg(struct dib7000p_state *state)
644{
645 u16 tmp = 0;
646 tmp = dib7000p_read_word(state, 903);
Olivier Grenie713d54a2011-01-04 04:54:31 -0300647 dib7000p_write_word(state, 903, (tmp | 0x1)); //pwr-up pll
Patrick Boettchera75763f2006-10-18 08:34:16 -0300648 tmp = dib7000p_read_word(state, 900);
Olivier Grenie713d54a2011-01-04 04:54:31 -0300649 dib7000p_write_word(state, 900, (tmp & 0x7fff) | (1 << 6)); //use High freq clock
Patrick Boettchera75763f2006-10-18 08:34:16 -0300650}
651
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300652static void dib7000p_restart_agc(struct dib7000p_state *state)
Patrick Boettchera75763f2006-10-18 08:34:16 -0300653{
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300654 // P_restart_iqc & P_restart_agc
655 dib7000p_write_word(state, 770, (1 << 11) | (1 << 9));
656 dib7000p_write_word(state, 770, 0x0000);
Patrick Boettchera75763f2006-10-18 08:34:16 -0300657}
658
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300659static int dib7000p_update_lna(struct dib7000p_state *state)
Patrick Boettchera75763f2006-10-18 08:34:16 -0300660{
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300661 u16 dyn_gain;
662
663 // when there is no LNA to program return immediatly
664 if (state->cfg.update_lna) {
Patrick Boettcher01373a52007-07-30 12:49:04 -0300665 // read dyn_gain here (because it is demod-dependent and not fe)
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300666 dyn_gain = dib7000p_read_word(state, 394);
Olivier Grenie713d54a2011-01-04 04:54:31 -0300667 if (state->cfg.update_lna(&state->demod, dyn_gain)) { // LNA has changed
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300668 dib7000p_restart_agc(state);
669 return 1;
670 }
671 }
672
673 return 0;
674}
675
676static int dib7000p_set_agc_config(struct dib7000p_state *state, u8 band)
677{
678 struct dibx000_agc_config *agc = NULL;
679 int i;
680 if (state->current_band == band && state->current_agc != NULL)
681 return 0;
682 state->current_band = band;
683
684 for (i = 0; i < state->cfg.agc_config_count; i++)
685 if (state->cfg.agc[i].band_caps & band) {
686 agc = &state->cfg.agc[i];
687 break;
688 }
689
690 if (agc == NULL) {
Olivier Grenie713d54a2011-01-04 04:54:31 -0300691 dprintk("no valid AGC configuration found for band 0x%02x", band);
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300692 return -EINVAL;
693 }
694
695 state->current_agc = agc;
696
697 /* AGC */
Olivier Grenie713d54a2011-01-04 04:54:31 -0300698 dib7000p_write_word(state, 75, agc->setup);
699 dib7000p_write_word(state, 76, agc->inv_gain);
700 dib7000p_write_word(state, 77, agc->time_stabiliz);
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300701 dib7000p_write_word(state, 100, (agc->alpha_level << 12) | agc->thlock);
702
703 // Demod AGC loop configuration
704 dib7000p_write_word(state, 101, (agc->alpha_mant << 5) | agc->alpha_exp);
Olivier Grenie713d54a2011-01-04 04:54:31 -0300705 dib7000p_write_word(state, 102, (agc->beta_mant << 6) | agc->beta_exp);
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300706
707 /* AGC continued */
Olivier Grenie713d54a2011-01-04 04:54:31 -0300708 dprintk("WBD: ref: %d, sel: %d, active: %d, alpha: %d",
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300709 state->wbd_ref != 0 ? state->wbd_ref : agc->wbd_ref, agc->wbd_sel, !agc->perform_agc_softsplit, agc->wbd_sel);
710
711 if (state->wbd_ref != 0)
712 dib7000p_write_word(state, 105, (agc->wbd_inv << 12) | state->wbd_ref);
713 else
714 dib7000p_write_word(state, 105, (agc->wbd_inv << 12) | agc->wbd_ref);
715
716 dib7000p_write_word(state, 106, (agc->wbd_sel << 13) | (agc->wbd_alpha << 9) | (agc->perform_agc_softsplit << 8));
717
Olivier Grenie713d54a2011-01-04 04:54:31 -0300718 dib7000p_write_word(state, 107, agc->agc1_max);
719 dib7000p_write_word(state, 108, agc->agc1_min);
720 dib7000p_write_word(state, 109, agc->agc2_max);
721 dib7000p_write_word(state, 110, agc->agc2_min);
722 dib7000p_write_word(state, 111, (agc->agc1_pt1 << 8) | agc->agc1_pt2);
723 dib7000p_write_word(state, 112, agc->agc1_pt3);
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300724 dib7000p_write_word(state, 113, (agc->agc1_slope1 << 8) | agc->agc1_slope2);
Olivier Grenie713d54a2011-01-04 04:54:31 -0300725 dib7000p_write_word(state, 114, (agc->agc2_pt1 << 8) | agc->agc2_pt2);
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300726 dib7000p_write_word(state, 115, (agc->agc2_slope1 << 8) | agc->agc2_slope2);
727 return 0;
728}
729
Olivier Grenie713d54a2011-01-04 04:54:31 -0300730static void dib7000p_set_dds(struct dib7000p_state *state, s32 offset_khz)
731{
732 u32 internal = dib7000p_get_internal_freq(state);
733 s32 unit_khz_dds_val = 67108864 / (internal); /* 2**26 / Fsampling is the unit 1KHz offset */
734 u32 abs_offset_khz = ABS(offset_khz);
735 u32 dds = state->cfg.bw->ifreq & 0x1ffffff;
736 u8 invert = !!(state->cfg.bw->ifreq & (1 << 25));
737
738 dprintk("setting a frequency offset of %dkHz internal freq = %d invert = %d", offset_khz, internal, invert);
739
740 if (offset_khz < 0)
741 unit_khz_dds_val *= -1;
742
743 /* IF tuner */
744 if (invert)
745 dds -= (abs_offset_khz * unit_khz_dds_val); /* /100 because of /100 on the unit_khz_dds_val line calc for better accuracy */
746 else
747 dds += (abs_offset_khz * unit_khz_dds_val);
748
749 if (abs_offset_khz <= (internal / 2)) { /* Max dds offset is the half of the demod freq */
750 dib7000p_write_word(state, 21, (u16) (((dds >> 16) & 0x1ff) | (0 << 10) | (invert << 9)));
751 dib7000p_write_word(state, 22, (u16) (dds & 0xffff));
752 }
753}
754
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300755static int dib7000p_agc_startup(struct dvb_frontend *demod, struct dvb_frontend_parameters *ch)
756{
757 struct dib7000p_state *state = demod->demodulator_priv;
758 int ret = -1;
759 u8 *agc_state = &state->agc_state;
760 u8 agc_split;
Olivier Grenie713d54a2011-01-04 04:54:31 -0300761 u16 reg;
762 u32 upd_demod_gain_period = 0x1000;
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300763
764 switch (state->agc_state) {
Olivier Grenie713d54a2011-01-04 04:54:31 -0300765 case 0:
766 // set power-up level: interf+analog+AGC
767 dib7000p_set_power_mode(state, DIB7000P_POWER_ALL);
768 if (state->version == SOC7090) {
769 reg = dib7000p_read_word(state, 0x79b) & 0xff00;
770 dib7000p_write_word(state, 0x79a, upd_demod_gain_period & 0xFFFF); /* lsb */
771 dib7000p_write_word(state, 0x79b, reg | (1 << 14) | ((upd_demod_gain_period >> 16) & 0xFF)); // bit 14 = enDemodGain
772
773 /* enable adc i & q */
774 reg = dib7000p_read_word(state, 0x780);
775 dib7000p_write_word(state, 0x780, (reg | (0x3)) & (~(1 << 7)));
776 } else {
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300777 dib7000p_set_adc_state(state, DIBX000_ADC_ON);
778 dib7000p_pll_clk_cfg(state);
Olivier Grenie713d54a2011-01-04 04:54:31 -0300779 }
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300780
Olivier Grenie713d54a2011-01-04 04:54:31 -0300781 if (dib7000p_set_agc_config(state, BAND_OF_FREQUENCY(ch->frequency / 1000)) != 0)
782 return -1;
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300783
Olivier Grenie713d54a2011-01-04 04:54:31 -0300784 dib7000p_set_dds(state, 0);
785 ret = 7;
786 (*agc_state)++;
787 break;
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300788
Olivier Grenie713d54a2011-01-04 04:54:31 -0300789 case 1:
790 // AGC initialization
791 if (state->cfg.agc_control)
792 state->cfg.agc_control(&state->demod, 1);
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300793
Olivier Grenie713d54a2011-01-04 04:54:31 -0300794 dib7000p_write_word(state, 78, 32768);
795 if (!state->current_agc->perform_agc_softsplit) {
796 /* we are using the wbd - so slow AGC startup */
797 /* force 0 split on WBD and restart AGC */
798 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 -0300799 (*agc_state)++;
800 ret = 5;
Olivier Grenie713d54a2011-01-04 04:54:31 -0300801 } else {
802 /* default AGC startup */
803 (*agc_state) = 4;
804 /* wait AGC rough lock time */
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300805 ret = 7;
Olivier Grenie713d54a2011-01-04 04:54:31 -0300806 }
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300807
Olivier Grenie713d54a2011-01-04 04:54:31 -0300808 dib7000p_restart_agc(state);
809 break;
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300810
Olivier Grenie713d54a2011-01-04 04:54:31 -0300811 case 2: /* fast split search path after 5sec */
812 dib7000p_write_word(state, 75, state->current_agc->setup | (1 << 4)); /* freeze AGC loop */
813 dib7000p_write_word(state, 106, (state->current_agc->wbd_sel << 13) | (2 << 9) | (0 << 8)); /* fast split search 0.25kHz */
814 (*agc_state)++;
815 ret = 14;
816 break;
817
818 case 3: /* split search ended */
819 agc_split = (u8) dib7000p_read_word(state, 396); /* store the split value for the next time */
820 dib7000p_write_word(state, 78, dib7000p_read_word(state, 394)); /* set AGC gain start value */
821
822 dib7000p_write_word(state, 75, state->current_agc->setup); /* std AGC loop */
823 dib7000p_write_word(state, 106, (state->current_agc->wbd_sel << 13) | (state->current_agc->wbd_alpha << 9) | agc_split); /* standard split search */
824
825 dib7000p_restart_agc(state);
826
827 dprintk("SPLIT %p: %hd", demod, agc_split);
828
829 (*agc_state)++;
830 ret = 5;
831 break;
832
833 case 4: /* LNA startup */
834 // wait AGC accurate lock time
835 ret = 7;
836
837 if (dib7000p_update_lna(state))
838 // wait only AGC rough lock time
839 ret = 5;
840 else // nothing was done, go to the next state
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300841 (*agc_state)++;
Olivier Grenie713d54a2011-01-04 04:54:31 -0300842 break;
843
844 case 5:
845 if (state->cfg.agc_control)
846 state->cfg.agc_control(&state->demod, 0);
847 (*agc_state)++;
848 break;
849 default:
850 break;
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300851 }
852 return ret;
853}
854
855static void dib7000p_update_timf(struct dib7000p_state *state)
856{
857 u32 timf = (dib7000p_read_word(state, 427) << 16) | dib7000p_read_word(state, 428);
858 state->timf = timf * 160 / (state->current_bandwidth / 50);
859 dib7000p_write_word(state, 23, (u16) (timf >> 16));
860 dib7000p_write_word(state, 24, (u16) (timf & 0xffff));
Olivier Grenie713d54a2011-01-04 04:54:31 -0300861 dprintk("updated timf_frequency: %d (default: %d)", state->timf, state->cfg.bw->timf);
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300862
863}
864
Olivier Grenie713d54a2011-01-04 04:54:31 -0300865u32 dib7000p_ctrl_timf(struct dvb_frontend *fe, u8 op, u32 timf)
866{
867 struct dib7000p_state *state = fe->demodulator_priv;
868 switch (op) {
869 case DEMOD_TIMF_SET:
870 state->timf = timf;
871 break;
872 case DEMOD_TIMF_UPDATE:
873 dib7000p_update_timf(state);
874 break;
875 case DEMOD_TIMF_GET:
876 break;
877 }
878 dib7000p_set_bandwidth(state, state->current_bandwidth);
879 return state->timf;
880}
881EXPORT_SYMBOL(dib7000p_ctrl_timf);
882
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300883static void dib7000p_set_channel(struct dib7000p_state *state, struct dvb_frontend_parameters *ch, u8 seq)
884{
885 u16 value, est[4];
886
Olivier Grenie713d54a2011-01-04 04:54:31 -0300887 dib7000p_set_bandwidth(state, BANDWIDTH_TO_KHZ(ch->u.ofdm.bandwidth));
Patrick Boettchera75763f2006-10-18 08:34:16 -0300888
889 /* nfft, guard, qam, alpha */
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300890 value = 0;
891 switch (ch->u.ofdm.transmission_mode) {
Olivier Grenie713d54a2011-01-04 04:54:31 -0300892 case TRANSMISSION_MODE_2K:
893 value |= (0 << 7);
894 break;
895 case TRANSMISSION_MODE_4K:
896 value |= (2 << 7);
897 break;
898 default:
899 case TRANSMISSION_MODE_8K:
900 value |= (1 << 7);
901 break;
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300902 }
903 switch (ch->u.ofdm.guard_interval) {
Olivier Grenie713d54a2011-01-04 04:54:31 -0300904 case GUARD_INTERVAL_1_32:
905 value |= (0 << 5);
906 break;
907 case GUARD_INTERVAL_1_16:
908 value |= (1 << 5);
909 break;
910 case GUARD_INTERVAL_1_4:
911 value |= (3 << 5);
912 break;
913 default:
914 case GUARD_INTERVAL_1_8:
915 value |= (2 << 5);
916 break;
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300917 }
918 switch (ch->u.ofdm.constellation) {
Olivier Grenie713d54a2011-01-04 04:54:31 -0300919 case QPSK:
920 value |= (0 << 3);
921 break;
922 case QAM_16:
923 value |= (1 << 3);
924 break;
925 default:
926 case QAM_64:
927 value |= (2 << 3);
928 break;
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300929 }
930 switch (HIERARCHY_1) {
Olivier Grenie713d54a2011-01-04 04:54:31 -0300931 case HIERARCHY_2:
932 value |= 2;
933 break;
934 case HIERARCHY_4:
935 value |= 4;
936 break;
937 default:
938 case HIERARCHY_1:
939 value |= 1;
940 break;
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300941 }
942 dib7000p_write_word(state, 0, value);
Olivier Grenie713d54a2011-01-04 04:54:31 -0300943 dib7000p_write_word(state, 5, (seq << 4) | 1); /* do not force tps, search list 0 */
Patrick Boettchera75763f2006-10-18 08:34:16 -0300944
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300945 /* P_dintl_native, P_dintlv_inv, P_hrch, P_code_rate, P_select_hp */
946 value = 0;
947 if (1 != 0)
948 value |= (1 << 6);
949 if (ch->u.ofdm.hierarchy_information == 1)
950 value |= (1 << 4);
951 if (1 == 1)
952 value |= 1;
953 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 -0300954 case FEC_2_3:
955 value |= (2 << 1);
956 break;
957 case FEC_3_4:
958 value |= (3 << 1);
959 break;
960 case FEC_5_6:
961 value |= (5 << 1);
962 break;
963 case FEC_7_8:
964 value |= (7 << 1);
965 break;
966 default:
967 case FEC_1_2:
968 value |= (1 << 1);
969 break;
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300970 }
971 dib7000p_write_word(state, 208, value);
972
973 /* offset loop parameters */
Olivier Grenie713d54a2011-01-04 04:54:31 -0300974 dib7000p_write_word(state, 26, 0x6680); // timf(6xxx)
975 dib7000p_write_word(state, 32, 0x0003); // pha_off_max(xxx3)
976 dib7000p_write_word(state, 29, 0x1273); // isi
977 dib7000p_write_word(state, 33, 0x0005); // sfreq(xxx5)
Patrick Boettchera75763f2006-10-18 08:34:16 -0300978
979 /* P_dvsy_sync_wait */
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300980 switch (ch->u.ofdm.transmission_mode) {
Olivier Grenie713d54a2011-01-04 04:54:31 -0300981 case TRANSMISSION_MODE_8K:
982 value = 256;
983 break;
984 case TRANSMISSION_MODE_4K:
985 value = 128;
986 break;
987 case TRANSMISSION_MODE_2K:
988 default:
989 value = 64;
990 break;
Patrick Boettchera75763f2006-10-18 08:34:16 -0300991 }
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300992 switch (ch->u.ofdm.guard_interval) {
Olivier Grenie713d54a2011-01-04 04:54:31 -0300993 case GUARD_INTERVAL_1_16:
994 value *= 2;
995 break;
996 case GUARD_INTERVAL_1_8:
997 value *= 4;
998 break;
999 case GUARD_INTERVAL_1_4:
1000 value *= 8;
1001 break;
1002 default:
1003 case GUARD_INTERVAL_1_32:
1004 value *= 1;
1005 break;
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001006 }
Olivier Grenie970d14c2010-09-07 12:50:46 -03001007 if (state->cfg.diversity_delay == 0)
Olivier Grenie713d54a2011-01-04 04:54:31 -03001008 state->div_sync_wait = (value * 3) / 2 + 48; // add 50% SFN margin + compensate for one DVSY-fifo
Olivier Grenie970d14c2010-09-07 12:50:46 -03001009 else
Olivier Grenie713d54a2011-01-04 04:54:31 -03001010 state->div_sync_wait = (value * 3) / 2 + state->cfg.diversity_delay; // add 50% SFN margin + compensate for one DVSY-fifo
Patrick Boettchera75763f2006-10-18 08:34:16 -03001011
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001012 /* deactive the possibility of diversity reception if extended interleaver */
1013 state->div_force_off = !1 && ch->u.ofdm.transmission_mode != TRANSMISSION_MODE_8K;
1014 dib7000p_set_diversity_in(&state->demod, state->div_state);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001015
1016 /* channel estimation fine configuration */
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001017 switch (ch->u.ofdm.constellation) {
Olivier Grenie713d54a2011-01-04 04:54:31 -03001018 case QAM_64:
1019 est[0] = 0x0148; /* P_adp_regul_cnt 0.04 */
1020 est[1] = 0xfff0; /* P_adp_noise_cnt -0.002 */
1021 est[2] = 0x00a4; /* P_adp_regul_ext 0.02 */
1022 est[3] = 0xfff8; /* P_adp_noise_ext -0.001 */
1023 break;
1024 case QAM_16:
1025 est[0] = 0x023d; /* P_adp_regul_cnt 0.07 */
1026 est[1] = 0xffdf; /* P_adp_noise_cnt -0.004 */
1027 est[2] = 0x00a4; /* P_adp_regul_ext 0.02 */
1028 est[3] = 0xfff0; /* P_adp_noise_ext -0.002 */
1029 break;
1030 default:
1031 est[0] = 0x099a; /* P_adp_regul_cnt 0.3 */
1032 est[1] = 0xffae; /* P_adp_noise_cnt -0.01 */
1033 est[2] = 0x0333; /* P_adp_regul_ext 0.1 */
1034 est[3] = 0xfff8; /* P_adp_noise_ext -0.002 */
1035 break;
Patrick Boettchera75763f2006-10-18 08:34:16 -03001036 }
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001037 for (value = 0; value < 4; value++)
1038 dib7000p_write_word(state, 187 + value, est[value]);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001039}
1040
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001041static int dib7000p_autosearch_start(struct dvb_frontend *demod, struct dvb_frontend_parameters *ch)
Patrick Boettchera75763f2006-10-18 08:34:16 -03001042{
1043 struct dib7000p_state *state = demod->demodulator_priv;
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001044 struct dvb_frontend_parameters schan;
1045 u32 value, factor;
Olivier Grenie713d54a2011-01-04 04:54:31 -03001046 u32 internal = dib7000p_get_internal_freq(state);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001047
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001048 schan = *ch;
1049 schan.u.ofdm.constellation = QAM_64;
Olivier Grenie713d54a2011-01-04 04:54:31 -03001050 schan.u.ofdm.guard_interval = GUARD_INTERVAL_1_32;
1051 schan.u.ofdm.transmission_mode = TRANSMISSION_MODE_8K;
1052 schan.u.ofdm.code_rate_HP = FEC_2_3;
1053 schan.u.ofdm.code_rate_LP = FEC_3_4;
1054 schan.u.ofdm.hierarchy_information = 0;
Patrick Boettchera75763f2006-10-18 08:34:16 -03001055
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001056 dib7000p_set_channel(state, &schan, 7);
1057
1058 factor = BANDWIDTH_TO_KHZ(ch->u.ofdm.bandwidth);
1059 if (factor >= 5000)
1060 factor = 1;
1061 else
1062 factor = 6;
Patrick Boettchera75763f2006-10-18 08:34:16 -03001063
1064 // always use the setting for 8MHz here lock_time for 7,6 MHz are longer
Olivier Grenie713d54a2011-01-04 04:54:31 -03001065 value = 30 * internal * factor;
1066 dib7000p_write_word(state, 6, (u16) ((value >> 16) & 0xffff)); // lock0 wait time
1067 dib7000p_write_word(state, 7, (u16) (value & 0xffff)); // lock0 wait time
1068 value = 100 * internal * factor;
1069 dib7000p_write_word(state, 8, (u16) ((value >> 16) & 0xffff)); // lock1 wait time
1070 dib7000p_write_word(state, 9, (u16) (value & 0xffff)); // lock1 wait time
1071 value = 500 * internal * factor;
1072 dib7000p_write_word(state, 10, (u16) ((value >> 16) & 0xffff)); // lock2 wait time
1073 dib7000p_write_word(state, 11, (u16) (value & 0xffff)); // lock2 wait time
Patrick Boettchera75763f2006-10-18 08:34:16 -03001074
1075 value = dib7000p_read_word(state, 0);
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001076 dib7000p_write_word(state, 0, (u16) ((1 << 9) | value));
Patrick Boettchera75763f2006-10-18 08:34:16 -03001077 dib7000p_read_word(state, 1284);
1078 dib7000p_write_word(state, 0, (u16) value);
1079
1080 return 0;
1081}
1082
1083static int dib7000p_autosearch_is_irq(struct dvb_frontend *demod)
1084{
1085 struct dib7000p_state *state = demod->demodulator_priv;
1086 u16 irq_pending = dib7000p_read_word(state, 1284);
1087
Olivier Grenie713d54a2011-01-04 04:54:31 -03001088 if (irq_pending & 0x1) // failed
Patrick Boettchera75763f2006-10-18 08:34:16 -03001089 return 1;
1090
Olivier Grenie713d54a2011-01-04 04:54:31 -03001091 if (irq_pending & 0x2) // succeeded
Patrick Boettchera75763f2006-10-18 08:34:16 -03001092 return 2;
1093
Olivier Grenie713d54a2011-01-04 04:54:31 -03001094 return 0; // still pending
Patrick Boettchera75763f2006-10-18 08:34:16 -03001095}
1096
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001097static void dib7000p_spur_protect(struct dib7000p_state *state, u32 rf_khz, u32 bw)
1098{
Olivier Grenie713d54a2011-01-04 04:54:31 -03001099 static s16 notch[] = { 16143, 14402, 12238, 9713, 6902, 3888, 759, -2392 };
1100 static u8 sine[] = { 0, 2, 3, 5, 6, 8, 9, 11, 13, 14, 16, 17, 19, 20, 22,
1101 24, 25, 27, 28, 30, 31, 33, 34, 36, 38, 39, 41, 42, 44, 45, 47, 48, 50, 51,
1102 53, 55, 56, 58, 59, 61, 62, 64, 65, 67, 68, 70, 71, 73, 74, 76, 77, 79, 80,
1103 82, 83, 85, 86, 88, 89, 91, 92, 94, 95, 97, 98, 99, 101, 102, 104, 105,
1104 107, 108, 109, 111, 112, 114, 115, 117, 118, 119, 121, 122, 123, 125, 126,
1105 128, 129, 130, 132, 133, 134, 136, 137, 138, 140, 141, 142, 144, 145, 146,
1106 147, 149, 150, 151, 152, 154, 155, 156, 157, 159, 160, 161, 162, 164, 165,
1107 166, 167, 168, 170, 171, 172, 173, 174, 175, 177, 178, 179, 180, 181, 182,
1108 183, 184, 185, 186, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198,
1109 199, 200, 201, 202, 203, 204, 205, 206, 207, 207, 208, 209, 210, 211, 212,
1110 213, 214, 215, 215, 216, 217, 218, 219, 220, 220, 221, 222, 223, 224, 224,
1111 225, 226, 227, 227, 228, 229, 229, 230, 231, 231, 232, 233, 233, 234, 235,
1112 235, 236, 237, 237, 238, 238, 239, 239, 240, 241, 241, 242, 242, 243, 243,
1113 244, 244, 245, 245, 245, 246, 246, 247, 247, 248, 248, 248, 249, 249, 249,
1114 250, 250, 250, 251, 251, 251, 252, 252, 252, 252, 253, 253, 253, 253, 254,
1115 254, 254, 254, 254, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
1116 255, 255, 255, 255, 255, 255
1117 };
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001118
1119 u32 xtal = state->cfg.bw->xtal_hz / 1000;
Julia Lawall75b697f2009-08-01 16:48:41 -03001120 int f_rel = DIV_ROUND_CLOSEST(rf_khz, xtal) * xtal - rf_khz;
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001121 int k;
Olivier Grenie713d54a2011-01-04 04:54:31 -03001122 int coef_re[8], coef_im[8];
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001123 int bw_khz = bw;
1124 u32 pha;
1125
Olivier Grenie713d54a2011-01-04 04:54:31 -03001126 dprintk("relative position of the Spur: %dk (RF: %dk, XTAL: %dk)", f_rel, rf_khz, xtal);
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001127
Olivier Grenie713d54a2011-01-04 04:54:31 -03001128 if (f_rel < -bw_khz / 2 || f_rel > bw_khz / 2)
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001129 return;
1130
1131 bw_khz /= 100;
1132
Olivier Grenie713d54a2011-01-04 04:54:31 -03001133 dib7000p_write_word(state, 142, 0x0610);
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001134
1135 for (k = 0; k < 8; k++) {
Olivier Grenie713d54a2011-01-04 04:54:31 -03001136 pha = ((f_rel * (k + 1) * 112 * 80 / bw_khz) / 1000) & 0x3ff;
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001137
Olivier Grenie713d54a2011-01-04 04:54:31 -03001138 if (pha == 0) {
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001139 coef_re[k] = 256;
1140 coef_im[k] = 0;
Olivier Grenie713d54a2011-01-04 04:54:31 -03001141 } else if (pha < 256) {
1142 coef_re[k] = sine[256 - (pha & 0xff)];
1143 coef_im[k] = sine[pha & 0xff];
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001144 } else if (pha == 256) {
1145 coef_re[k] = 0;
1146 coef_im[k] = 256;
1147 } else if (pha < 512) {
Olivier Grenie713d54a2011-01-04 04:54:31 -03001148 coef_re[k] = -sine[pha & 0xff];
1149 coef_im[k] = sine[256 - (pha & 0xff)];
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001150 } else if (pha == 512) {
1151 coef_re[k] = -256;
1152 coef_im[k] = 0;
1153 } else if (pha < 768) {
Olivier Grenie713d54a2011-01-04 04:54:31 -03001154 coef_re[k] = -sine[256 - (pha & 0xff)];
1155 coef_im[k] = -sine[pha & 0xff];
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001156 } else if (pha == 768) {
1157 coef_re[k] = 0;
1158 coef_im[k] = -256;
1159 } else {
Olivier Grenie713d54a2011-01-04 04:54:31 -03001160 coef_re[k] = sine[pha & 0xff];
1161 coef_im[k] = -sine[256 - (pha & 0xff)];
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001162 }
1163
1164 coef_re[k] *= notch[k];
Olivier Grenie713d54a2011-01-04 04:54:31 -03001165 coef_re[k] += (1 << 14);
1166 if (coef_re[k] >= (1 << 24))
1167 coef_re[k] = (1 << 24) - 1;
1168 coef_re[k] /= (1 << 15);
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001169
1170 coef_im[k] *= notch[k];
Olivier Grenie713d54a2011-01-04 04:54:31 -03001171 coef_im[k] += (1 << 14);
1172 if (coef_im[k] >= (1 << 24))
1173 coef_im[k] = (1 << 24) - 1;
1174 coef_im[k] /= (1 << 15);
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001175
Olivier Grenie713d54a2011-01-04 04:54:31 -03001176 dprintk("PALF COEF: %d re: %d im: %d", k, coef_re[k], coef_im[k]);
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001177
1178 dib7000p_write_word(state, 143, (0 << 14) | (k << 10) | (coef_re[k] & 0x3ff));
1179 dib7000p_write_word(state, 144, coef_im[k] & 0x3ff);
1180 dib7000p_write_word(state, 143, (1 << 14) | (k << 10) | (coef_re[k] & 0x3ff));
1181 }
Olivier Grenie713d54a2011-01-04 04:54:31 -03001182 dib7000p_write_word(state, 143, 0);
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001183}
1184
1185static int dib7000p_tune(struct dvb_frontend *demod, struct dvb_frontend_parameters *ch)
Patrick Boettchera75763f2006-10-18 08:34:16 -03001186{
1187 struct dib7000p_state *state = demod->demodulator_priv;
1188 u16 tmp = 0;
1189
1190 if (ch != NULL)
1191 dib7000p_set_channel(state, ch, 0);
1192 else
1193 return -EINVAL;
1194
1195 // restart demod
1196 dib7000p_write_word(state, 770, 0x4000);
1197 dib7000p_write_word(state, 770, 0x0000);
1198 msleep(45);
1199
1200 /* 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 -03001201 tmp = (0 << 14) | (4 << 10) | (0 << 9) | (3 << 5) | (1 << 4) | (0x3);
1202 if (state->sfn_workaround_active) {
Olivier Grenie713d54a2011-01-04 04:54:31 -03001203 dprintk("SFN workaround is active");
Matt Doran8f6956c2007-07-31 07:09:30 -03001204 tmp |= (1 << 9);
Olivier Grenie713d54a2011-01-04 04:54:31 -03001205 dib7000p_write_word(state, 166, 0x4000); // P_pha3_force_pha_shift
Matt Doran8f6956c2007-07-31 07:09:30 -03001206 } else {
Olivier Grenie713d54a2011-01-04 04:54:31 -03001207 dib7000p_write_word(state, 166, 0x0000); // P_pha3_force_pha_shift
Matt Doran8f6956c2007-07-31 07:09:30 -03001208 }
1209 dib7000p_write_word(state, 29, tmp);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001210
1211 // never achieved a lock with that bandwidth so far - wait for osc-freq to update
1212 if (state->timf == 0)
1213 msleep(200);
1214
1215 /* offset loop parameters */
1216
1217 /* P_timf_alpha, P_corm_alpha=6, P_corm_thres=0x80 */
1218 tmp = (6 << 8) | 0x80;
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001219 switch (ch->u.ofdm.transmission_mode) {
Olivier Grenie713d54a2011-01-04 04:54:31 -03001220 case TRANSMISSION_MODE_2K:
1221 tmp |= (2 << 12);
1222 break;
1223 case TRANSMISSION_MODE_4K:
1224 tmp |= (3 << 12);
1225 break;
1226 default:
1227 case TRANSMISSION_MODE_8K:
1228 tmp |= (4 << 12);
1229 break;
Patrick Boettchera75763f2006-10-18 08:34:16 -03001230 }
Olivier Grenie713d54a2011-01-04 04:54:31 -03001231 dib7000p_write_word(state, 26, tmp); /* timf_a(6xxx) */
Patrick Boettchera75763f2006-10-18 08:34:16 -03001232
1233 /* P_ctrl_freeze_pha_shift=0, P_ctrl_pha_off_max */
1234 tmp = (0 << 4);
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001235 switch (ch->u.ofdm.transmission_mode) {
Olivier Grenie713d54a2011-01-04 04:54:31 -03001236 case TRANSMISSION_MODE_2K:
1237 tmp |= 0x6;
1238 break;
1239 case TRANSMISSION_MODE_4K:
1240 tmp |= 0x7;
1241 break;
1242 default:
1243 case TRANSMISSION_MODE_8K:
1244 tmp |= 0x8;
1245 break;
Patrick Boettchera75763f2006-10-18 08:34:16 -03001246 }
Olivier Grenie713d54a2011-01-04 04:54:31 -03001247 dib7000p_write_word(state, 32, tmp);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001248
1249 /* P_ctrl_sfreq_inh=0, P_ctrl_sfreq_step */
1250 tmp = (0 << 4);
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001251 switch (ch->u.ofdm.transmission_mode) {
Olivier Grenie713d54a2011-01-04 04:54:31 -03001252 case TRANSMISSION_MODE_2K:
1253 tmp |= 0x6;
1254 break;
1255 case TRANSMISSION_MODE_4K:
1256 tmp |= 0x7;
1257 break;
1258 default:
1259 case TRANSMISSION_MODE_8K:
1260 tmp |= 0x8;
1261 break;
Patrick Boettchera75763f2006-10-18 08:34:16 -03001262 }
Olivier Grenie713d54a2011-01-04 04:54:31 -03001263 dib7000p_write_word(state, 33, tmp);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001264
Olivier Grenie713d54a2011-01-04 04:54:31 -03001265 tmp = dib7000p_read_word(state, 509);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001266 if (!((tmp >> 6) & 0x1)) {
1267 /* restart the fec */
Olivier Grenie713d54a2011-01-04 04:54:31 -03001268 tmp = dib7000p_read_word(state, 771);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001269 dib7000p_write_word(state, 771, tmp | (1 << 1));
1270 dib7000p_write_word(state, 771, tmp);
Olivier Grenie713d54a2011-01-04 04:54:31 -03001271 msleep(40);
1272 tmp = dib7000p_read_word(state, 509);
1273 }
1274 // we achieved a lock - it's time to update the osc freq
1275 if ((tmp >> 6) & 0x1) {
1276 dib7000p_update_timf(state);
1277 /* P_timf_alpha += 2 */
1278 tmp = dib7000p_read_word(state, 26);
1279 dib7000p_write_word(state, 26, (tmp & ~(0xf << 12)) | ((((tmp >> 12) & 0xf) + 5) << 12));
Patrick Boettchera75763f2006-10-18 08:34:16 -03001280 }
1281
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001282 if (state->cfg.spur_protect)
Olivier Grenie713d54a2011-01-04 04:54:31 -03001283 dib7000p_spur_protect(state, ch->frequency / 1000, BANDWIDTH_TO_KHZ(ch->u.ofdm.bandwidth));
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001284
Olivier Grenie713d54a2011-01-04 04:54:31 -03001285 dib7000p_set_bandwidth(state, BANDWIDTH_TO_KHZ(ch->u.ofdm.bandwidth));
Patrick Boettchera75763f2006-10-18 08:34:16 -03001286 return 0;
1287}
1288
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001289static int dib7000p_wakeup(struct dvb_frontend *demod)
Patrick Boettchera75763f2006-10-18 08:34:16 -03001290{
Patrick Boettchera75763f2006-10-18 08:34:16 -03001291 struct dib7000p_state *state = demod->demodulator_priv;
Patrick Boettchera75763f2006-10-18 08:34:16 -03001292 dib7000p_set_power_mode(state, DIB7000P_POWER_ALL);
1293 dib7000p_set_adc_state(state, DIBX000_SLOW_ADC_ON);
Olivier Grenie713d54a2011-01-04 04:54:31 -03001294 if (state->version == SOC7090)
1295 dib7000p_sad_calib(state);
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001296 return 0;
Patrick Boettchera75763f2006-10-18 08:34:16 -03001297}
1298
1299static int dib7000p_sleep(struct dvb_frontend *demod)
1300{
1301 struct dib7000p_state *state = demod->demodulator_priv;
Olivier Grenie713d54a2011-01-04 04:54:31 -03001302 if (state->version == SOC7090)
1303 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 -03001304 return dib7000p_set_output_mode(state, OUTMODE_HIGH_Z) | dib7000p_set_power_mode(state, DIB7000P_POWER_INTERFACE_ONLY);
1305}
1306
1307static int dib7000p_identify(struct dib7000p_state *st)
1308{
1309 u16 value;
Olivier Grenie713d54a2011-01-04 04:54:31 -03001310 dprintk("checking demod on I2C address: %d (%x)", st->i2c_addr, st->i2c_addr);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001311
1312 if ((value = dib7000p_read_word(st, 768)) != 0x01b3) {
Olivier Grenie713d54a2011-01-04 04:54:31 -03001313 dprintk("wrong Vendor ID (read=0x%x)", value);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001314 return -EREMOTEIO;
1315 }
1316
1317 if ((value = dib7000p_read_word(st, 769)) != 0x4000) {
Olivier Grenie713d54a2011-01-04 04:54:31 -03001318 dprintk("wrong Device ID (%x)", value);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001319 return -EREMOTEIO;
1320 }
1321
1322 return 0;
1323}
1324
Olivier Grenie713d54a2011-01-04 04:54:31 -03001325static int dib7000p_get_frontend(struct dvb_frontend *fe, struct dvb_frontend_parameters *fep)
Patrick Boettchera75763f2006-10-18 08:34:16 -03001326{
1327 struct dib7000p_state *state = fe->demodulator_priv;
Olivier Grenie713d54a2011-01-04 04:54:31 -03001328 u16 tps = dib7000p_read_word(state, 463);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001329
1330 fep->inversion = INVERSION_AUTO;
1331
Patrick Boettcher904a82e2008-01-25 07:31:58 -03001332 fep->u.ofdm.bandwidth = BANDWIDTH_TO_INDEX(state->current_bandwidth);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001333
1334 switch ((tps >> 8) & 0x3) {
Olivier Grenie713d54a2011-01-04 04:54:31 -03001335 case 0:
1336 fep->u.ofdm.transmission_mode = TRANSMISSION_MODE_2K;
1337 break;
1338 case 1:
1339 fep->u.ofdm.transmission_mode = TRANSMISSION_MODE_8K;
1340 break;
Patrick Boettchera75763f2006-10-18 08:34:16 -03001341 /* case 2: fep->u.ofdm.transmission_mode = TRANSMISSION_MODE_4K; break; */
1342 }
1343
1344 switch (tps & 0x3) {
Olivier Grenie713d54a2011-01-04 04:54:31 -03001345 case 0:
1346 fep->u.ofdm.guard_interval = GUARD_INTERVAL_1_32;
1347 break;
1348 case 1:
1349 fep->u.ofdm.guard_interval = GUARD_INTERVAL_1_16;
1350 break;
1351 case 2:
1352 fep->u.ofdm.guard_interval = GUARD_INTERVAL_1_8;
1353 break;
1354 case 3:
1355 fep->u.ofdm.guard_interval = GUARD_INTERVAL_1_4;
1356 break;
Patrick Boettchera75763f2006-10-18 08:34:16 -03001357 }
1358
1359 switch ((tps >> 14) & 0x3) {
Olivier Grenie713d54a2011-01-04 04:54:31 -03001360 case 0:
1361 fep->u.ofdm.constellation = QPSK;
1362 break;
1363 case 1:
1364 fep->u.ofdm.constellation = QAM_16;
1365 break;
1366 case 2:
1367 default:
1368 fep->u.ofdm.constellation = QAM_64;
1369 break;
Patrick Boettchera75763f2006-10-18 08:34:16 -03001370 }
1371
1372 /* as long as the frontend_param structure is fixed for hierarchical transmission I refuse to use it */
1373 /* (tps >> 13) & 0x1 == hrch is used, (tps >> 10) & 0x7 == alpha */
1374
1375 fep->u.ofdm.hierarchy_information = HIERARCHY_NONE;
1376 switch ((tps >> 5) & 0x7) {
Olivier Grenie713d54a2011-01-04 04:54:31 -03001377 case 1:
1378 fep->u.ofdm.code_rate_HP = FEC_1_2;
1379 break;
1380 case 2:
1381 fep->u.ofdm.code_rate_HP = FEC_2_3;
1382 break;
1383 case 3:
1384 fep->u.ofdm.code_rate_HP = FEC_3_4;
1385 break;
1386 case 5:
1387 fep->u.ofdm.code_rate_HP = FEC_5_6;
1388 break;
1389 case 7:
1390 default:
1391 fep->u.ofdm.code_rate_HP = FEC_7_8;
1392 break;
Patrick Boettchera75763f2006-10-18 08:34:16 -03001393
1394 }
1395
1396 switch ((tps >> 2) & 0x7) {
Olivier Grenie713d54a2011-01-04 04:54:31 -03001397 case 1:
1398 fep->u.ofdm.code_rate_LP = FEC_1_2;
1399 break;
1400 case 2:
1401 fep->u.ofdm.code_rate_LP = FEC_2_3;
1402 break;
1403 case 3:
1404 fep->u.ofdm.code_rate_LP = FEC_3_4;
1405 break;
1406 case 5:
1407 fep->u.ofdm.code_rate_LP = FEC_5_6;
1408 break;
1409 case 7:
1410 default:
1411 fep->u.ofdm.code_rate_LP = FEC_7_8;
1412 break;
Patrick Boettchera75763f2006-10-18 08:34:16 -03001413 }
1414
1415 /* native interleaver: (dib7000p_read_word(state, 464) >> 5) & 0x1 */
1416
1417 return 0;
1418}
1419
Olivier Grenie713d54a2011-01-04 04:54:31 -03001420static int dib7000p_set_frontend(struct dvb_frontend *fe, struct dvb_frontend_parameters *fep)
Patrick Boettchera75763f2006-10-18 08:34:16 -03001421{
1422 struct dib7000p_state *state = fe->demodulator_priv;
Soeren Moch853ea132008-01-25 06:27:06 -03001423 int time, ret;
Patrick Boettchera75763f2006-10-18 08:34:16 -03001424
Olivier Grenie713d54a2011-01-04 04:54:31 -03001425 if (state->version == SOC7090) {
1426 dib7090_set_diversity_in(fe, 0);
1427 dib7090_set_output_mode(fe, OUTMODE_HIGH_Z);
1428 }
1429 else
1430 dib7000p_set_output_mode(state, OUTMODE_HIGH_Z);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001431
Olivier Grenie713d54a2011-01-04 04:54:31 -03001432 /* maybe the parameter has been changed */
Matt Doran8f6956c2007-07-31 07:09:30 -03001433 state->sfn_workaround_active = buggy_sfn_workaround;
1434
Patrick Boettchera75763f2006-10-18 08:34:16 -03001435 if (fe->ops.tuner_ops.set_params)
1436 fe->ops.tuner_ops.set_params(fe, fep);
1437
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001438 /* start up the AGC */
1439 state->agc_state = 0;
1440 do {
1441 time = dib7000p_agc_startup(fe, fep);
1442 if (time != -1)
1443 msleep(time);
1444 } while (time != -1);
1445
Patrick Boettchera75763f2006-10-18 08:34:16 -03001446 if (fep->u.ofdm.transmission_mode == TRANSMISSION_MODE_AUTO ||
Olivier Grenie713d54a2011-01-04 04:54:31 -03001447 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 -03001448 int i = 800, found;
1449
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001450 dib7000p_autosearch_start(fe, fep);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001451 do {
1452 msleep(1);
1453 found = dib7000p_autosearch_is_irq(fe);
1454 } while (found == 0 && i--);
1455
Olivier Grenie713d54a2011-01-04 04:54:31 -03001456 dprintk("autosearch returns: %d", found);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001457 if (found == 0 || found == 1)
Olivier Grenie713d54a2011-01-04 04:54:31 -03001458 return 0; // no channel found
Patrick Boettchera75763f2006-10-18 08:34:16 -03001459
1460 dib7000p_get_frontend(fe, fep);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001461 }
1462
Soeren Moch853ea132008-01-25 06:27:06 -03001463 ret = dib7000p_tune(fe, fep);
1464
Patrick Boettchera75763f2006-10-18 08:34:16 -03001465 /* make this a config parameter */
Olivier Grenie713d54a2011-01-04 04:54:31 -03001466 if (state->version == SOC7090)
1467 dib7090_set_output_mode(fe, state->cfg.output_mode);
1468 else
1469 dib7000p_set_output_mode(state, state->cfg.output_mode);
1470
1471 return ret;
Patrick Boettchera75763f2006-10-18 08:34:16 -03001472}
1473
Olivier Grenie713d54a2011-01-04 04:54:31 -03001474static int dib7000p_read_status(struct dvb_frontend *fe, fe_status_t * stat)
Patrick Boettchera75763f2006-10-18 08:34:16 -03001475{
1476 struct dib7000p_state *state = fe->demodulator_priv;
1477 u16 lock = dib7000p_read_word(state, 509);
1478
1479 *stat = 0;
1480
1481 if (lock & 0x8000)
1482 *stat |= FE_HAS_SIGNAL;
1483 if (lock & 0x3000)
1484 *stat |= FE_HAS_CARRIER;
1485 if (lock & 0x0100)
1486 *stat |= FE_HAS_VITERBI;
1487 if (lock & 0x0010)
1488 *stat |= FE_HAS_SYNC;
Olivier Grenie713d54a2011-01-04 04:54:31 -03001489 if ((lock & 0x0038) == 0x38)
Patrick Boettchera75763f2006-10-18 08:34:16 -03001490 *stat |= FE_HAS_LOCK;
1491
1492 return 0;
1493}
1494
Olivier Grenie713d54a2011-01-04 04:54:31 -03001495static int dib7000p_read_ber(struct dvb_frontend *fe, u32 * ber)
Patrick Boettchera75763f2006-10-18 08:34:16 -03001496{
1497 struct dib7000p_state *state = fe->demodulator_priv;
1498 *ber = (dib7000p_read_word(state, 500) << 16) | dib7000p_read_word(state, 501);
1499 return 0;
1500}
1501
Olivier Grenie713d54a2011-01-04 04:54:31 -03001502static int dib7000p_read_unc_blocks(struct dvb_frontend *fe, u32 * unc)
Patrick Boettchera75763f2006-10-18 08:34:16 -03001503{
1504 struct dib7000p_state *state = fe->demodulator_priv;
1505 *unc = dib7000p_read_word(state, 506);
1506 return 0;
1507}
1508
Olivier Grenie713d54a2011-01-04 04:54:31 -03001509static int dib7000p_read_signal_strength(struct dvb_frontend *fe, u16 * strength)
Patrick Boettchera75763f2006-10-18 08:34:16 -03001510{
1511 struct dib7000p_state *state = fe->demodulator_priv;
1512 u16 val = dib7000p_read_word(state, 394);
1513 *strength = 65535 - val;
1514 return 0;
1515}
1516
Olivier Grenie713d54a2011-01-04 04:54:31 -03001517static int dib7000p_read_snr(struct dvb_frontend *fe, u16 * snr)
Patrick Boettchera75763f2006-10-18 08:34:16 -03001518{
Olivier Grenieef801962009-09-15 06:46:52 -03001519 struct dib7000p_state *state = fe->demodulator_priv;
1520 u16 val;
1521 s32 signal_mant, signal_exp, noise_mant, noise_exp;
1522 u32 result = 0;
1523
1524 val = dib7000p_read_word(state, 479);
1525 noise_mant = (val >> 4) & 0xff;
1526 noise_exp = ((val & 0xf) << 2);
1527 val = dib7000p_read_word(state, 480);
1528 noise_exp += ((val >> 14) & 0x3);
1529 if ((noise_exp & 0x20) != 0)
1530 noise_exp -= 0x40;
1531
1532 signal_mant = (val >> 6) & 0xFF;
Olivier Grenie713d54a2011-01-04 04:54:31 -03001533 signal_exp = (val & 0x3F);
Olivier Grenieef801962009-09-15 06:46:52 -03001534 if ((signal_exp & 0x20) != 0)
1535 signal_exp -= 0x40;
1536
1537 if (signal_mant != 0)
Olivier Grenie713d54a2011-01-04 04:54:31 -03001538 result = intlog10(2) * 10 * signal_exp + 10 * intlog10(signal_mant);
Olivier Grenieef801962009-09-15 06:46:52 -03001539 else
1540 result = intlog10(2) * 10 * signal_exp - 100;
1541
1542 if (noise_mant != 0)
Olivier Grenie713d54a2011-01-04 04:54:31 -03001543 result -= intlog10(2) * 10 * noise_exp + 10 * intlog10(noise_mant);
Olivier Grenieef801962009-09-15 06:46:52 -03001544 else
1545 result -= intlog10(2) * 10 * noise_exp - 100;
1546
1547 *snr = result / ((1 << 24) / 10);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001548 return 0;
1549}
1550
Olivier Grenie713d54a2011-01-04 04:54:31 -03001551static int dib7000p_fe_get_tune_settings(struct dvb_frontend *fe, struct dvb_frontend_tune_settings *tune)
Patrick Boettchera75763f2006-10-18 08:34:16 -03001552{
1553 tune->min_delay_ms = 1000;
1554 return 0;
1555}
1556
1557static void dib7000p_release(struct dvb_frontend *demod)
1558{
1559 struct dib7000p_state *st = demod->demodulator_priv;
1560 dibx000_exit_i2c_master(&st->i2c_master);
Olivier Grenie713d54a2011-01-04 04:54:31 -03001561 i2c_del_adapter(&st->dib7090_tuner_adap);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001562 kfree(st);
1563}
1564
1565int dib7000pc_detection(struct i2c_adapter *i2c_adap)
1566{
1567 u8 tx[2], rx[2];
1568 struct i2c_msg msg[2] = {
Olivier Grenie713d54a2011-01-04 04:54:31 -03001569 {.addr = 18 >> 1,.flags = 0,.buf = tx,.len = 2},
1570 {.addr = 18 >> 1,.flags = I2C_M_RD,.buf = rx,.len = 2},
Patrick Boettchera75763f2006-10-18 08:34:16 -03001571 };
1572
1573 tx[0] = 0x03;
1574 tx[1] = 0x00;
1575
1576 if (i2c_transfer(i2c_adap, msg, 2) == 2)
1577 if (rx[0] == 0x01 && rx[1] == 0xb3) {
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001578 dprintk("-D- DiB7000PC detected");
Patrick Boettchera75763f2006-10-18 08:34:16 -03001579 return 1;
1580 }
1581
1582 msg[0].addr = msg[1].addr = 0x40;
1583
1584 if (i2c_transfer(i2c_adap, msg, 2) == 2)
1585 if (rx[0] == 0x01 && rx[1] == 0xb3) {
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001586 dprintk("-D- DiB7000PC detected");
Patrick Boettchera75763f2006-10-18 08:34:16 -03001587 return 1;
1588 }
1589
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001590 dprintk("-D- DiB7000PC not detected");
Patrick Boettchera75763f2006-10-18 08:34:16 -03001591 return 0;
1592}
1593EXPORT_SYMBOL(dib7000pc_detection);
1594
Olivier Grenie713d54a2011-01-04 04:54:31 -03001595struct i2c_adapter *dib7000p_get_i2c_master(struct dvb_frontend *demod, enum dibx000_i2c_interface intf, int gating)
Patrick Boettchera75763f2006-10-18 08:34:16 -03001596{
1597 struct dib7000p_state *st = demod->demodulator_priv;
1598 return dibx000_get_i2c_adapter(&st->i2c_master, intf, gating);
1599}
1600EXPORT_SYMBOL(dib7000p_get_i2c_master);
1601
Olivier Grenief8731f42009-09-18 04:08:43 -03001602int dib7000p_pid_filter_ctrl(struct dvb_frontend *fe, u8 onoff)
1603{
Olivier Grenie713d54a2011-01-04 04:54:31 -03001604 struct dib7000p_state *state = fe->demodulator_priv;
1605 u16 val = dib7000p_read_word(state, 235) & 0xffef;
1606 val |= (onoff & 0x1) << 4;
1607 dprintk("PID filter enabled %d", onoff);
1608 return dib7000p_write_word(state, 235, val);
Olivier Grenief8731f42009-09-18 04:08:43 -03001609}
1610EXPORT_SYMBOL(dib7000p_pid_filter_ctrl);
1611
1612int dib7000p_pid_filter(struct dvb_frontend *fe, u8 id, u16 pid, u8 onoff)
1613{
Olivier Grenie713d54a2011-01-04 04:54:31 -03001614 struct dib7000p_state *state = fe->demodulator_priv;
1615 dprintk("PID filter: index %x, PID %d, OnOff %d", id, pid, onoff);
1616 return dib7000p_write_word(state, 241 + id, onoff ? (1 << 13) | pid : 0);
Olivier Grenief8731f42009-09-18 04:08:43 -03001617}
1618EXPORT_SYMBOL(dib7000p_pid_filter);
1619
Patrick Boettchera75763f2006-10-18 08:34:16 -03001620int dib7000p_i2c_enumeration(struct i2c_adapter *i2c, int no_of_demods, u8 default_addr, struct dib7000p_config cfg[])
1621{
Randy Dunlap30d81bb2010-02-08 20:30:44 -03001622 struct dib7000p_state *dpst;
Patrick Boettchera75763f2006-10-18 08:34:16 -03001623 int k = 0;
1624 u8 new_addr = 0;
1625
Randy Dunlap30d81bb2010-02-08 20:30:44 -03001626 dpst = kzalloc(sizeof(struct dib7000p_state), GFP_KERNEL);
1627 if (!dpst)
Andrew Morton0b427602010-04-27 19:09:45 -03001628 return -ENOMEM;
Randy Dunlap30d81bb2010-02-08 20:30:44 -03001629
1630 dpst->i2c_adap = i2c;
1631
Olivier Grenie713d54a2011-01-04 04:54:31 -03001632 for (k = no_of_demods - 1; k >= 0; k--) {
Randy Dunlap30d81bb2010-02-08 20:30:44 -03001633 dpst->cfg = cfg[k];
Patrick Boettchera75763f2006-10-18 08:34:16 -03001634
1635 /* designated i2c address */
Olivier Grenie713d54a2011-01-04 04:54:31 -03001636 if (cfg[k].default_i2c_addr != 0)
1637 new_addr = cfg[k].default_i2c_addr + (k << 1);
1638 else
1639 new_addr = (0x40 + k) << 1;
Randy Dunlap30d81bb2010-02-08 20:30:44 -03001640 dpst->i2c_addr = new_addr;
Olivier Grenie713d54a2011-01-04 04:54:31 -03001641 dib7000p_write_word(dpst, 1287, 0x0003); /* sram lead in, rdy */
Randy Dunlap30d81bb2010-02-08 20:30:44 -03001642 if (dib7000p_identify(dpst) != 0) {
1643 dpst->i2c_addr = default_addr;
Olivier Grenie713d54a2011-01-04 04:54:31 -03001644 dib7000p_write_word(dpst, 1287, 0x0003); /* sram lead in, rdy */
Randy Dunlap30d81bb2010-02-08 20:30:44 -03001645 if (dib7000p_identify(dpst) != 0) {
Patrick Boettchera75763f2006-10-18 08:34:16 -03001646 dprintk("DiB7000P #%d: not identified\n", k);
Randy Dunlap30d81bb2010-02-08 20:30:44 -03001647 kfree(dpst);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001648 return -EIO;
1649 }
1650 }
1651
1652 /* start diversity to pull_down div_str - just for i2c-enumeration */
Randy Dunlap30d81bb2010-02-08 20:30:44 -03001653 dib7000p_set_output_mode(dpst, OUTMODE_DIVERSITY);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001654
1655 /* set new i2c address and force divstart */
Randy Dunlap30d81bb2010-02-08 20:30:44 -03001656 dib7000p_write_word(dpst, 1285, (new_addr << 2) | 0x2);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001657
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001658 dprintk("IC %d initialized (to i2c_address 0x%x)", k, new_addr);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001659 }
1660
1661 for (k = 0; k < no_of_demods; k++) {
Randy Dunlap30d81bb2010-02-08 20:30:44 -03001662 dpst->cfg = cfg[k];
Olivier Grenie713d54a2011-01-04 04:54:31 -03001663 if (cfg[k].default_i2c_addr != 0)
1664 dpst->i2c_addr = (cfg[k].default_i2c_addr + k) << 1;
1665 else
1666 dpst->i2c_addr = (0x40 + k) << 1;
Patrick Boettchera75763f2006-10-18 08:34:16 -03001667
1668 // unforce divstr
Randy Dunlap30d81bb2010-02-08 20:30:44 -03001669 dib7000p_write_word(dpst, 1285, dpst->i2c_addr << 2);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001670
1671 /* deactivate div - it was just for i2c-enumeration */
Randy Dunlap30d81bb2010-02-08 20:30:44 -03001672 dib7000p_set_output_mode(dpst, OUTMODE_HIGH_Z);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001673 }
1674
Randy Dunlap30d81bb2010-02-08 20:30:44 -03001675 kfree(dpst);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001676 return 0;
1677}
1678EXPORT_SYMBOL(dib7000p_i2c_enumeration);
1679
Olivier Grenie713d54a2011-01-04 04:54:31 -03001680static const s32 lut_1000ln_mant[] = {
1681 6908, 6956, 7003, 7047, 7090, 7131, 7170, 7208, 7244, 7279, 7313, 7346, 7377, 7408, 7438, 7467, 7495, 7523, 7549, 7575, 7600
1682};
1683
1684static s32 dib7000p_get_adc_power(struct dvb_frontend *fe)
1685{
1686 struct dib7000p_state *state = fe->demodulator_priv;
1687 u32 tmp_val = 0, exp = 0, mant = 0;
1688 s32 pow_i;
1689 u16 buf[2];
1690 u8 ix = 0;
1691
1692 buf[0] = dib7000p_read_word(state, 0x184);
1693 buf[1] = dib7000p_read_word(state, 0x185);
1694 pow_i = (buf[0] << 16) | buf[1];
1695 dprintk("raw pow_i = %d", pow_i);
1696
1697 tmp_val = pow_i;
1698 while (tmp_val >>= 1)
1699 exp++;
1700
1701 mant = (pow_i * 1000 / (1 << exp));
1702 dprintk(" mant = %d exp = %d", mant / 1000, exp);
1703
1704 ix = (u8) ((mant - 1000) / 100); /* index of the LUT */
1705 dprintk(" ix = %d", ix);
1706
1707 pow_i = (lut_1000ln_mant[ix] + 693 * (exp - 20) - 6908);
1708 pow_i = (pow_i << 8) / 1000;
1709 dprintk(" pow_i = %d", pow_i);
1710
1711 return pow_i;
1712}
1713
1714static int map_addr_to_serpar_number(struct i2c_msg *msg)
1715{
1716 if ((msg->buf[0] <= 15))
1717 msg->buf[0] -= 1;
1718 else if (msg->buf[0] == 17)
1719 msg->buf[0] = 15;
1720 else if (msg->buf[0] == 16)
1721 msg->buf[0] = 17;
1722 else if (msg->buf[0] == 19)
1723 msg->buf[0] = 16;
1724 else if (msg->buf[0] >= 21 && msg->buf[0] <= 25)
1725 msg->buf[0] -= 3;
1726 else if (msg->buf[0] == 28)
1727 msg->buf[0] = 23;
1728 else {
1729 return -EINVAL;
1730 }
1731 return 0;
1732}
1733
1734static int w7090p_tuner_write_serpar(struct i2c_adapter *i2c_adap, struct i2c_msg msg[], int num)
1735{
1736 struct dib7000p_state *state = i2c_get_adapdata(i2c_adap);
1737 u8 n_overflow = 1;
1738 u16 i = 1000;
1739 u16 serpar_num = msg[0].buf[0];
1740
1741 while (n_overflow == 1 && i) {
1742 n_overflow = (dib7000p_read_word(state, 1984) >> 1) & 0x1;
1743 i--;
1744 if (i == 0)
1745 dprintk("Tuner ITF: write busy (overflow)");
1746 }
1747 dib7000p_write_word(state, 1985, (1 << 6) | (serpar_num & 0x3f));
1748 dib7000p_write_word(state, 1986, (msg[0].buf[1] << 8) | msg[0].buf[2]);
1749
1750 return num;
1751}
1752
1753static int w7090p_tuner_read_serpar(struct i2c_adapter *i2c_adap, struct i2c_msg msg[], int num)
1754{
1755 struct dib7000p_state *state = i2c_get_adapdata(i2c_adap);
1756 u8 n_overflow = 1, n_empty = 1;
1757 u16 i = 1000;
1758 u16 serpar_num = msg[0].buf[0];
1759 u16 read_word;
1760
1761 while (n_overflow == 1 && i) {
1762 n_overflow = (dib7000p_read_word(state, 1984) >> 1) & 0x1;
1763 i--;
1764 if (i == 0)
1765 dprintk("TunerITF: read busy (overflow)");
1766 }
1767 dib7000p_write_word(state, 1985, (0 << 6) | (serpar_num & 0x3f));
1768
1769 i = 1000;
1770 while (n_empty == 1 && i) {
1771 n_empty = dib7000p_read_word(state, 1984) & 0x1;
1772 i--;
1773 if (i == 0)
1774 dprintk("TunerITF: read busy (empty)");
1775 }
1776 read_word = dib7000p_read_word(state, 1987);
1777 msg[1].buf[0] = (read_word >> 8) & 0xff;
1778 msg[1].buf[1] = (read_word) & 0xff;
1779
1780 return num;
1781}
1782
1783static int w7090p_tuner_rw_serpar(struct i2c_adapter *i2c_adap, struct i2c_msg msg[], int num)
1784{
1785 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... */
1786 if (num == 1) { /* write */
1787 return w7090p_tuner_write_serpar(i2c_adap, msg, 1);
1788 } else { /* read */
1789 return w7090p_tuner_read_serpar(i2c_adap, msg, 2);
1790 }
1791 }
1792 return num;
1793}
1794
1795int dib7090p_rw_on_apb(struct i2c_adapter *i2c_adap, struct i2c_msg msg[], int num, u16 apb_address)
1796{
1797 struct dib7000p_state *state = i2c_get_adapdata(i2c_adap);
1798 u16 word;
1799
1800 if (num == 1) { /* write */
1801 dib7000p_write_word(state, apb_address, ((msg[0].buf[1] << 8) | (msg[0].buf[2])));
1802 } else {
1803 word = dib7000p_read_word(state, apb_address);
1804 msg[1].buf[0] = (word >> 8) & 0xff;
1805 msg[1].buf[1] = (word) & 0xff;
1806 }
1807
1808 return num;
1809}
1810
1811static int dib7090_tuner_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg msg[], int num)
1812{
1813 struct dib7000p_state *state = i2c_get_adapdata(i2c_adap);
1814
1815 u16 apb_address = 0, word;
1816 int i = 0;
1817 switch (msg[0].buf[0]) {
1818 case 0x12:
1819 apb_address = 1920;
1820 break;
1821 case 0x14:
1822 apb_address = 1921;
1823 break;
1824 case 0x24:
1825 apb_address = 1922;
1826 break;
1827 case 0x1a:
1828 apb_address = 1923;
1829 break;
1830 case 0x22:
1831 apb_address = 1924;
1832 break;
1833 case 0x33:
1834 apb_address = 1926;
1835 break;
1836 case 0x34:
1837 apb_address = 1927;
1838 break;
1839 case 0x35:
1840 apb_address = 1928;
1841 break;
1842 case 0x36:
1843 apb_address = 1929;
1844 break;
1845 case 0x37:
1846 apb_address = 1930;
1847 break;
1848 case 0x38:
1849 apb_address = 1931;
1850 break;
1851 case 0x39:
1852 apb_address = 1932;
1853 break;
1854 case 0x2a:
1855 apb_address = 1935;
1856 break;
1857 case 0x2b:
1858 apb_address = 1936;
1859 break;
1860 case 0x2c:
1861 apb_address = 1937;
1862 break;
1863 case 0x2d:
1864 apb_address = 1938;
1865 break;
1866 case 0x2e:
1867 apb_address = 1939;
1868 break;
1869 case 0x2f:
1870 apb_address = 1940;
1871 break;
1872 case 0x30:
1873 apb_address = 1941;
1874 break;
1875 case 0x31:
1876 apb_address = 1942;
1877 break;
1878 case 0x32:
1879 apb_address = 1943;
1880 break;
1881 case 0x3e:
1882 apb_address = 1944;
1883 break;
1884 case 0x3f:
1885 apb_address = 1945;
1886 break;
1887 case 0x40:
1888 apb_address = 1948;
1889 break;
1890 case 0x25:
1891 apb_address = 914;
1892 break;
1893 case 0x26:
1894 apb_address = 915;
1895 break;
1896 case 0x27:
1897 apb_address = 916;
1898 break;
1899 case 0x28:
1900 apb_address = 917;
1901 break;
1902 case 0x1d:
1903 i = ((dib7000p_read_word(state, 72) >> 12) & 0x3);
1904 word = dib7000p_read_word(state, 384 + i);
1905 msg[1].buf[0] = (word >> 8) & 0xff;
1906 msg[1].buf[1] = (word) & 0xff;
1907 return num;
1908 case 0x1f:
1909 if (num == 1) { /* write */
1910 word = (u16) ((msg[0].buf[1] << 8) | msg[0].buf[2]);
1911 word &= 0x3;
1912 word = (dib7000p_read_word(state, 72) & ~(3 << 12)) | (word << 12); //Mask bit 12,13
1913 dib7000p_write_word(state, 72, word); /* Set the proper input */
1914 return num;
1915 }
1916 }
1917
1918 if (apb_address != 0) /* R/W acces via APB */
1919 return dib7090p_rw_on_apb(i2c_adap, msg, num, apb_address);
1920 else /* R/W access via SERPAR */
1921 return w7090p_tuner_rw_serpar(i2c_adap, msg, num);
1922
1923 return 0;
1924}
1925
1926static u32 dib7000p_i2c_func(struct i2c_adapter *adapter)
1927{
1928 return I2C_FUNC_I2C;
1929}
1930
1931static struct i2c_algorithm dib7090_tuner_xfer_algo = {
1932 .master_xfer = dib7090_tuner_xfer,
1933 .functionality = dib7000p_i2c_func,
1934};
1935
1936struct i2c_adapter *dib7090_get_i2c_tuner(struct dvb_frontend *fe)
1937{
1938 struct dib7000p_state *st = fe->demodulator_priv;
1939 return &st->dib7090_tuner_adap;
1940}
1941EXPORT_SYMBOL(dib7090_get_i2c_tuner);
1942
1943static int dib7090_host_bus_drive(struct dib7000p_state *state, u8 drive)
1944{
1945 u16 reg;
1946
1947 /* drive host bus 2, 3, 4 */
1948 reg = dib7000p_read_word(state, 1798) & ~((0x7) | (0x7 << 6) | (0x7 << 12));
1949 reg |= (drive << 12) | (drive << 6) | drive;
1950 dib7000p_write_word(state, 1798, reg);
1951
1952 /* drive host bus 5,6 */
1953 reg = dib7000p_read_word(state, 1799) & ~((0x7 << 2) | (0x7 << 8));
1954 reg |= (drive << 8) | (drive << 2);
1955 dib7000p_write_word(state, 1799, reg);
1956
1957 /* drive host bus 7, 8, 9 */
1958 reg = dib7000p_read_word(state, 1800) & ~((0x7) | (0x7 << 6) | (0x7 << 12));
1959 reg |= (drive << 12) | (drive << 6) | drive;
1960 dib7000p_write_word(state, 1800, reg);
1961
1962 /* drive host bus 10, 11 */
1963 reg = dib7000p_read_word(state, 1801) & ~((0x7 << 2) | (0x7 << 8));
1964 reg |= (drive << 8) | (drive << 2);
1965 dib7000p_write_word(state, 1801, reg);
1966
1967 /* drive host bus 12, 13, 14 */
1968 reg = dib7000p_read_word(state, 1802) & ~((0x7) | (0x7 << 6) | (0x7 << 12));
1969 reg |= (drive << 12) | (drive << 6) | drive;
1970 dib7000p_write_word(state, 1802, reg);
1971
1972 return 0;
1973}
1974
1975static u32 dib7090_calcSyncFreq(u32 P_Kin, u32 P_Kout, u32 insertExtSynchro, u32 syncSize)
1976{
1977 u32 quantif = 3;
1978 u32 nom = (insertExtSynchro * P_Kin + syncSize);
1979 u32 denom = P_Kout;
1980 u32 syncFreq = ((nom << quantif) / denom);
1981
1982 if ((syncFreq & ((1 << quantif) - 1)) != 0)
1983 syncFreq = (syncFreq >> quantif) + 1;
1984 else
1985 syncFreq = (syncFreq >> quantif);
1986
1987 if (syncFreq != 0)
1988 syncFreq = syncFreq - 1;
1989
1990 return syncFreq;
1991}
1992
1993static int dib7090_cfg_DibTx(struct dib7000p_state *state, u32 P_Kin, u32 P_Kout, u32 insertExtSynchro, u32 synchroMode, u32 syncWord, u32 syncSize)
1994{
1995 u8 index_buf;
1996 u16 rx_copy_buf[22];
1997
1998 dprintk("Configure DibStream Tx");
1999 for (index_buf = 0; index_buf<22; index_buf++)
2000 rx_copy_buf[index_buf] = dib7000p_read_word(state, 1536+index_buf);
2001
2002 dib7000p_write_word(state, 1615, 1);
2003 dib7000p_write_word(state, 1603, P_Kin);
2004 dib7000p_write_word(state, 1605, P_Kout);
2005 dib7000p_write_word(state, 1606, insertExtSynchro);
2006 dib7000p_write_word(state, 1608, synchroMode);
2007 dib7000p_write_word(state, 1609, (syncWord >> 16) & 0xffff);
2008 dib7000p_write_word(state, 1610, syncWord & 0xffff);
2009 dib7000p_write_word(state, 1612, syncSize);
2010 dib7000p_write_word(state, 1615, 0);
2011
2012 for (index_buf = 0; index_buf<22; index_buf++)
2013 dib7000p_write_word(state, 1536+index_buf, rx_copy_buf[index_buf]);
2014
2015 return 0;
2016}
2017
2018static int dib7090_cfg_DibRx(struct dib7000p_state *state, u32 P_Kin, u32 P_Kout, u32 synchroMode, u32 insertExtSynchro, u32 syncWord, u32 syncSize,
2019 u32 dataOutRate)
2020{
2021 u32 syncFreq;
2022
2023 dprintk("Configure DibStream Rx");
2024 if ((P_Kin != 0) && (P_Kout != 0))
2025 {
2026 syncFreq = dib7090_calcSyncFreq(P_Kin, P_Kout, insertExtSynchro, syncSize);
2027 dib7000p_write_word(state, 1542, syncFreq);
2028 }
2029 dib7000p_write_word(state, 1554, 1);
2030 dib7000p_write_word(state, 1536, P_Kin);
2031 dib7000p_write_word(state, 1537, P_Kout);
2032 dib7000p_write_word(state, 1539, synchroMode);
2033 dib7000p_write_word(state, 1540, (syncWord >> 16) & 0xffff);
2034 dib7000p_write_word(state, 1541, syncWord & 0xffff);
2035 dib7000p_write_word(state, 1543, syncSize);
2036 dib7000p_write_word(state, 1544, dataOutRate);
2037 dib7000p_write_word(state, 1554, 0);
2038
2039 return 0;
2040}
2041
2042static int dib7090_enDivOnHostBus(struct dib7000p_state *state)
2043{
2044 u16 reg;
2045
2046 dprintk("Enable Diversity on host bus");
2047 reg = (1 << 8) | (1 << 5); // P_enDivOutOnDibTx = 1 ; P_enDibTxOnHostBus = 1
2048 dib7000p_write_word(state, 1288, reg);
2049
2050 return dib7090_cfg_DibTx(state, 5, 5, 0, 0, 0, 0);
2051}
2052
2053static int dib7090_enAdcOnHostBus(struct dib7000p_state *state)
2054{
2055 u16 reg;
2056
2057 dprintk("Enable ADC on host bus");
2058 reg = (1 << 7) | (1 << 5); //P_enAdcOnDibTx = 1 ; P_enDibTxOnHostBus = 1
2059 dib7000p_write_word(state, 1288, reg);
2060
2061 return dib7090_cfg_DibTx(state, 20, 5, 10, 0, 0, 0);
2062}
2063
2064static int dib7090_enMpegOnHostBus(struct dib7000p_state *state)
2065{
2066 u16 reg;
2067
2068 dprintk("Enable Mpeg on host bus");
2069 reg = (1 << 9) | (1 << 5); //P_enMpegOnDibTx = 1 ; P_enDibTxOnHostBus = 1
2070 dib7000p_write_word(state, 1288, reg);
2071
2072 return dib7090_cfg_DibTx(state, 8, 5, 0, 0, 0, 0);
2073}
2074
2075static int dib7090_enMpegInput(struct dib7000p_state *state)
2076{
2077 dprintk("Enable Mpeg input");
2078 return dib7090_cfg_DibRx(state, 8, 5, 0, 0, 0, 8, 0); /*outputRate = 8 */
2079}
2080
2081static int dib7090_enMpegMux(struct dib7000p_state *state, u16 pulseWidth, u16 enSerialMode, u16 enSerialClkDiv2)
2082{
2083 u16 reg = (1 << 7) | ((pulseWidth & 0x1f) << 2) | ((enSerialMode & 0x1) << 1) | (enSerialClkDiv2 & 0x1);
2084
2085 dprintk("Enable Mpeg mux");
2086 dib7000p_write_word(state, 1287, reg);
2087
2088 reg &= ~(1 << 7); // P_restart_mpegMux = 0
2089 dib7000p_write_word(state, 1287, reg);
2090
2091 reg = (1 << 4); //P_enMpegMuxOnHostBus = 1
2092 dib7000p_write_word(state, 1288, reg);
2093
2094 return 0;
2095}
2096
2097static int dib7090_disableMpegMux(struct dib7000p_state *state)
2098{
2099 u16 reg;
2100
2101 dprintk("Disable Mpeg mux");
2102 dib7000p_write_word(state, 1288, 0); //P_enMpegMuxOnHostBus = 0
2103
2104 reg = dib7000p_read_word(state, 1287);
2105 reg &= ~(1 << 7); // P_restart_mpegMux = 0
2106 dib7000p_write_word(state, 1287, reg);
2107
2108 return 0;
2109}
2110
2111static int dib7090_set_input_mode(struct dvb_frontend *fe, int mode)
2112{
2113 struct dib7000p_state *state = fe->demodulator_priv;
2114
2115 switch(mode) {
2116 case INPUT_MODE_DIVERSITY:
2117 dprintk("Enable diversity INPUT");
2118 dib7090_cfg_DibRx(state, 5,5,0,0,0,0,0);
2119 break;
2120 case INPUT_MODE_MPEG:
2121 dprintk("Enable Mpeg INPUT");
2122 dib7090_cfg_DibRx(state, 8,5,0,0,0,8,0); /*outputRate = 8 */
2123 break;
2124 case INPUT_MODE_OFF:
2125 default:
2126 dprintk("Disable INPUT");
2127 dib7090_cfg_DibRx(state, 0,0,0,0,0,0,0);
2128 break;
2129 }
2130 return 0;
2131}
2132
2133static int dib7090_set_diversity_in(struct dvb_frontend *fe, int onoff)
2134{
2135 switch (onoff) {
2136 case 0: /* only use the internal way - not the diversity input */
2137 dib7090_set_input_mode(fe, INPUT_MODE_MPEG);
2138 break;
2139 case 1: /* both ways */
2140 case 2: /* only the diversity input */
2141 dib7090_set_input_mode(fe, INPUT_MODE_DIVERSITY);
2142 break;
2143 }
2144
2145 return 0;
2146}
2147
2148static int dib7090_set_output_mode(struct dvb_frontend *fe, int mode)
2149{
2150 struct dib7000p_state *state = fe->demodulator_priv;
2151
2152 u16 outreg, smo_mode, fifo_threshold;
2153 u8 prefer_mpeg_mux_use = 1;
2154 int ret = 0;
2155
2156 dib7090_host_bus_drive(state, 1);
2157
2158 fifo_threshold = 1792;
2159 smo_mode = (dib7000p_read_word(state, 235) & 0x0050) | (1 << 1);
2160 outreg = dib7000p_read_word(state, 1286) & ~((1 << 10) | (0x7 << 6) | (1 << 1));
2161
2162 switch (mode) {
2163 case OUTMODE_HIGH_Z:
2164 outreg = 0;
2165 break;
2166
2167 case OUTMODE_MPEG2_SERIAL:
2168 if (prefer_mpeg_mux_use) {
2169 dprintk("Sip 7090P setting output mode TS_SERIAL using Mpeg Mux");
2170 dib7090_enMpegOnHostBus(state);
2171 dib7090_enMpegInput(state);
2172 if (state->cfg.enMpegOutput == 1)
2173 dib7090_enMpegMux(state, 3, 1, 1);
2174
2175 } else { /* Use Smooth block */
2176 dprintk("Sip 7090P setting output mode TS_SERIAL using Smooth bloc");
2177 dib7090_disableMpegMux(state);
2178 dib7000p_write_word(state, 1288, (1 << 6)); //P_enDemOutInterfOnHostBus = 1
2179 outreg |= (2 << 6) | (0 << 1);
2180 }
2181 break;
2182
2183 case OUTMODE_MPEG2_PAR_GATED_CLK:
2184 if (prefer_mpeg_mux_use) {
2185 dprintk("Sip 7090P setting output mode TS_PARALLEL_GATED using Mpeg Mux");
2186 dib7090_enMpegOnHostBus(state);
2187 dib7090_enMpegInput(state);
2188 if (state->cfg.enMpegOutput == 1)
2189 dib7090_enMpegMux(state, 2, 0, 0);
2190 } else { /* Use Smooth block */
2191 dprintk("Sip 7090P setting output mode TS_PARALLEL_GATED using Smooth block");
2192 dib7090_disableMpegMux(state);
2193 dib7000p_write_word(state, 1288, (1 << 6)); //P_enDemOutInterfOnHostBus = 1
2194 outreg |= (0 << 6);
2195 }
2196 break;
2197
2198 case OUTMODE_MPEG2_PAR_CONT_CLK: /* Using Smooth block only */
2199 dprintk("Sip 7090P setting output mode TS_PARALLEL_CONT using Smooth block");
2200 dib7090_disableMpegMux(state);
2201 dib7000p_write_word(state, 1288, (1 << 6)); //P_enDemOutInterfOnHostBus = 1
2202 outreg |= (1 << 6);
2203 break;
2204
2205 case OUTMODE_MPEG2_FIFO: /* Using Smooth block because not supported by new Mpeg Mux bloc */
2206 dprintk("Sip 7090P setting output mode TS_FIFO using Smooth block");
2207 dib7090_disableMpegMux(state);
2208 dib7000p_write_word(state, 1288, (1 << 6)); //P_enDemOutInterfOnHostBus = 1
2209 outreg |= (5 << 6);
2210 smo_mode |= (3 << 1);
2211 fifo_threshold = 512;
2212 break;
2213
2214 case OUTMODE_DIVERSITY:
2215 dprintk("Sip 7090P setting output mode MODE_DIVERSITY");
2216 dib7090_disableMpegMux(state);
2217 dib7090_enDivOnHostBus(state);
2218 break;
2219
2220 case OUTMODE_ANALOG_ADC:
2221 dprintk("Sip 7090P setting output mode MODE_ANALOG_ADC");
2222 dib7090_enAdcOnHostBus(state);
2223 break;
2224 }
2225
2226 if (state->cfg.output_mpeg2_in_188_bytes)
2227 smo_mode |= (1 << 5);
2228
2229 ret |= dib7000p_write_word(state, 235, smo_mode);
2230 ret |= dib7000p_write_word(state, 236, fifo_threshold); /* synchronous fread */
2231 ret |= dib7000p_write_word(state, 1286, outreg | (1 << 10)); /* allways set Dout active = 1 !!! */
2232
2233 return ret;
2234}
2235
2236int dib7090_tuner_sleep(struct dvb_frontend *fe, int onoff)
2237{
2238 struct dib7000p_state *state = fe->demodulator_priv;
2239 u16 en_cur_state;
2240
2241 dprintk("sleep dib7090: %d", onoff);
2242
2243 en_cur_state = dib7000p_read_word(state, 1922);
2244
2245 if (en_cur_state > 0xff) { //LNAs and MIX are ON and therefore it is a valid configuration
2246 state->tuner_enable = en_cur_state;
2247 }
2248
2249 if (onoff)
2250 en_cur_state &= 0x00ff; //Mask to be applied
2251 else {
2252 if (state->tuner_enable != 0)
2253 en_cur_state = state->tuner_enable;
2254 }
2255
2256 dib7000p_write_word(state, 1922, en_cur_state);
2257
2258 return 0;
2259}
2260EXPORT_SYMBOL(dib7090_tuner_sleep);
2261
2262int dib7090_agc_restart(struct dvb_frontend *fe, u8 restart)
2263{
2264 dprintk("AGC restart callback: %d", restart);
2265 return 0;
2266}
2267EXPORT_SYMBOL(dib7090_agc_restart);
2268
2269int dib7090_get_adc_power(struct dvb_frontend *fe)
2270{
2271 return dib7000p_get_adc_power(fe);
2272}
2273EXPORT_SYMBOL(dib7090_get_adc_power);
2274
2275int dib7090_slave_reset(struct dvb_frontend *fe)
2276{
2277 struct dib7000p_state *state = fe->demodulator_priv;
2278 u16 reg;
2279
2280 reg = dib7000p_read_word(state, 1794);
2281 dib7000p_write_word(state, 1794, reg | (4 << 12));
2282
2283 dib7000p_write_word(state, 1032, 0xffff);
2284 return 0;
2285}
2286EXPORT_SYMBOL(dib7090_slave_reset);
2287
Patrick Boettchera75763f2006-10-18 08:34:16 -03002288static struct dvb_frontend_ops dib7000p_ops;
Olivier Grenie713d54a2011-01-04 04:54:31 -03002289struct dvb_frontend *dib7000p_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr, struct dib7000p_config *cfg)
Patrick Boettchera75763f2006-10-18 08:34:16 -03002290{
2291 struct dvb_frontend *demod;
2292 struct dib7000p_state *st;
2293 st = kzalloc(sizeof(struct dib7000p_state), GFP_KERNEL);
2294 if (st == NULL)
2295 return NULL;
2296
2297 memcpy(&st->cfg, cfg, sizeof(struct dib7000p_config));
2298 st->i2c_adap = i2c_adap;
2299 st->i2c_addr = i2c_addr;
2300 st->gpio_val = cfg->gpio_val;
2301 st->gpio_dir = cfg->gpio_dir;
2302
Steven Totha38d6e32008-04-22 15:37:01 -03002303 /* Ensure the output mode remains at the previous default if it's
2304 * not specifically set by the caller.
2305 */
Olivier Grenie713d54a2011-01-04 04:54:31 -03002306 if ((st->cfg.output_mode != OUTMODE_MPEG2_SERIAL) && (st->cfg.output_mode != OUTMODE_MPEG2_PAR_GATED_CLK))
Steven Totha38d6e32008-04-22 15:37:01 -03002307 st->cfg.output_mode = OUTMODE_MPEG2_FIFO;
2308
Olivier Grenie713d54a2011-01-04 04:54:31 -03002309 demod = &st->demod;
Patrick Boettchera75763f2006-10-18 08:34:16 -03002310 demod->demodulator_priv = st;
2311 memcpy(&st->demod.ops, &dib7000p_ops, sizeof(struct dvb_frontend_ops));
2312
Olivier Grenie713d54a2011-01-04 04:54:31 -03002313 dib7000p_write_word(st, 1287, 0x0003); /* sram lead in, rdy */
Olivier Grenieeac1fe12009-09-23 13:41:27 -03002314
Patrick Boettchera75763f2006-10-18 08:34:16 -03002315 if (dib7000p_identify(st) != 0)
2316 goto error;
2317
Olivier Grenie713d54a2011-01-04 04:54:31 -03002318 st->version = dib7000p_read_word(st, 897);
2319
Martin Samek7646b9d2009-09-30 22:59:09 -03002320 /* FIXME: make sure the dev.parent field is initialized, or else
Olivier Grenie713d54a2011-01-04 04:54:31 -03002321 request_firmware() will hit an OOPS (this should be moved somewhere
2322 more common) */
Martin Samek7646b9d2009-09-30 22:59:09 -03002323
Patrick Boettchera75763f2006-10-18 08:34:16 -03002324 dibx000_init_i2c_master(&st->i2c_master, DIB7000P, st->i2c_adap, st->i2c_addr);
2325
Olivier Grenie713d54a2011-01-04 04:54:31 -03002326 /* init 7090 tuner adapter */
2327 strncpy(st->dib7090_tuner_adap.name, "DiB7090 tuner interface", sizeof(st->dib7090_tuner_adap.name));
2328 st->dib7090_tuner_adap.algo = &dib7090_tuner_xfer_algo;
2329 st->dib7090_tuner_adap.algo_data = NULL;
2330 st->dib7090_tuner_adap.dev.parent = st->i2c_adap->dev.parent;
2331 i2c_set_adapdata(&st->dib7090_tuner_adap, st);
2332 i2c_add_adapter(&st->dib7090_tuner_adap);
2333
Patrick Boettchera75763f2006-10-18 08:34:16 -03002334 dib7000p_demod_reset(st);
2335
Olivier Grenie713d54a2011-01-04 04:54:31 -03002336 if (st->version == SOC7090) {
2337 dib7090_set_output_mode(demod, st->cfg.output_mode);
2338 dib7090_set_diversity_in(demod, 0);
2339 }
2340
Patrick Boettchera75763f2006-10-18 08:34:16 -03002341 return demod;
2342
Olivier Grenie713d54a2011-01-04 04:54:31 -03002343 error:
Patrick Boettchera75763f2006-10-18 08:34:16 -03002344 kfree(st);
2345 return NULL;
2346}
2347EXPORT_SYMBOL(dib7000p_attach);
2348
2349static struct dvb_frontend_ops dib7000p_ops = {
2350 .info = {
Olivier Grenie713d54a2011-01-04 04:54:31 -03002351 .name = "DiBcom 7000PC",
2352 .type = FE_OFDM,
2353 .frequency_min = 44250000,
2354 .frequency_max = 867250000,
2355 .frequency_stepsize = 62500,
2356 .caps = FE_CAN_INVERSION_AUTO |
2357 FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
2358 FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
2359 FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO |
2360 FE_CAN_TRANSMISSION_MODE_AUTO | FE_CAN_GUARD_INTERVAL_AUTO | FE_CAN_RECOVER | FE_CAN_HIERARCHY_AUTO,
2361 },
Patrick Boettchera75763f2006-10-18 08:34:16 -03002362
Olivier Grenie713d54a2011-01-04 04:54:31 -03002363 .release = dib7000p_release,
Patrick Boettchera75763f2006-10-18 08:34:16 -03002364
Olivier Grenie713d54a2011-01-04 04:54:31 -03002365 .init = dib7000p_wakeup,
2366 .sleep = dib7000p_sleep,
Patrick Boettchera75763f2006-10-18 08:34:16 -03002367
Olivier Grenie713d54a2011-01-04 04:54:31 -03002368 .set_frontend = dib7000p_set_frontend,
2369 .get_tune_settings = dib7000p_fe_get_tune_settings,
2370 .get_frontend = dib7000p_get_frontend,
Patrick Boettchera75763f2006-10-18 08:34:16 -03002371
Olivier Grenie713d54a2011-01-04 04:54:31 -03002372 .read_status = dib7000p_read_status,
2373 .read_ber = dib7000p_read_ber,
Patrick Boettchera75763f2006-10-18 08:34:16 -03002374 .read_signal_strength = dib7000p_read_signal_strength,
Olivier Grenie713d54a2011-01-04 04:54:31 -03002375 .read_snr = dib7000p_read_snr,
2376 .read_ucblocks = dib7000p_read_unc_blocks,
Patrick Boettchera75763f2006-10-18 08:34:16 -03002377};
2378
Olivier Grenie713d54a2011-01-04 04:54:31 -03002379MODULE_AUTHOR("Olivier Grenie <ogrenie@dibcom.fr>");
Patrick Boettchera75763f2006-10-18 08:34:16 -03002380MODULE_AUTHOR("Patrick Boettcher <pboettcher@dibcom.fr>");
2381MODULE_DESCRIPTION("Driver for the DiBcom 7000PC COFDM demodulator");
2382MODULE_LICENSE("GPL");