blob: b3ca3e2f8d537b32bdc92e2e36018f3bc50bbd78 [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 Grenieb4d6046e2011-01-04 13:08:14 -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 Grenieb4d6046e2011-01-04 13:08:14 -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 Grenieb4d6046e2011-01-04 13:08:14 -0300132 case OUTMODE_MPEG2_PAR_GATED_CLK:
Olivier Grenie713d54a2011-01-04 04:54:31 -0300133 outreg = (1 << 10); /* 0x0400 */
134 break;
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300135 case OUTMODE_MPEG2_PAR_CONT_CLK:
Olivier Grenie713d54a2011-01-04 04:54:31 -0300136 outreg = (1 << 10) | (1 << 6); /* 0x0440 */
137 break;
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300138 case OUTMODE_MPEG2_SERIAL:
Olivier Grenie713d54a2011-01-04 04:54:31 -0300139 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;
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300147 case OUTMODE_MPEG2_FIFO:
Olivier Grenie713d54a2011-01-04 04:54:31 -0300148 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;
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300155 case OUTMODE_HIGH_Z:
Olivier Grenie713d54a2011-01-04 04:54:31 -0300156 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 Grenieb4d6046e2011-01-04 13:08:14 -0300287 case DIBX000_ADC_OFF:
Olivier Grenie713d54a2011-01-04 04:54:31 -0300288 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 Boettchera75763f2006-10-18 08:34:16 -0300339 dib7000p_write_word(state, 73, (0 << 1) | (0 << 0));
Olivier Grenie713d54a2011-01-04 04:54:31 -0300340
341 if (state->version == SOC7090)
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300342 dib7000p_write_word(state, 74, 2048);
Olivier Grenie713d54a2011-01-04 04:54:31 -0300343 else
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300344 dib7000p_write_word(state, 74, 776);
Patrick Boettchera75763f2006-10-18 08:34:16 -0300345
346 /* do the calibration */
347 dib7000p_write_word(state, 73, (1 << 0));
348 dib7000p_write_word(state, 73, (0 << 0));
349
350 msleep(1);
351
352 return 0;
353}
354
Patrick Boettcher01373a52007-07-30 12:49:04 -0300355int dib7000p_set_wbd_ref(struct dvb_frontend *demod, u16 value)
356{
357 struct dib7000p_state *state = demod->demodulator_priv;
358 if (value > 4095)
359 value = 4095;
360 state->wbd_ref = value;
361 return dib7000p_write_word(state, 105, (dib7000p_read_word(state, 105) & 0xf000) | value);
362}
Patrick Boettcher01373a52007-07-30 12:49:04 -0300363EXPORT_SYMBOL(dib7000p_set_wbd_ref);
Olivier Grenie713d54a2011-01-04 04:54:31 -0300364
Patrick Boettchera75763f2006-10-18 08:34:16 -0300365static void dib7000p_reset_pll(struct dib7000p_state *state)
366{
367 struct dibx000_bandwidth_config *bw = &state->cfg.bw[0];
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300368 u16 clk_cfg0;
Patrick Boettchera75763f2006-10-18 08:34:16 -0300369
Olivier Grenie713d54a2011-01-04 04:54:31 -0300370 if (state->version == SOC7090) {
371 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 -0300372
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300373 while (((dib7000p_read_word(state, 1856) >> 15) & 0x1) != 1)
374 ;
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300375
Olivier Grenie713d54a2011-01-04 04:54:31 -0300376 dib7000p_write_word(state, 1857, dib7000p_read_word(state, 1857) | (!bw->pll_bypass << 15));
377 } else {
378 /* force PLL bypass */
379 clk_cfg0 = (1 << 15) | ((bw->pll_ratio & 0x3f) << 9) |
380 (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 -0300381
Olivier Grenie713d54a2011-01-04 04:54:31 -0300382 dib7000p_write_word(state, 900, clk_cfg0);
383
384 /* P_pll_cfg */
385 dib7000p_write_word(state, 903, (bw->pll_prediv << 5) | (((bw->pll_ratio >> 6) & 0x3) << 3) | (bw->pll_range << 1) | bw->pll_reset);
386 clk_cfg0 = (bw->pll_bypass << 15) | (clk_cfg0 & 0x7fff);
387 dib7000p_write_word(state, 900, clk_cfg0);
388 }
389
390 dib7000p_write_word(state, 18, (u16) (((bw->internal * 1000) >> 16) & 0xffff));
391 dib7000p_write_word(state, 19, (u16) ((bw->internal * 1000) & 0xffff));
392 dib7000p_write_word(state, 21, (u16) ((bw->ifreq >> 16) & 0xffff));
393 dib7000p_write_word(state, 22, (u16) ((bw->ifreq) & 0xffff));
Patrick Boettchera75763f2006-10-18 08:34:16 -0300394
395 dib7000p_write_word(state, 72, bw->sad_cfg);
396}
397
Olivier Grenie713d54a2011-01-04 04:54:31 -0300398static u32 dib7000p_get_internal_freq(struct dib7000p_state *state)
399{
400 u32 internal = (u32) dib7000p_read_word(state, 18) << 16;
401 internal |= (u32) dib7000p_read_word(state, 19);
402 internal /= 1000;
403
404 return internal;
405}
406
407int dib7000p_update_pll(struct dvb_frontend *fe, struct dibx000_bandwidth_config *bw)
408{
409 struct dib7000p_state *state = fe->demodulator_priv;
410 u16 reg_1857, reg_1856 = dib7000p_read_word(state, 1856);
411 u8 loopdiv, prediv;
412 u32 internal, xtal;
413
414 /* get back old values */
415 prediv = reg_1856 & 0x3f;
416 loopdiv = (reg_1856 >> 6) & 0x3f;
417
418 if ((bw != NULL) && (bw->pll_prediv != prediv || bw->pll_ratio != loopdiv)) {
419 dprintk("Updating pll (prediv: old = %d new = %d ; loopdiv : old = %d new = %d)", prediv, bw->pll_prediv, loopdiv, bw->pll_ratio);
420 reg_1856 &= 0xf000;
421 reg_1857 = dib7000p_read_word(state, 1857);
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300422 dib7000p_write_word(state, 1857, reg_1857 & ~(1 << 15));
Olivier Grenie713d54a2011-01-04 04:54:31 -0300423
424 dib7000p_write_word(state, 1856, reg_1856 | ((bw->pll_ratio & 0x3f) << 6) | (bw->pll_prediv & 0x3f));
425
426 /* write new system clk into P_sec_len */
427 internal = dib7000p_get_internal_freq(state);
428 xtal = (internal / loopdiv) * prediv;
429 internal = 1000 * (xtal / bw->pll_prediv) * bw->pll_ratio; /* new internal */
430 dib7000p_write_word(state, 18, (u16) ((internal >> 16) & 0xffff));
431 dib7000p_write_word(state, 19, (u16) (internal & 0xffff));
432
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300433 dib7000p_write_word(state, 1857, reg_1857 | (1 << 15));
Olivier Grenie713d54a2011-01-04 04:54:31 -0300434
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300435 while (((dib7000p_read_word(state, 1856) >> 15) & 0x1) != 1)
Olivier Grenie713d54a2011-01-04 04:54:31 -0300436 dprintk("Waiting for PLL to lock");
Olivier Grenie713d54a2011-01-04 04:54:31 -0300437
438 return 0;
439 }
440 return -EIO;
441}
442EXPORT_SYMBOL(dib7000p_update_pll);
443
Patrick Boettchera75763f2006-10-18 08:34:16 -0300444static int dib7000p_reset_gpio(struct dib7000p_state *st)
445{
446 /* reset the GPIOs */
Olivier Grenie713d54a2011-01-04 04:54:31 -0300447 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 -0300448
449 dib7000p_write_word(st, 1029, st->gpio_dir);
450 dib7000p_write_word(st, 1030, st->gpio_val);
451
452 /* TODO 1031 is P_gpio_od */
453
454 dib7000p_write_word(st, 1032, st->cfg.gpio_pwm_pos);
455
456 dib7000p_write_word(st, 1037, st->cfg.pwm_freq_div);
457 return 0;
458}
459
Patrick Boettcher01373a52007-07-30 12:49:04 -0300460static int dib7000p_cfg_gpio(struct dib7000p_state *st, u8 num, u8 dir, u8 val)
461{
462 st->gpio_dir = dib7000p_read_word(st, 1029);
Olivier Grenie713d54a2011-01-04 04:54:31 -0300463 st->gpio_dir &= ~(1 << num); /* reset the direction bit */
464 st->gpio_dir |= (dir & 0x1) << num; /* set the new direction */
Patrick Boettcher01373a52007-07-30 12:49:04 -0300465 dib7000p_write_word(st, 1029, st->gpio_dir);
466
467 st->gpio_val = dib7000p_read_word(st, 1030);
Olivier Grenie713d54a2011-01-04 04:54:31 -0300468 st->gpio_val &= ~(1 << num); /* reset the direction bit */
469 st->gpio_val |= (val & 0x01) << num; /* set the new value */
Patrick Boettcher01373a52007-07-30 12:49:04 -0300470 dib7000p_write_word(st, 1030, st->gpio_val);
471
472 return 0;
473}
474
475int dib7000p_set_gpio(struct dvb_frontend *demod, u8 num, u8 dir, u8 val)
476{
477 struct dib7000p_state *state = demod->demodulator_priv;
478 return dib7000p_cfg_gpio(state, num, dir, val);
479}
Patrick Boettcher01373a52007-07-30 12:49:04 -0300480EXPORT_SYMBOL(dib7000p_set_gpio);
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300481
Olivier Grenie713d54a2011-01-04 04:54:31 -0300482static u16 dib7000p_defaults[] = {
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300483 // auto search configuration
484 3, 2,
Olivier Grenie713d54a2011-01-04 04:54:31 -0300485 0x0004,
486 0x1000,
487 0x0814, /* Equal Lock */
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300488
489 12, 6,
Olivier Grenie713d54a2011-01-04 04:54:31 -0300490 0x001b,
491 0x7740,
492 0x005b,
493 0x8d80,
494 0x01c9,
495 0xc380,
496 0x0000,
497 0x0080,
498 0x0000,
499 0x0090,
500 0x0001,
501 0xd4c0,
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300502
503 1, 26,
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300504 0x6680,
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300505
506 /* set ADC level to -16 */
507 11, 79,
Olivier Grenie713d54a2011-01-04 04:54:31 -0300508 (1 << 13) - 825 - 117,
509 (1 << 13) - 837 - 117,
510 (1 << 13) - 811 - 117,
511 (1 << 13) - 766 - 117,
512 (1 << 13) - 737 - 117,
513 (1 << 13) - 693 - 117,
514 (1 << 13) - 648 - 117,
515 (1 << 13) - 619 - 117,
516 (1 << 13) - 575 - 117,
517 (1 << 13) - 531 - 117,
518 (1 << 13) - 501 - 117,
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300519
520 1, 142,
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300521 0x0410,
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300522
523 /* disable power smoothing */
524 8, 145,
Olivier Grenie713d54a2011-01-04 04:54:31 -0300525 0,
526 0,
527 0,
528 0,
529 0,
530 0,
531 0,
532 0,
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300533
534 1, 154,
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300535 1 << 13,
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300536
537 1, 168,
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300538 0x0ccd,
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300539
540 1, 183,
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300541 0x200f,
Olivier Grenie713d54a2011-01-04 04:54:31 -0300542
543 1, 212,
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300544 0x169,
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300545
546 5, 187,
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300547 0x023d,
548 0x00a4,
549 0x00a4,
550 0x7ff0,
551 0x3ccc,
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300552
553 1, 198,
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300554 0x800,
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300555
556 1, 222,
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300557 0x0010,
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300558
559 1, 235,
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300560 0x0062,
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300561
562 2, 901,
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300563 0x0006,
564 (3 << 10) | (1 << 6),
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300565
566 1, 905,
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300567 0x2c8e,
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300568
569 0,
570};
571
Patrick Boettchera75763f2006-10-18 08:34:16 -0300572static int dib7000p_demod_reset(struct dib7000p_state *state)
573{
574 dib7000p_set_power_mode(state, DIB7000P_POWER_ALL);
575
Olivier Grenie713d54a2011-01-04 04:54:31 -0300576 if (state->version == SOC7090)
577 dibx000_reset_i2c_master(&state->i2c_master);
578
Patrick Boettchera75763f2006-10-18 08:34:16 -0300579 dib7000p_set_adc_state(state, DIBX000_VBG_ENABLE);
580
581 /* restart all parts */
Olivier Grenie713d54a2011-01-04 04:54:31 -0300582 dib7000p_write_word(state, 770, 0xffff);
583 dib7000p_write_word(state, 771, 0xffff);
584 dib7000p_write_word(state, 772, 0x001f);
585 dib7000p_write_word(state, 898, 0x0003);
586 dib7000p_write_word(state, 1280, 0x001f - ((1 << 4) | (1 << 3)));
Patrick Boettchera75763f2006-10-18 08:34:16 -0300587
Olivier Grenie713d54a2011-01-04 04:54:31 -0300588 dib7000p_write_word(state, 770, 0);
589 dib7000p_write_word(state, 771, 0);
590 dib7000p_write_word(state, 772, 0);
591 dib7000p_write_word(state, 898, 0);
Patrick Boettchera75763f2006-10-18 08:34:16 -0300592 dib7000p_write_word(state, 1280, 0);
593
594 /* default */
595 dib7000p_reset_pll(state);
596
597 if (dib7000p_reset_gpio(state) != 0)
Olivier Grenie713d54a2011-01-04 04:54:31 -0300598 dprintk("GPIO reset was not successful.");
Patrick Boettchera75763f2006-10-18 08:34:16 -0300599
Olivier Grenie713d54a2011-01-04 04:54:31 -0300600 if (state->version == SOC7090) {
601 dib7000p_write_word(state, 899, 0);
602
603 /* impulse noise */
604 dib7000p_write_word(state, 42, (1<<5) | 3); /* P_iqc_thsat_ipc = 1 ; P_iqc_win2 = 3 */
605 dib7000p_write_word(state, 43, 0x2d4); /*-300 fag P_iqc_dect_min = -280 */
606 dib7000p_write_word(state, 44, 300); /* 300 fag P_iqc_dect_min = +280 */
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300607 dib7000p_write_word(state, 273, (1<<6) | 30);
Olivier Grenie713d54a2011-01-04 04:54:31 -0300608 }
Patrick Boettchera75763f2006-10-18 08:34:16 -0300609 if (dib7000p_set_output_mode(state, OUTMODE_HIGH_Z) != 0)
Olivier Grenie713d54a2011-01-04 04:54:31 -0300610 dprintk("OUTPUT_MODE could not be reset.");
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300611
612 dib7000p_set_adc_state(state, DIBX000_SLOW_ADC_ON);
613 dib7000p_sad_calib(state);
614 dib7000p_set_adc_state(state, DIBX000_SLOW_ADC_OFF);
615
Olivier Grenie713d54a2011-01-04 04:54:31 -0300616 /* unforce divstr regardless whether i2c enumeration was done or not */
617 dib7000p_write_word(state, 1285, dib7000p_read_word(state, 1285) & ~(1 << 1));
618
619 dib7000p_set_bandwidth(state, 8000);
620
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300621 if (state->version == SOC7090) {
Olivier Grenie713d54a2011-01-04 04:54:31 -0300622 dib7000p_write_word(state, 36, 0x5755);/* P_iqc_impnc_on =1 & P_iqc_corr_inh = 1 for impulsive noise */
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300623 } else {
Olivier Grenie713d54a2011-01-04 04:54:31 -0300624 if (state->cfg.tuner_is_baseband)
625 dib7000p_write_word(state, 36, 0x0755);
626 else
627 dib7000p_write_word(state, 36, 0x1f55);
628 }
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300629
630 dib7000p_write_tab(state, dib7000p_defaults);
631
Patrick Boettchera75763f2006-10-18 08:34:16 -0300632 dib7000p_set_power_mode(state, DIB7000P_POWER_INTERFACE_ONLY);
633
634 return 0;
635}
636
Patrick Boettchera75763f2006-10-18 08:34:16 -0300637static void dib7000p_pll_clk_cfg(struct dib7000p_state *state)
638{
639 u16 tmp = 0;
640 tmp = dib7000p_read_word(state, 903);
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300641 dib7000p_write_word(state, 903, (tmp | 0x1));
Patrick Boettchera75763f2006-10-18 08:34:16 -0300642 tmp = dib7000p_read_word(state, 900);
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300643 dib7000p_write_word(state, 900, (tmp & 0x7fff) | (1 << 6));
Patrick Boettchera75763f2006-10-18 08:34:16 -0300644}
645
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300646static void dib7000p_restart_agc(struct dib7000p_state *state)
Patrick Boettchera75763f2006-10-18 08:34:16 -0300647{
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300648 // P_restart_iqc & P_restart_agc
649 dib7000p_write_word(state, 770, (1 << 11) | (1 << 9));
650 dib7000p_write_word(state, 770, 0x0000);
Patrick Boettchera75763f2006-10-18 08:34:16 -0300651}
652
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300653static int dib7000p_update_lna(struct dib7000p_state *state)
Patrick Boettchera75763f2006-10-18 08:34:16 -0300654{
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300655 u16 dyn_gain;
656
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300657 if (state->cfg.update_lna) {
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300658 dyn_gain = dib7000p_read_word(state, 394);
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300659 if (state->cfg.update_lna(&state->demod, dyn_gain)) {
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300660 dib7000p_restart_agc(state);
661 return 1;
662 }
663 }
664
665 return 0;
666}
667
668static int dib7000p_set_agc_config(struct dib7000p_state *state, u8 band)
669{
670 struct dibx000_agc_config *agc = NULL;
671 int i;
672 if (state->current_band == band && state->current_agc != NULL)
673 return 0;
674 state->current_band = band;
675
676 for (i = 0; i < state->cfg.agc_config_count; i++)
677 if (state->cfg.agc[i].band_caps & band) {
678 agc = &state->cfg.agc[i];
679 break;
680 }
681
682 if (agc == NULL) {
Olivier Grenie713d54a2011-01-04 04:54:31 -0300683 dprintk("no valid AGC configuration found for band 0x%02x", band);
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300684 return -EINVAL;
685 }
686
687 state->current_agc = agc;
688
689 /* AGC */
Olivier Grenie713d54a2011-01-04 04:54:31 -0300690 dib7000p_write_word(state, 75, agc->setup);
691 dib7000p_write_word(state, 76, agc->inv_gain);
692 dib7000p_write_word(state, 77, agc->time_stabiliz);
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300693 dib7000p_write_word(state, 100, (agc->alpha_level << 12) | agc->thlock);
694
695 // Demod AGC loop configuration
696 dib7000p_write_word(state, 101, (agc->alpha_mant << 5) | agc->alpha_exp);
Olivier Grenie713d54a2011-01-04 04:54:31 -0300697 dib7000p_write_word(state, 102, (agc->beta_mant << 6) | agc->beta_exp);
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300698
699 /* AGC continued */
Olivier Grenie713d54a2011-01-04 04:54:31 -0300700 dprintk("WBD: ref: %d, sel: %d, active: %d, alpha: %d",
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300701 state->wbd_ref != 0 ? state->wbd_ref : agc->wbd_ref, agc->wbd_sel, !agc->perform_agc_softsplit, agc->wbd_sel);
702
703 if (state->wbd_ref != 0)
704 dib7000p_write_word(state, 105, (agc->wbd_inv << 12) | state->wbd_ref);
705 else
706 dib7000p_write_word(state, 105, (agc->wbd_inv << 12) | agc->wbd_ref);
707
708 dib7000p_write_word(state, 106, (agc->wbd_sel << 13) | (agc->wbd_alpha << 9) | (agc->perform_agc_softsplit << 8));
709
Olivier Grenie713d54a2011-01-04 04:54:31 -0300710 dib7000p_write_word(state, 107, agc->agc1_max);
711 dib7000p_write_word(state, 108, agc->agc1_min);
712 dib7000p_write_word(state, 109, agc->agc2_max);
713 dib7000p_write_word(state, 110, agc->agc2_min);
714 dib7000p_write_word(state, 111, (agc->agc1_pt1 << 8) | agc->agc1_pt2);
715 dib7000p_write_word(state, 112, agc->agc1_pt3);
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300716 dib7000p_write_word(state, 113, (agc->agc1_slope1 << 8) | agc->agc1_slope2);
Olivier Grenie713d54a2011-01-04 04:54:31 -0300717 dib7000p_write_word(state, 114, (agc->agc2_pt1 << 8) | agc->agc2_pt2);
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300718 dib7000p_write_word(state, 115, (agc->agc2_slope1 << 8) | agc->agc2_slope2);
719 return 0;
720}
721
Olivier Grenie713d54a2011-01-04 04:54:31 -0300722static void dib7000p_set_dds(struct dib7000p_state *state, s32 offset_khz)
723{
724 u32 internal = dib7000p_get_internal_freq(state);
725 s32 unit_khz_dds_val = 67108864 / (internal); /* 2**26 / Fsampling is the unit 1KHz offset */
726 u32 abs_offset_khz = ABS(offset_khz);
727 u32 dds = state->cfg.bw->ifreq & 0x1ffffff;
728 u8 invert = !!(state->cfg.bw->ifreq & (1 << 25));
729
730 dprintk("setting a frequency offset of %dkHz internal freq = %d invert = %d", offset_khz, internal, invert);
731
732 if (offset_khz < 0)
733 unit_khz_dds_val *= -1;
734
735 /* IF tuner */
736 if (invert)
737 dds -= (abs_offset_khz * unit_khz_dds_val); /* /100 because of /100 on the unit_khz_dds_val line calc for better accuracy */
738 else
739 dds += (abs_offset_khz * unit_khz_dds_val);
740
741 if (abs_offset_khz <= (internal / 2)) { /* Max dds offset is the half of the demod freq */
742 dib7000p_write_word(state, 21, (u16) (((dds >> 16) & 0x1ff) | (0 << 10) | (invert << 9)));
743 dib7000p_write_word(state, 22, (u16) (dds & 0xffff));
744 }
745}
746
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300747static int dib7000p_agc_startup(struct dvb_frontend *demod, struct dvb_frontend_parameters *ch)
748{
749 struct dib7000p_state *state = demod->demodulator_priv;
750 int ret = -1;
751 u8 *agc_state = &state->agc_state;
752 u8 agc_split;
Olivier Grenie713d54a2011-01-04 04:54:31 -0300753 u16 reg;
754 u32 upd_demod_gain_period = 0x1000;
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300755
756 switch (state->agc_state) {
Olivier Grenie713d54a2011-01-04 04:54:31 -0300757 case 0:
Olivier Grenie713d54a2011-01-04 04:54:31 -0300758 dib7000p_set_power_mode(state, DIB7000P_POWER_ALL);
759 if (state->version == SOC7090) {
760 reg = dib7000p_read_word(state, 0x79b) & 0xff00;
761 dib7000p_write_word(state, 0x79a, upd_demod_gain_period & 0xFFFF); /* lsb */
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300762 dib7000p_write_word(state, 0x79b, reg | (1 << 14) | ((upd_demod_gain_period >> 16) & 0xFF));
Olivier Grenie713d54a2011-01-04 04:54:31 -0300763
764 /* enable adc i & q */
765 reg = dib7000p_read_word(state, 0x780);
766 dib7000p_write_word(state, 0x780, (reg | (0x3)) & (~(1 << 7)));
767 } else {
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300768 dib7000p_set_adc_state(state, DIBX000_ADC_ON);
769 dib7000p_pll_clk_cfg(state);
Olivier Grenie713d54a2011-01-04 04:54:31 -0300770 }
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300771
Olivier Grenie713d54a2011-01-04 04:54:31 -0300772 if (dib7000p_set_agc_config(state, BAND_OF_FREQUENCY(ch->frequency / 1000)) != 0)
773 return -1;
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300774
Olivier Grenie713d54a2011-01-04 04:54:31 -0300775 dib7000p_set_dds(state, 0);
776 ret = 7;
777 (*agc_state)++;
778 break;
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300779
Olivier Grenie713d54a2011-01-04 04:54:31 -0300780 case 1:
Olivier Grenie713d54a2011-01-04 04:54:31 -0300781 if (state->cfg.agc_control)
782 state->cfg.agc_control(&state->demod, 1);
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300783
Olivier Grenie713d54a2011-01-04 04:54:31 -0300784 dib7000p_write_word(state, 78, 32768);
785 if (!state->current_agc->perform_agc_softsplit) {
786 /* we are using the wbd - so slow AGC startup */
787 /* force 0 split on WBD and restart AGC */
788 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 -0300789 (*agc_state)++;
790 ret = 5;
Olivier Grenie713d54a2011-01-04 04:54:31 -0300791 } else {
792 /* default AGC startup */
793 (*agc_state) = 4;
794 /* wait AGC rough lock time */
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300795 ret = 7;
Olivier Grenie713d54a2011-01-04 04:54:31 -0300796 }
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300797
Olivier Grenie713d54a2011-01-04 04:54:31 -0300798 dib7000p_restart_agc(state);
799 break;
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300800
Olivier Grenie713d54a2011-01-04 04:54:31 -0300801 case 2: /* fast split search path after 5sec */
802 dib7000p_write_word(state, 75, state->current_agc->setup | (1 << 4)); /* freeze AGC loop */
803 dib7000p_write_word(state, 106, (state->current_agc->wbd_sel << 13) | (2 << 9) | (0 << 8)); /* fast split search 0.25kHz */
804 (*agc_state)++;
805 ret = 14;
806 break;
807
808 case 3: /* split search ended */
809 agc_split = (u8) dib7000p_read_word(state, 396); /* store the split value for the next time */
810 dib7000p_write_word(state, 78, dib7000p_read_word(state, 394)); /* set AGC gain start value */
811
812 dib7000p_write_word(state, 75, state->current_agc->setup); /* std AGC loop */
813 dib7000p_write_word(state, 106, (state->current_agc->wbd_sel << 13) | (state->current_agc->wbd_alpha << 9) | agc_split); /* standard split search */
814
815 dib7000p_restart_agc(state);
816
817 dprintk("SPLIT %p: %hd", demod, agc_split);
818
819 (*agc_state)++;
820 ret = 5;
821 break;
822
823 case 4: /* LNA startup */
Olivier Grenie713d54a2011-01-04 04:54:31 -0300824 ret = 7;
825
826 if (dib7000p_update_lna(state))
Olivier Grenie713d54a2011-01-04 04:54:31 -0300827 ret = 5;
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300828 else
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300829 (*agc_state)++;
Olivier Grenie713d54a2011-01-04 04:54:31 -0300830 break;
831
832 case 5:
833 if (state->cfg.agc_control)
834 state->cfg.agc_control(&state->demod, 0);
835 (*agc_state)++;
836 break;
837 default:
838 break;
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300839 }
840 return ret;
841}
842
843static void dib7000p_update_timf(struct dib7000p_state *state)
844{
845 u32 timf = (dib7000p_read_word(state, 427) << 16) | dib7000p_read_word(state, 428);
846 state->timf = timf * 160 / (state->current_bandwidth / 50);
847 dib7000p_write_word(state, 23, (u16) (timf >> 16));
848 dib7000p_write_word(state, 24, (u16) (timf & 0xffff));
Olivier Grenie713d54a2011-01-04 04:54:31 -0300849 dprintk("updated timf_frequency: %d (default: %d)", state->timf, state->cfg.bw->timf);
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300850
851}
852
Olivier Grenie713d54a2011-01-04 04:54:31 -0300853u32 dib7000p_ctrl_timf(struct dvb_frontend *fe, u8 op, u32 timf)
854{
855 struct dib7000p_state *state = fe->demodulator_priv;
856 switch (op) {
857 case DEMOD_TIMF_SET:
858 state->timf = timf;
859 break;
860 case DEMOD_TIMF_UPDATE:
861 dib7000p_update_timf(state);
862 break;
863 case DEMOD_TIMF_GET:
864 break;
865 }
866 dib7000p_set_bandwidth(state, state->current_bandwidth);
867 return state->timf;
868}
869EXPORT_SYMBOL(dib7000p_ctrl_timf);
870
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300871static void dib7000p_set_channel(struct dib7000p_state *state, struct dvb_frontend_parameters *ch, u8 seq)
872{
873 u16 value, est[4];
874
Olivier Grenie713d54a2011-01-04 04:54:31 -0300875 dib7000p_set_bandwidth(state, BANDWIDTH_TO_KHZ(ch->u.ofdm.bandwidth));
Patrick Boettchera75763f2006-10-18 08:34:16 -0300876
877 /* nfft, guard, qam, alpha */
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300878 value = 0;
879 switch (ch->u.ofdm.transmission_mode) {
Olivier Grenie713d54a2011-01-04 04:54:31 -0300880 case TRANSMISSION_MODE_2K:
881 value |= (0 << 7);
882 break;
883 case TRANSMISSION_MODE_4K:
884 value |= (2 << 7);
885 break;
886 default:
887 case TRANSMISSION_MODE_8K:
888 value |= (1 << 7);
889 break;
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300890 }
891 switch (ch->u.ofdm.guard_interval) {
Olivier Grenie713d54a2011-01-04 04:54:31 -0300892 case GUARD_INTERVAL_1_32:
893 value |= (0 << 5);
894 break;
895 case GUARD_INTERVAL_1_16:
896 value |= (1 << 5);
897 break;
898 case GUARD_INTERVAL_1_4:
899 value |= (3 << 5);
900 break;
901 default:
902 case GUARD_INTERVAL_1_8:
903 value |= (2 << 5);
904 break;
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300905 }
906 switch (ch->u.ofdm.constellation) {
Olivier Grenie713d54a2011-01-04 04:54:31 -0300907 case QPSK:
908 value |= (0 << 3);
909 break;
910 case QAM_16:
911 value |= (1 << 3);
912 break;
913 default:
914 case QAM_64:
915 value |= (2 << 3);
916 break;
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300917 }
918 switch (HIERARCHY_1) {
Olivier Grenie713d54a2011-01-04 04:54:31 -0300919 case HIERARCHY_2:
920 value |= 2;
921 break;
922 case HIERARCHY_4:
923 value |= 4;
924 break;
925 default:
926 case HIERARCHY_1:
927 value |= 1;
928 break;
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300929 }
930 dib7000p_write_word(state, 0, value);
Olivier Grenie713d54a2011-01-04 04:54:31 -0300931 dib7000p_write_word(state, 5, (seq << 4) | 1); /* do not force tps, search list 0 */
Patrick Boettchera75763f2006-10-18 08:34:16 -0300932
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300933 /* P_dintl_native, P_dintlv_inv, P_hrch, P_code_rate, P_select_hp */
934 value = 0;
935 if (1 != 0)
936 value |= (1 << 6);
937 if (ch->u.ofdm.hierarchy_information == 1)
938 value |= (1 << 4);
939 if (1 == 1)
940 value |= 1;
941 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 -0300942 case FEC_2_3:
943 value |= (2 << 1);
944 break;
945 case FEC_3_4:
946 value |= (3 << 1);
947 break;
948 case FEC_5_6:
949 value |= (5 << 1);
950 break;
951 case FEC_7_8:
952 value |= (7 << 1);
953 break;
954 default:
955 case FEC_1_2:
956 value |= (1 << 1);
957 break;
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300958 }
959 dib7000p_write_word(state, 208, value);
960
961 /* offset loop parameters */
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300962 dib7000p_write_word(state, 26, 0x6680);
963 dib7000p_write_word(state, 32, 0x0003);
964 dib7000p_write_word(state, 29, 0x1273);
965 dib7000p_write_word(state, 33, 0x0005);
Patrick Boettchera75763f2006-10-18 08:34:16 -0300966
967 /* P_dvsy_sync_wait */
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300968 switch (ch->u.ofdm.transmission_mode) {
Olivier Grenie713d54a2011-01-04 04:54:31 -0300969 case TRANSMISSION_MODE_8K:
970 value = 256;
971 break;
972 case TRANSMISSION_MODE_4K:
973 value = 128;
974 break;
975 case TRANSMISSION_MODE_2K:
976 default:
977 value = 64;
978 break;
Patrick Boettchera75763f2006-10-18 08:34:16 -0300979 }
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300980 switch (ch->u.ofdm.guard_interval) {
Olivier Grenie713d54a2011-01-04 04:54:31 -0300981 case GUARD_INTERVAL_1_16:
982 value *= 2;
983 break;
984 case GUARD_INTERVAL_1_8:
985 value *= 4;
986 break;
987 case GUARD_INTERVAL_1_4:
988 value *= 8;
989 break;
990 default:
991 case GUARD_INTERVAL_1_32:
992 value *= 1;
993 break;
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300994 }
Olivier Grenie970d14c2010-09-07 12:50:46 -0300995 if (state->cfg.diversity_delay == 0)
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300996 state->div_sync_wait = (value * 3) / 2 + 48;
Olivier Grenie970d14c2010-09-07 12:50:46 -0300997 else
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300998 state->div_sync_wait = (value * 3) / 2 + state->cfg.diversity_delay;
Patrick Boettchera75763f2006-10-18 08:34:16 -0300999
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001000 /* deactive the possibility of diversity reception if extended interleaver */
1001 state->div_force_off = !1 && ch->u.ofdm.transmission_mode != TRANSMISSION_MODE_8K;
1002 dib7000p_set_diversity_in(&state->demod, state->div_state);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001003
1004 /* channel estimation fine configuration */
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001005 switch (ch->u.ofdm.constellation) {
Olivier Grenie713d54a2011-01-04 04:54:31 -03001006 case QAM_64:
1007 est[0] = 0x0148; /* P_adp_regul_cnt 0.04 */
1008 est[1] = 0xfff0; /* P_adp_noise_cnt -0.002 */
1009 est[2] = 0x00a4; /* P_adp_regul_ext 0.02 */
1010 est[3] = 0xfff8; /* P_adp_noise_ext -0.001 */
1011 break;
1012 case QAM_16:
1013 est[0] = 0x023d; /* P_adp_regul_cnt 0.07 */
1014 est[1] = 0xffdf; /* P_adp_noise_cnt -0.004 */
1015 est[2] = 0x00a4; /* P_adp_regul_ext 0.02 */
1016 est[3] = 0xfff0; /* P_adp_noise_ext -0.002 */
1017 break;
1018 default:
1019 est[0] = 0x099a; /* P_adp_regul_cnt 0.3 */
1020 est[1] = 0xffae; /* P_adp_noise_cnt -0.01 */
1021 est[2] = 0x0333; /* P_adp_regul_ext 0.1 */
1022 est[3] = 0xfff8; /* P_adp_noise_ext -0.002 */
1023 break;
Patrick Boettchera75763f2006-10-18 08:34:16 -03001024 }
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001025 for (value = 0; value < 4; value++)
1026 dib7000p_write_word(state, 187 + value, est[value]);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001027}
1028
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001029static int dib7000p_autosearch_start(struct dvb_frontend *demod, struct dvb_frontend_parameters *ch)
Patrick Boettchera75763f2006-10-18 08:34:16 -03001030{
1031 struct dib7000p_state *state = demod->demodulator_priv;
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001032 struct dvb_frontend_parameters schan;
1033 u32 value, factor;
Olivier Grenie713d54a2011-01-04 04:54:31 -03001034 u32 internal = dib7000p_get_internal_freq(state);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001035
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001036 schan = *ch;
1037 schan.u.ofdm.constellation = QAM_64;
Olivier Grenie713d54a2011-01-04 04:54:31 -03001038 schan.u.ofdm.guard_interval = GUARD_INTERVAL_1_32;
1039 schan.u.ofdm.transmission_mode = TRANSMISSION_MODE_8K;
1040 schan.u.ofdm.code_rate_HP = FEC_2_3;
1041 schan.u.ofdm.code_rate_LP = FEC_3_4;
1042 schan.u.ofdm.hierarchy_information = 0;
Patrick Boettchera75763f2006-10-18 08:34:16 -03001043
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001044 dib7000p_set_channel(state, &schan, 7);
1045
1046 factor = BANDWIDTH_TO_KHZ(ch->u.ofdm.bandwidth);
1047 if (factor >= 5000)
1048 factor = 1;
1049 else
1050 factor = 6;
Patrick Boettchera75763f2006-10-18 08:34:16 -03001051
Olivier Grenie713d54a2011-01-04 04:54:31 -03001052 value = 30 * internal * factor;
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001053 dib7000p_write_word(state, 6, (u16) ((value >> 16) & 0xffff));
1054 dib7000p_write_word(state, 7, (u16) (value & 0xffff));
Olivier Grenie713d54a2011-01-04 04:54:31 -03001055 value = 100 * internal * factor;
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001056 dib7000p_write_word(state, 8, (u16) ((value >> 16) & 0xffff));
1057 dib7000p_write_word(state, 9, (u16) (value & 0xffff));
Olivier Grenie713d54a2011-01-04 04:54:31 -03001058 value = 500 * internal * factor;
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001059 dib7000p_write_word(state, 10, (u16) ((value >> 16) & 0xffff));
1060 dib7000p_write_word(state, 11, (u16) (value & 0xffff));
Patrick Boettchera75763f2006-10-18 08:34:16 -03001061
1062 value = dib7000p_read_word(state, 0);
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001063 dib7000p_write_word(state, 0, (u16) ((1 << 9) | value));
Patrick Boettchera75763f2006-10-18 08:34:16 -03001064 dib7000p_read_word(state, 1284);
1065 dib7000p_write_word(state, 0, (u16) value);
1066
1067 return 0;
1068}
1069
1070static int dib7000p_autosearch_is_irq(struct dvb_frontend *demod)
1071{
1072 struct dib7000p_state *state = demod->demodulator_priv;
1073 u16 irq_pending = dib7000p_read_word(state, 1284);
1074
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001075 if (irq_pending & 0x1)
Patrick Boettchera75763f2006-10-18 08:34:16 -03001076 return 1;
1077
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001078 if (irq_pending & 0x2)
Patrick Boettchera75763f2006-10-18 08:34:16 -03001079 return 2;
1080
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001081 return 0;
Patrick Boettchera75763f2006-10-18 08:34:16 -03001082}
1083
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001084static void dib7000p_spur_protect(struct dib7000p_state *state, u32 rf_khz, u32 bw)
1085{
Olivier Grenie713d54a2011-01-04 04:54:31 -03001086 static s16 notch[] = { 16143, 14402, 12238, 9713, 6902, 3888, 759, -2392 };
1087 static u8 sine[] = { 0, 2, 3, 5, 6, 8, 9, 11, 13, 14, 16, 17, 19, 20, 22,
1088 24, 25, 27, 28, 30, 31, 33, 34, 36, 38, 39, 41, 42, 44, 45, 47, 48, 50, 51,
1089 53, 55, 56, 58, 59, 61, 62, 64, 65, 67, 68, 70, 71, 73, 74, 76, 77, 79, 80,
1090 82, 83, 85, 86, 88, 89, 91, 92, 94, 95, 97, 98, 99, 101, 102, 104, 105,
1091 107, 108, 109, 111, 112, 114, 115, 117, 118, 119, 121, 122, 123, 125, 126,
1092 128, 129, 130, 132, 133, 134, 136, 137, 138, 140, 141, 142, 144, 145, 146,
1093 147, 149, 150, 151, 152, 154, 155, 156, 157, 159, 160, 161, 162, 164, 165,
1094 166, 167, 168, 170, 171, 172, 173, 174, 175, 177, 178, 179, 180, 181, 182,
1095 183, 184, 185, 186, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198,
1096 199, 200, 201, 202, 203, 204, 205, 206, 207, 207, 208, 209, 210, 211, 212,
1097 213, 214, 215, 215, 216, 217, 218, 219, 220, 220, 221, 222, 223, 224, 224,
1098 225, 226, 227, 227, 228, 229, 229, 230, 231, 231, 232, 233, 233, 234, 235,
1099 235, 236, 237, 237, 238, 238, 239, 239, 240, 241, 241, 242, 242, 243, 243,
1100 244, 244, 245, 245, 245, 246, 246, 247, 247, 248, 248, 248, 249, 249, 249,
1101 250, 250, 250, 251, 251, 251, 252, 252, 252, 252, 253, 253, 253, 253, 254,
1102 254, 254, 254, 254, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
1103 255, 255, 255, 255, 255, 255
1104 };
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001105
1106 u32 xtal = state->cfg.bw->xtal_hz / 1000;
Julia Lawall75b697f2009-08-01 16:48:41 -03001107 int f_rel = DIV_ROUND_CLOSEST(rf_khz, xtal) * xtal - rf_khz;
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001108 int k;
Olivier Grenie713d54a2011-01-04 04:54:31 -03001109 int coef_re[8], coef_im[8];
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001110 int bw_khz = bw;
1111 u32 pha;
1112
Olivier Grenie713d54a2011-01-04 04:54:31 -03001113 dprintk("relative position of the Spur: %dk (RF: %dk, XTAL: %dk)", f_rel, rf_khz, xtal);
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001114
Olivier Grenie713d54a2011-01-04 04:54:31 -03001115 if (f_rel < -bw_khz / 2 || f_rel > bw_khz / 2)
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001116 return;
1117
1118 bw_khz /= 100;
1119
Olivier Grenie713d54a2011-01-04 04:54:31 -03001120 dib7000p_write_word(state, 142, 0x0610);
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001121
1122 for (k = 0; k < 8; k++) {
Olivier Grenie713d54a2011-01-04 04:54:31 -03001123 pha = ((f_rel * (k + 1) * 112 * 80 / bw_khz) / 1000) & 0x3ff;
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001124
Olivier Grenie713d54a2011-01-04 04:54:31 -03001125 if (pha == 0) {
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001126 coef_re[k] = 256;
1127 coef_im[k] = 0;
Olivier Grenie713d54a2011-01-04 04:54:31 -03001128 } else if (pha < 256) {
1129 coef_re[k] = sine[256 - (pha & 0xff)];
1130 coef_im[k] = sine[pha & 0xff];
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001131 } else if (pha == 256) {
1132 coef_re[k] = 0;
1133 coef_im[k] = 256;
1134 } else if (pha < 512) {
Olivier Grenie713d54a2011-01-04 04:54:31 -03001135 coef_re[k] = -sine[pha & 0xff];
1136 coef_im[k] = sine[256 - (pha & 0xff)];
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001137 } else if (pha == 512) {
1138 coef_re[k] = -256;
1139 coef_im[k] = 0;
1140 } else if (pha < 768) {
Olivier Grenie713d54a2011-01-04 04:54:31 -03001141 coef_re[k] = -sine[256 - (pha & 0xff)];
1142 coef_im[k] = -sine[pha & 0xff];
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001143 } else if (pha == 768) {
1144 coef_re[k] = 0;
1145 coef_im[k] = -256;
1146 } else {
Olivier Grenie713d54a2011-01-04 04:54:31 -03001147 coef_re[k] = sine[pha & 0xff];
1148 coef_im[k] = -sine[256 - (pha & 0xff)];
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001149 }
1150
1151 coef_re[k] *= notch[k];
Olivier Grenie713d54a2011-01-04 04:54:31 -03001152 coef_re[k] += (1 << 14);
1153 if (coef_re[k] >= (1 << 24))
1154 coef_re[k] = (1 << 24) - 1;
1155 coef_re[k] /= (1 << 15);
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001156
1157 coef_im[k] *= notch[k];
Olivier Grenie713d54a2011-01-04 04:54:31 -03001158 coef_im[k] += (1 << 14);
1159 if (coef_im[k] >= (1 << 24))
1160 coef_im[k] = (1 << 24) - 1;
1161 coef_im[k] /= (1 << 15);
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001162
Olivier Grenie713d54a2011-01-04 04:54:31 -03001163 dprintk("PALF COEF: %d re: %d im: %d", k, coef_re[k], coef_im[k]);
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001164
1165 dib7000p_write_word(state, 143, (0 << 14) | (k << 10) | (coef_re[k] & 0x3ff));
1166 dib7000p_write_word(state, 144, coef_im[k] & 0x3ff);
1167 dib7000p_write_word(state, 143, (1 << 14) | (k << 10) | (coef_re[k] & 0x3ff));
1168 }
Olivier Grenie713d54a2011-01-04 04:54:31 -03001169 dib7000p_write_word(state, 143, 0);
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001170}
1171
1172static int dib7000p_tune(struct dvb_frontend *demod, struct dvb_frontend_parameters *ch)
Patrick Boettchera75763f2006-10-18 08:34:16 -03001173{
1174 struct dib7000p_state *state = demod->demodulator_priv;
1175 u16 tmp = 0;
1176
1177 if (ch != NULL)
1178 dib7000p_set_channel(state, ch, 0);
1179 else
1180 return -EINVAL;
1181
1182 // restart demod
1183 dib7000p_write_word(state, 770, 0x4000);
1184 dib7000p_write_word(state, 770, 0x0000);
1185 msleep(45);
1186
1187 /* 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 -03001188 tmp = (0 << 14) | (4 << 10) | (0 << 9) | (3 << 5) | (1 << 4) | (0x3);
1189 if (state->sfn_workaround_active) {
Olivier Grenie713d54a2011-01-04 04:54:31 -03001190 dprintk("SFN workaround is active");
Matt Doran8f6956c2007-07-31 07:09:30 -03001191 tmp |= (1 << 9);
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001192 dib7000p_write_word(state, 166, 0x4000);
Matt Doran8f6956c2007-07-31 07:09:30 -03001193 } else {
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001194 dib7000p_write_word(state, 166, 0x0000);
Matt Doran8f6956c2007-07-31 07:09:30 -03001195 }
1196 dib7000p_write_word(state, 29, tmp);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001197
1198 // never achieved a lock with that bandwidth so far - wait for osc-freq to update
1199 if (state->timf == 0)
1200 msleep(200);
1201
1202 /* offset loop parameters */
1203
1204 /* P_timf_alpha, P_corm_alpha=6, P_corm_thres=0x80 */
1205 tmp = (6 << 8) | 0x80;
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001206 switch (ch->u.ofdm.transmission_mode) {
Olivier Grenie713d54a2011-01-04 04:54:31 -03001207 case TRANSMISSION_MODE_2K:
1208 tmp |= (2 << 12);
1209 break;
1210 case TRANSMISSION_MODE_4K:
1211 tmp |= (3 << 12);
1212 break;
1213 default:
1214 case TRANSMISSION_MODE_8K:
1215 tmp |= (4 << 12);
1216 break;
Patrick Boettchera75763f2006-10-18 08:34:16 -03001217 }
Olivier Grenie713d54a2011-01-04 04:54:31 -03001218 dib7000p_write_word(state, 26, tmp); /* timf_a(6xxx) */
Patrick Boettchera75763f2006-10-18 08:34:16 -03001219
1220 /* P_ctrl_freeze_pha_shift=0, P_ctrl_pha_off_max */
1221 tmp = (0 << 4);
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001222 switch (ch->u.ofdm.transmission_mode) {
Olivier Grenie713d54a2011-01-04 04:54:31 -03001223 case TRANSMISSION_MODE_2K:
1224 tmp |= 0x6;
1225 break;
1226 case TRANSMISSION_MODE_4K:
1227 tmp |= 0x7;
1228 break;
1229 default:
1230 case TRANSMISSION_MODE_8K:
1231 tmp |= 0x8;
1232 break;
Patrick Boettchera75763f2006-10-18 08:34:16 -03001233 }
Olivier Grenie713d54a2011-01-04 04:54:31 -03001234 dib7000p_write_word(state, 32, tmp);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001235
1236 /* P_ctrl_sfreq_inh=0, P_ctrl_sfreq_step */
1237 tmp = (0 << 4);
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001238 switch (ch->u.ofdm.transmission_mode) {
Olivier Grenie713d54a2011-01-04 04:54:31 -03001239 case TRANSMISSION_MODE_2K:
1240 tmp |= 0x6;
1241 break;
1242 case TRANSMISSION_MODE_4K:
1243 tmp |= 0x7;
1244 break;
1245 default:
1246 case TRANSMISSION_MODE_8K:
1247 tmp |= 0x8;
1248 break;
Patrick Boettchera75763f2006-10-18 08:34:16 -03001249 }
Olivier Grenie713d54a2011-01-04 04:54:31 -03001250 dib7000p_write_word(state, 33, tmp);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001251
Olivier Grenie713d54a2011-01-04 04:54:31 -03001252 tmp = dib7000p_read_word(state, 509);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001253 if (!((tmp >> 6) & 0x1)) {
1254 /* restart the fec */
Olivier Grenie713d54a2011-01-04 04:54:31 -03001255 tmp = dib7000p_read_word(state, 771);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001256 dib7000p_write_word(state, 771, tmp | (1 << 1));
1257 dib7000p_write_word(state, 771, tmp);
Olivier Grenie713d54a2011-01-04 04:54:31 -03001258 msleep(40);
1259 tmp = dib7000p_read_word(state, 509);
1260 }
1261 // we achieved a lock - it's time to update the osc freq
1262 if ((tmp >> 6) & 0x1) {
1263 dib7000p_update_timf(state);
1264 /* P_timf_alpha += 2 */
1265 tmp = dib7000p_read_word(state, 26);
1266 dib7000p_write_word(state, 26, (tmp & ~(0xf << 12)) | ((((tmp >> 12) & 0xf) + 5) << 12));
Patrick Boettchera75763f2006-10-18 08:34:16 -03001267 }
1268
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001269 if (state->cfg.spur_protect)
Olivier Grenie713d54a2011-01-04 04:54:31 -03001270 dib7000p_spur_protect(state, ch->frequency / 1000, BANDWIDTH_TO_KHZ(ch->u.ofdm.bandwidth));
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001271
Olivier Grenie713d54a2011-01-04 04:54:31 -03001272 dib7000p_set_bandwidth(state, BANDWIDTH_TO_KHZ(ch->u.ofdm.bandwidth));
Patrick Boettchera75763f2006-10-18 08:34:16 -03001273 return 0;
1274}
1275
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001276static int dib7000p_wakeup(struct dvb_frontend *demod)
Patrick Boettchera75763f2006-10-18 08:34:16 -03001277{
Patrick Boettchera75763f2006-10-18 08:34:16 -03001278 struct dib7000p_state *state = demod->demodulator_priv;
Patrick Boettchera75763f2006-10-18 08:34:16 -03001279 dib7000p_set_power_mode(state, DIB7000P_POWER_ALL);
1280 dib7000p_set_adc_state(state, DIBX000_SLOW_ADC_ON);
Olivier Grenie713d54a2011-01-04 04:54:31 -03001281 if (state->version == SOC7090)
1282 dib7000p_sad_calib(state);
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001283 return 0;
Patrick Boettchera75763f2006-10-18 08:34:16 -03001284}
1285
1286static int dib7000p_sleep(struct dvb_frontend *demod)
1287{
1288 struct dib7000p_state *state = demod->demodulator_priv;
Olivier Grenie713d54a2011-01-04 04:54:31 -03001289 if (state->version == SOC7090)
1290 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 -03001291 return dib7000p_set_output_mode(state, OUTMODE_HIGH_Z) | dib7000p_set_power_mode(state, DIB7000P_POWER_INTERFACE_ONLY);
1292}
1293
1294static int dib7000p_identify(struct dib7000p_state *st)
1295{
1296 u16 value;
Olivier Grenie713d54a2011-01-04 04:54:31 -03001297 dprintk("checking demod on I2C address: %d (%x)", st->i2c_addr, st->i2c_addr);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001298
1299 if ((value = dib7000p_read_word(st, 768)) != 0x01b3) {
Olivier Grenie713d54a2011-01-04 04:54:31 -03001300 dprintk("wrong Vendor ID (read=0x%x)", value);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001301 return -EREMOTEIO;
1302 }
1303
1304 if ((value = dib7000p_read_word(st, 769)) != 0x4000) {
Olivier Grenie713d54a2011-01-04 04:54:31 -03001305 dprintk("wrong Device ID (%x)", value);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001306 return -EREMOTEIO;
1307 }
1308
1309 return 0;
1310}
1311
Olivier Grenie713d54a2011-01-04 04:54:31 -03001312static int dib7000p_get_frontend(struct dvb_frontend *fe, struct dvb_frontend_parameters *fep)
Patrick Boettchera75763f2006-10-18 08:34:16 -03001313{
1314 struct dib7000p_state *state = fe->demodulator_priv;
Olivier Grenie713d54a2011-01-04 04:54:31 -03001315 u16 tps = dib7000p_read_word(state, 463);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001316
1317 fep->inversion = INVERSION_AUTO;
1318
Patrick Boettcher904a82e2008-01-25 07:31:58 -03001319 fep->u.ofdm.bandwidth = BANDWIDTH_TO_INDEX(state->current_bandwidth);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001320
1321 switch ((tps >> 8) & 0x3) {
Olivier Grenie713d54a2011-01-04 04:54:31 -03001322 case 0:
1323 fep->u.ofdm.transmission_mode = TRANSMISSION_MODE_2K;
1324 break;
1325 case 1:
1326 fep->u.ofdm.transmission_mode = TRANSMISSION_MODE_8K;
1327 break;
Patrick Boettchera75763f2006-10-18 08:34:16 -03001328 /* case 2: fep->u.ofdm.transmission_mode = TRANSMISSION_MODE_4K; break; */
1329 }
1330
1331 switch (tps & 0x3) {
Olivier Grenie713d54a2011-01-04 04:54:31 -03001332 case 0:
1333 fep->u.ofdm.guard_interval = GUARD_INTERVAL_1_32;
1334 break;
1335 case 1:
1336 fep->u.ofdm.guard_interval = GUARD_INTERVAL_1_16;
1337 break;
1338 case 2:
1339 fep->u.ofdm.guard_interval = GUARD_INTERVAL_1_8;
1340 break;
1341 case 3:
1342 fep->u.ofdm.guard_interval = GUARD_INTERVAL_1_4;
1343 break;
Patrick Boettchera75763f2006-10-18 08:34:16 -03001344 }
1345
1346 switch ((tps >> 14) & 0x3) {
Olivier Grenie713d54a2011-01-04 04:54:31 -03001347 case 0:
1348 fep->u.ofdm.constellation = QPSK;
1349 break;
1350 case 1:
1351 fep->u.ofdm.constellation = QAM_16;
1352 break;
1353 case 2:
1354 default:
1355 fep->u.ofdm.constellation = QAM_64;
1356 break;
Patrick Boettchera75763f2006-10-18 08:34:16 -03001357 }
1358
1359 /* as long as the frontend_param structure is fixed for hierarchical transmission I refuse to use it */
1360 /* (tps >> 13) & 0x1 == hrch is used, (tps >> 10) & 0x7 == alpha */
1361
1362 fep->u.ofdm.hierarchy_information = HIERARCHY_NONE;
1363 switch ((tps >> 5) & 0x7) {
Olivier Grenie713d54a2011-01-04 04:54:31 -03001364 case 1:
1365 fep->u.ofdm.code_rate_HP = FEC_1_2;
1366 break;
1367 case 2:
1368 fep->u.ofdm.code_rate_HP = FEC_2_3;
1369 break;
1370 case 3:
1371 fep->u.ofdm.code_rate_HP = FEC_3_4;
1372 break;
1373 case 5:
1374 fep->u.ofdm.code_rate_HP = FEC_5_6;
1375 break;
1376 case 7:
1377 default:
1378 fep->u.ofdm.code_rate_HP = FEC_7_8;
1379 break;
Patrick Boettchera75763f2006-10-18 08:34:16 -03001380
1381 }
1382
1383 switch ((tps >> 2) & 0x7) {
Olivier Grenie713d54a2011-01-04 04:54:31 -03001384 case 1:
1385 fep->u.ofdm.code_rate_LP = FEC_1_2;
1386 break;
1387 case 2:
1388 fep->u.ofdm.code_rate_LP = FEC_2_3;
1389 break;
1390 case 3:
1391 fep->u.ofdm.code_rate_LP = FEC_3_4;
1392 break;
1393 case 5:
1394 fep->u.ofdm.code_rate_LP = FEC_5_6;
1395 break;
1396 case 7:
1397 default:
1398 fep->u.ofdm.code_rate_LP = FEC_7_8;
1399 break;
Patrick Boettchera75763f2006-10-18 08:34:16 -03001400 }
1401
1402 /* native interleaver: (dib7000p_read_word(state, 464) >> 5) & 0x1 */
1403
1404 return 0;
1405}
1406
Olivier Grenie713d54a2011-01-04 04:54:31 -03001407static int dib7000p_set_frontend(struct dvb_frontend *fe, struct dvb_frontend_parameters *fep)
Patrick Boettchera75763f2006-10-18 08:34:16 -03001408{
1409 struct dib7000p_state *state = fe->demodulator_priv;
Soeren Moch853ea132008-01-25 06:27:06 -03001410 int time, ret;
Patrick Boettchera75763f2006-10-18 08:34:16 -03001411
Olivier Grenie713d54a2011-01-04 04:54:31 -03001412 if (state->version == SOC7090) {
1413 dib7090_set_diversity_in(fe, 0);
1414 dib7090_set_output_mode(fe, OUTMODE_HIGH_Z);
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001415 } else
Olivier Grenie713d54a2011-01-04 04:54:31 -03001416 dib7000p_set_output_mode(state, OUTMODE_HIGH_Z);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001417
Olivier Grenie713d54a2011-01-04 04:54:31 -03001418 /* maybe the parameter has been changed */
Matt Doran8f6956c2007-07-31 07:09:30 -03001419 state->sfn_workaround_active = buggy_sfn_workaround;
1420
Patrick Boettchera75763f2006-10-18 08:34:16 -03001421 if (fe->ops.tuner_ops.set_params)
1422 fe->ops.tuner_ops.set_params(fe, fep);
1423
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001424 /* start up the AGC */
1425 state->agc_state = 0;
1426 do {
1427 time = dib7000p_agc_startup(fe, fep);
1428 if (time != -1)
1429 msleep(time);
1430 } while (time != -1);
1431
Patrick Boettchera75763f2006-10-18 08:34:16 -03001432 if (fep->u.ofdm.transmission_mode == TRANSMISSION_MODE_AUTO ||
Olivier Grenie713d54a2011-01-04 04:54:31 -03001433 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 -03001434 int i = 800, found;
1435
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001436 dib7000p_autosearch_start(fe, fep);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001437 do {
1438 msleep(1);
1439 found = dib7000p_autosearch_is_irq(fe);
1440 } while (found == 0 && i--);
1441
Olivier Grenie713d54a2011-01-04 04:54:31 -03001442 dprintk("autosearch returns: %d", found);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001443 if (found == 0 || found == 1)
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001444 return 0;
Patrick Boettchera75763f2006-10-18 08:34:16 -03001445
1446 dib7000p_get_frontend(fe, fep);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001447 }
1448
Soeren Moch853ea132008-01-25 06:27:06 -03001449 ret = dib7000p_tune(fe, fep);
1450
Patrick Boettchera75763f2006-10-18 08:34:16 -03001451 /* make this a config parameter */
Olivier Grenie713d54a2011-01-04 04:54:31 -03001452 if (state->version == SOC7090)
1453 dib7090_set_output_mode(fe, state->cfg.output_mode);
1454 else
1455 dib7000p_set_output_mode(state, state->cfg.output_mode);
1456
1457 return ret;
Patrick Boettchera75763f2006-10-18 08:34:16 -03001458}
1459
Olivier Grenie713d54a2011-01-04 04:54:31 -03001460static int dib7000p_read_status(struct dvb_frontend *fe, fe_status_t * stat)
Patrick Boettchera75763f2006-10-18 08:34:16 -03001461{
1462 struct dib7000p_state *state = fe->demodulator_priv;
1463 u16 lock = dib7000p_read_word(state, 509);
1464
1465 *stat = 0;
1466
1467 if (lock & 0x8000)
1468 *stat |= FE_HAS_SIGNAL;
1469 if (lock & 0x3000)
1470 *stat |= FE_HAS_CARRIER;
1471 if (lock & 0x0100)
1472 *stat |= FE_HAS_VITERBI;
1473 if (lock & 0x0010)
1474 *stat |= FE_HAS_SYNC;
Olivier Grenie713d54a2011-01-04 04:54:31 -03001475 if ((lock & 0x0038) == 0x38)
Patrick Boettchera75763f2006-10-18 08:34:16 -03001476 *stat |= FE_HAS_LOCK;
1477
1478 return 0;
1479}
1480
Olivier Grenie713d54a2011-01-04 04:54:31 -03001481static int dib7000p_read_ber(struct dvb_frontend *fe, u32 * ber)
Patrick Boettchera75763f2006-10-18 08:34:16 -03001482{
1483 struct dib7000p_state *state = fe->demodulator_priv;
1484 *ber = (dib7000p_read_word(state, 500) << 16) | dib7000p_read_word(state, 501);
1485 return 0;
1486}
1487
Olivier Grenie713d54a2011-01-04 04:54:31 -03001488static int dib7000p_read_unc_blocks(struct dvb_frontend *fe, u32 * unc)
Patrick Boettchera75763f2006-10-18 08:34:16 -03001489{
1490 struct dib7000p_state *state = fe->demodulator_priv;
1491 *unc = dib7000p_read_word(state, 506);
1492 return 0;
1493}
1494
Olivier Grenie713d54a2011-01-04 04:54:31 -03001495static int dib7000p_read_signal_strength(struct dvb_frontend *fe, u16 * strength)
Patrick Boettchera75763f2006-10-18 08:34:16 -03001496{
1497 struct dib7000p_state *state = fe->demodulator_priv;
1498 u16 val = dib7000p_read_word(state, 394);
1499 *strength = 65535 - val;
1500 return 0;
1501}
1502
Olivier Grenie713d54a2011-01-04 04:54:31 -03001503static int dib7000p_read_snr(struct dvb_frontend *fe, u16 * snr)
Patrick Boettchera75763f2006-10-18 08:34:16 -03001504{
Olivier Grenieef801962009-09-15 06:46:52 -03001505 struct dib7000p_state *state = fe->demodulator_priv;
1506 u16 val;
1507 s32 signal_mant, signal_exp, noise_mant, noise_exp;
1508 u32 result = 0;
1509
1510 val = dib7000p_read_word(state, 479);
1511 noise_mant = (val >> 4) & 0xff;
1512 noise_exp = ((val & 0xf) << 2);
1513 val = dib7000p_read_word(state, 480);
1514 noise_exp += ((val >> 14) & 0x3);
1515 if ((noise_exp & 0x20) != 0)
1516 noise_exp -= 0x40;
1517
1518 signal_mant = (val >> 6) & 0xFF;
Olivier Grenie713d54a2011-01-04 04:54:31 -03001519 signal_exp = (val & 0x3F);
Olivier Grenieef801962009-09-15 06:46:52 -03001520 if ((signal_exp & 0x20) != 0)
1521 signal_exp -= 0x40;
1522
1523 if (signal_mant != 0)
Olivier Grenie713d54a2011-01-04 04:54:31 -03001524 result = intlog10(2) * 10 * signal_exp + 10 * intlog10(signal_mant);
Olivier Grenieef801962009-09-15 06:46:52 -03001525 else
1526 result = intlog10(2) * 10 * signal_exp - 100;
1527
1528 if (noise_mant != 0)
Olivier Grenie713d54a2011-01-04 04:54:31 -03001529 result -= intlog10(2) * 10 * noise_exp + 10 * intlog10(noise_mant);
Olivier Grenieef801962009-09-15 06:46:52 -03001530 else
1531 result -= intlog10(2) * 10 * noise_exp - 100;
1532
1533 *snr = result / ((1 << 24) / 10);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001534 return 0;
1535}
1536
Olivier Grenie713d54a2011-01-04 04:54:31 -03001537static int dib7000p_fe_get_tune_settings(struct dvb_frontend *fe, struct dvb_frontend_tune_settings *tune)
Patrick Boettchera75763f2006-10-18 08:34:16 -03001538{
1539 tune->min_delay_ms = 1000;
1540 return 0;
1541}
1542
1543static void dib7000p_release(struct dvb_frontend *demod)
1544{
1545 struct dib7000p_state *st = demod->demodulator_priv;
1546 dibx000_exit_i2c_master(&st->i2c_master);
Olivier Grenie713d54a2011-01-04 04:54:31 -03001547 i2c_del_adapter(&st->dib7090_tuner_adap);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001548 kfree(st);
1549}
1550
1551int dib7000pc_detection(struct i2c_adapter *i2c_adap)
1552{
1553 u8 tx[2], rx[2];
1554 struct i2c_msg msg[2] = {
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001555 {.addr = 18 >> 1, .flags = 0, .buf = tx, .len = 2},
1556 {.addr = 18 >> 1, .flags = I2C_M_RD, .buf = rx, .len = 2},
Patrick Boettchera75763f2006-10-18 08:34:16 -03001557 };
1558
1559 tx[0] = 0x03;
1560 tx[1] = 0x00;
1561
1562 if (i2c_transfer(i2c_adap, msg, 2) == 2)
1563 if (rx[0] == 0x01 && rx[1] == 0xb3) {
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001564 dprintk("-D- DiB7000PC detected");
Patrick Boettchera75763f2006-10-18 08:34:16 -03001565 return 1;
1566 }
1567
1568 msg[0].addr = msg[1].addr = 0x40;
1569
1570 if (i2c_transfer(i2c_adap, msg, 2) == 2)
1571 if (rx[0] == 0x01 && rx[1] == 0xb3) {
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001572 dprintk("-D- DiB7000PC detected");
Patrick Boettchera75763f2006-10-18 08:34:16 -03001573 return 1;
1574 }
1575
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001576 dprintk("-D- DiB7000PC not detected");
Patrick Boettchera75763f2006-10-18 08:34:16 -03001577 return 0;
1578}
1579EXPORT_SYMBOL(dib7000pc_detection);
1580
Olivier Grenie713d54a2011-01-04 04:54:31 -03001581struct i2c_adapter *dib7000p_get_i2c_master(struct dvb_frontend *demod, enum dibx000_i2c_interface intf, int gating)
Patrick Boettchera75763f2006-10-18 08:34:16 -03001582{
1583 struct dib7000p_state *st = demod->demodulator_priv;
1584 return dibx000_get_i2c_adapter(&st->i2c_master, intf, gating);
1585}
1586EXPORT_SYMBOL(dib7000p_get_i2c_master);
1587
Olivier Grenief8731f42009-09-18 04:08:43 -03001588int dib7000p_pid_filter_ctrl(struct dvb_frontend *fe, u8 onoff)
1589{
Olivier Grenie713d54a2011-01-04 04:54:31 -03001590 struct dib7000p_state *state = fe->demodulator_priv;
1591 u16 val = dib7000p_read_word(state, 235) & 0xffef;
1592 val |= (onoff & 0x1) << 4;
1593 dprintk("PID filter enabled %d", onoff);
1594 return dib7000p_write_word(state, 235, val);
Olivier Grenief8731f42009-09-18 04:08:43 -03001595}
1596EXPORT_SYMBOL(dib7000p_pid_filter_ctrl);
1597
1598int dib7000p_pid_filter(struct dvb_frontend *fe, u8 id, u16 pid, u8 onoff)
1599{
Olivier Grenie713d54a2011-01-04 04:54:31 -03001600 struct dib7000p_state *state = fe->demodulator_priv;
1601 dprintk("PID filter: index %x, PID %d, OnOff %d", id, pid, onoff);
1602 return dib7000p_write_word(state, 241 + id, onoff ? (1 << 13) | pid : 0);
Olivier Grenief8731f42009-09-18 04:08:43 -03001603}
1604EXPORT_SYMBOL(dib7000p_pid_filter);
1605
Patrick Boettchera75763f2006-10-18 08:34:16 -03001606int dib7000p_i2c_enumeration(struct i2c_adapter *i2c, int no_of_demods, u8 default_addr, struct dib7000p_config cfg[])
1607{
Randy Dunlap30d81bb2010-02-08 20:30:44 -03001608 struct dib7000p_state *dpst;
Patrick Boettchera75763f2006-10-18 08:34:16 -03001609 int k = 0;
1610 u8 new_addr = 0;
1611
Randy Dunlap30d81bb2010-02-08 20:30:44 -03001612 dpst = kzalloc(sizeof(struct dib7000p_state), GFP_KERNEL);
1613 if (!dpst)
Andrew Morton0b427602010-04-27 19:09:45 -03001614 return -ENOMEM;
Randy Dunlap30d81bb2010-02-08 20:30:44 -03001615
1616 dpst->i2c_adap = i2c;
1617
Olivier Grenie713d54a2011-01-04 04:54:31 -03001618 for (k = no_of_demods - 1; k >= 0; k--) {
Randy Dunlap30d81bb2010-02-08 20:30:44 -03001619 dpst->cfg = cfg[k];
Patrick Boettchera75763f2006-10-18 08:34:16 -03001620
1621 /* designated i2c address */
Olivier Grenie713d54a2011-01-04 04:54:31 -03001622 if (cfg[k].default_i2c_addr != 0)
1623 new_addr = cfg[k].default_i2c_addr + (k << 1);
1624 else
1625 new_addr = (0x40 + k) << 1;
Randy Dunlap30d81bb2010-02-08 20:30:44 -03001626 dpst->i2c_addr = new_addr;
Olivier Grenie713d54a2011-01-04 04:54:31 -03001627 dib7000p_write_word(dpst, 1287, 0x0003); /* sram lead in, rdy */
Randy Dunlap30d81bb2010-02-08 20:30:44 -03001628 if (dib7000p_identify(dpst) != 0) {
1629 dpst->i2c_addr = default_addr;
Olivier Grenie713d54a2011-01-04 04:54:31 -03001630 dib7000p_write_word(dpst, 1287, 0x0003); /* sram lead in, rdy */
Randy Dunlap30d81bb2010-02-08 20:30:44 -03001631 if (dib7000p_identify(dpst) != 0) {
Patrick Boettchera75763f2006-10-18 08:34:16 -03001632 dprintk("DiB7000P #%d: not identified\n", k);
Randy Dunlap30d81bb2010-02-08 20:30:44 -03001633 kfree(dpst);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001634 return -EIO;
1635 }
1636 }
1637
1638 /* start diversity to pull_down div_str - just for i2c-enumeration */
Randy Dunlap30d81bb2010-02-08 20:30:44 -03001639 dib7000p_set_output_mode(dpst, OUTMODE_DIVERSITY);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001640
1641 /* set new i2c address and force divstart */
Randy Dunlap30d81bb2010-02-08 20:30:44 -03001642 dib7000p_write_word(dpst, 1285, (new_addr << 2) | 0x2);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001643
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001644 dprintk("IC %d initialized (to i2c_address 0x%x)", k, new_addr);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001645 }
1646
1647 for (k = 0; k < no_of_demods; k++) {
Randy Dunlap30d81bb2010-02-08 20:30:44 -03001648 dpst->cfg = cfg[k];
Olivier Grenie713d54a2011-01-04 04:54:31 -03001649 if (cfg[k].default_i2c_addr != 0)
1650 dpst->i2c_addr = (cfg[k].default_i2c_addr + k) << 1;
1651 else
1652 dpst->i2c_addr = (0x40 + k) << 1;
Patrick Boettchera75763f2006-10-18 08:34:16 -03001653
1654 // unforce divstr
Randy Dunlap30d81bb2010-02-08 20:30:44 -03001655 dib7000p_write_word(dpst, 1285, dpst->i2c_addr << 2);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001656
1657 /* deactivate div - it was just for i2c-enumeration */
Randy Dunlap30d81bb2010-02-08 20:30:44 -03001658 dib7000p_set_output_mode(dpst, OUTMODE_HIGH_Z);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001659 }
1660
Randy Dunlap30d81bb2010-02-08 20:30:44 -03001661 kfree(dpst);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001662 return 0;
1663}
1664EXPORT_SYMBOL(dib7000p_i2c_enumeration);
1665
Olivier Grenie713d54a2011-01-04 04:54:31 -03001666static const s32 lut_1000ln_mant[] = {
1667 6908, 6956, 7003, 7047, 7090, 7131, 7170, 7208, 7244, 7279, 7313, 7346, 7377, 7408, 7438, 7467, 7495, 7523, 7549, 7575, 7600
1668};
1669
1670static s32 dib7000p_get_adc_power(struct dvb_frontend *fe)
1671{
1672 struct dib7000p_state *state = fe->demodulator_priv;
1673 u32 tmp_val = 0, exp = 0, mant = 0;
1674 s32 pow_i;
1675 u16 buf[2];
1676 u8 ix = 0;
1677
1678 buf[0] = dib7000p_read_word(state, 0x184);
1679 buf[1] = dib7000p_read_word(state, 0x185);
1680 pow_i = (buf[0] << 16) | buf[1];
1681 dprintk("raw pow_i = %d", pow_i);
1682
1683 tmp_val = pow_i;
1684 while (tmp_val >>= 1)
1685 exp++;
1686
1687 mant = (pow_i * 1000 / (1 << exp));
1688 dprintk(" mant = %d exp = %d", mant / 1000, exp);
1689
1690 ix = (u8) ((mant - 1000) / 100); /* index of the LUT */
1691 dprintk(" ix = %d", ix);
1692
1693 pow_i = (lut_1000ln_mant[ix] + 693 * (exp - 20) - 6908);
1694 pow_i = (pow_i << 8) / 1000;
1695 dprintk(" pow_i = %d", pow_i);
1696
1697 return pow_i;
1698}
1699
1700static int map_addr_to_serpar_number(struct i2c_msg *msg)
1701{
1702 if ((msg->buf[0] <= 15))
1703 msg->buf[0] -= 1;
1704 else if (msg->buf[0] == 17)
1705 msg->buf[0] = 15;
1706 else if (msg->buf[0] == 16)
1707 msg->buf[0] = 17;
1708 else if (msg->buf[0] == 19)
1709 msg->buf[0] = 16;
1710 else if (msg->buf[0] >= 21 && msg->buf[0] <= 25)
1711 msg->buf[0] -= 3;
1712 else if (msg->buf[0] == 28)
1713 msg->buf[0] = 23;
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001714 else
Olivier Grenie713d54a2011-01-04 04:54:31 -03001715 return -EINVAL;
Olivier Grenie713d54a2011-01-04 04:54:31 -03001716 return 0;
1717}
1718
1719static int w7090p_tuner_write_serpar(struct i2c_adapter *i2c_adap, struct i2c_msg msg[], int num)
1720{
1721 struct dib7000p_state *state = i2c_get_adapdata(i2c_adap);
1722 u8 n_overflow = 1;
1723 u16 i = 1000;
1724 u16 serpar_num = msg[0].buf[0];
1725
1726 while (n_overflow == 1 && i) {
1727 n_overflow = (dib7000p_read_word(state, 1984) >> 1) & 0x1;
1728 i--;
1729 if (i == 0)
1730 dprintk("Tuner ITF: write busy (overflow)");
1731 }
1732 dib7000p_write_word(state, 1985, (1 << 6) | (serpar_num & 0x3f));
1733 dib7000p_write_word(state, 1986, (msg[0].buf[1] << 8) | msg[0].buf[2]);
1734
1735 return num;
1736}
1737
1738static int w7090p_tuner_read_serpar(struct i2c_adapter *i2c_adap, struct i2c_msg msg[], int num)
1739{
1740 struct dib7000p_state *state = i2c_get_adapdata(i2c_adap);
1741 u8 n_overflow = 1, n_empty = 1;
1742 u16 i = 1000;
1743 u16 serpar_num = msg[0].buf[0];
1744 u16 read_word;
1745
1746 while (n_overflow == 1 && i) {
1747 n_overflow = (dib7000p_read_word(state, 1984) >> 1) & 0x1;
1748 i--;
1749 if (i == 0)
1750 dprintk("TunerITF: read busy (overflow)");
1751 }
1752 dib7000p_write_word(state, 1985, (0 << 6) | (serpar_num & 0x3f));
1753
1754 i = 1000;
1755 while (n_empty == 1 && i) {
1756 n_empty = dib7000p_read_word(state, 1984) & 0x1;
1757 i--;
1758 if (i == 0)
1759 dprintk("TunerITF: read busy (empty)");
1760 }
1761 read_word = dib7000p_read_word(state, 1987);
1762 msg[1].buf[0] = (read_word >> 8) & 0xff;
1763 msg[1].buf[1] = (read_word) & 0xff;
1764
1765 return num;
1766}
1767
1768static int w7090p_tuner_rw_serpar(struct i2c_adapter *i2c_adap, struct i2c_msg msg[], int num)
1769{
1770 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... */
1771 if (num == 1) { /* write */
1772 return w7090p_tuner_write_serpar(i2c_adap, msg, 1);
1773 } else { /* read */
1774 return w7090p_tuner_read_serpar(i2c_adap, msg, 2);
1775 }
1776 }
1777 return num;
1778}
1779
1780int dib7090p_rw_on_apb(struct i2c_adapter *i2c_adap, struct i2c_msg msg[], int num, u16 apb_address)
1781{
1782 struct dib7000p_state *state = i2c_get_adapdata(i2c_adap);
1783 u16 word;
1784
1785 if (num == 1) { /* write */
1786 dib7000p_write_word(state, apb_address, ((msg[0].buf[1] << 8) | (msg[0].buf[2])));
1787 } else {
1788 word = dib7000p_read_word(state, apb_address);
1789 msg[1].buf[0] = (word >> 8) & 0xff;
1790 msg[1].buf[1] = (word) & 0xff;
1791 }
1792
1793 return num;
1794}
1795
1796static int dib7090_tuner_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg msg[], int num)
1797{
1798 struct dib7000p_state *state = i2c_get_adapdata(i2c_adap);
1799
1800 u16 apb_address = 0, word;
1801 int i = 0;
1802 switch (msg[0].buf[0]) {
1803 case 0x12:
1804 apb_address = 1920;
1805 break;
1806 case 0x14:
1807 apb_address = 1921;
1808 break;
1809 case 0x24:
1810 apb_address = 1922;
1811 break;
1812 case 0x1a:
1813 apb_address = 1923;
1814 break;
1815 case 0x22:
1816 apb_address = 1924;
1817 break;
1818 case 0x33:
1819 apb_address = 1926;
1820 break;
1821 case 0x34:
1822 apb_address = 1927;
1823 break;
1824 case 0x35:
1825 apb_address = 1928;
1826 break;
1827 case 0x36:
1828 apb_address = 1929;
1829 break;
1830 case 0x37:
1831 apb_address = 1930;
1832 break;
1833 case 0x38:
1834 apb_address = 1931;
1835 break;
1836 case 0x39:
1837 apb_address = 1932;
1838 break;
1839 case 0x2a:
1840 apb_address = 1935;
1841 break;
1842 case 0x2b:
1843 apb_address = 1936;
1844 break;
1845 case 0x2c:
1846 apb_address = 1937;
1847 break;
1848 case 0x2d:
1849 apb_address = 1938;
1850 break;
1851 case 0x2e:
1852 apb_address = 1939;
1853 break;
1854 case 0x2f:
1855 apb_address = 1940;
1856 break;
1857 case 0x30:
1858 apb_address = 1941;
1859 break;
1860 case 0x31:
1861 apb_address = 1942;
1862 break;
1863 case 0x32:
1864 apb_address = 1943;
1865 break;
1866 case 0x3e:
1867 apb_address = 1944;
1868 break;
1869 case 0x3f:
1870 apb_address = 1945;
1871 break;
1872 case 0x40:
1873 apb_address = 1948;
1874 break;
1875 case 0x25:
1876 apb_address = 914;
1877 break;
1878 case 0x26:
1879 apb_address = 915;
1880 break;
1881 case 0x27:
1882 apb_address = 916;
1883 break;
1884 case 0x28:
1885 apb_address = 917;
1886 break;
1887 case 0x1d:
1888 i = ((dib7000p_read_word(state, 72) >> 12) & 0x3);
1889 word = dib7000p_read_word(state, 384 + i);
1890 msg[1].buf[0] = (word >> 8) & 0xff;
1891 msg[1].buf[1] = (word) & 0xff;
1892 return num;
1893 case 0x1f:
1894 if (num == 1) { /* write */
1895 word = (u16) ((msg[0].buf[1] << 8) | msg[0].buf[2]);
1896 word &= 0x3;
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001897 word = (dib7000p_read_word(state, 72) & ~(3 << 12)) | (word << 12);
Olivier Grenie713d54a2011-01-04 04:54:31 -03001898 dib7000p_write_word(state, 72, word); /* Set the proper input */
1899 return num;
1900 }
1901 }
1902
1903 if (apb_address != 0) /* R/W acces via APB */
1904 return dib7090p_rw_on_apb(i2c_adap, msg, num, apb_address);
1905 else /* R/W access via SERPAR */
1906 return w7090p_tuner_rw_serpar(i2c_adap, msg, num);
1907
1908 return 0;
1909}
1910
1911static u32 dib7000p_i2c_func(struct i2c_adapter *adapter)
1912{
1913 return I2C_FUNC_I2C;
1914}
1915
1916static struct i2c_algorithm dib7090_tuner_xfer_algo = {
1917 .master_xfer = dib7090_tuner_xfer,
1918 .functionality = dib7000p_i2c_func,
1919};
1920
1921struct i2c_adapter *dib7090_get_i2c_tuner(struct dvb_frontend *fe)
1922{
1923 struct dib7000p_state *st = fe->demodulator_priv;
1924 return &st->dib7090_tuner_adap;
1925}
1926EXPORT_SYMBOL(dib7090_get_i2c_tuner);
1927
1928static int dib7090_host_bus_drive(struct dib7000p_state *state, u8 drive)
1929{
1930 u16 reg;
1931
1932 /* drive host bus 2, 3, 4 */
1933 reg = dib7000p_read_word(state, 1798) & ~((0x7) | (0x7 << 6) | (0x7 << 12));
1934 reg |= (drive << 12) | (drive << 6) | drive;
1935 dib7000p_write_word(state, 1798, reg);
1936
1937 /* drive host bus 5,6 */
1938 reg = dib7000p_read_word(state, 1799) & ~((0x7 << 2) | (0x7 << 8));
1939 reg |= (drive << 8) | (drive << 2);
1940 dib7000p_write_word(state, 1799, reg);
1941
1942 /* drive host bus 7, 8, 9 */
1943 reg = dib7000p_read_word(state, 1800) & ~((0x7) | (0x7 << 6) | (0x7 << 12));
1944 reg |= (drive << 12) | (drive << 6) | drive;
1945 dib7000p_write_word(state, 1800, reg);
1946
1947 /* drive host bus 10, 11 */
1948 reg = dib7000p_read_word(state, 1801) & ~((0x7 << 2) | (0x7 << 8));
1949 reg |= (drive << 8) | (drive << 2);
1950 dib7000p_write_word(state, 1801, reg);
1951
1952 /* drive host bus 12, 13, 14 */
1953 reg = dib7000p_read_word(state, 1802) & ~((0x7) | (0x7 << 6) | (0x7 << 12));
1954 reg |= (drive << 12) | (drive << 6) | drive;
1955 dib7000p_write_word(state, 1802, reg);
1956
1957 return 0;
1958}
1959
1960static u32 dib7090_calcSyncFreq(u32 P_Kin, u32 P_Kout, u32 insertExtSynchro, u32 syncSize)
1961{
1962 u32 quantif = 3;
1963 u32 nom = (insertExtSynchro * P_Kin + syncSize);
1964 u32 denom = P_Kout;
1965 u32 syncFreq = ((nom << quantif) / denom);
1966
1967 if ((syncFreq & ((1 << quantif) - 1)) != 0)
1968 syncFreq = (syncFreq >> quantif) + 1;
1969 else
1970 syncFreq = (syncFreq >> quantif);
1971
1972 if (syncFreq != 0)
1973 syncFreq = syncFreq - 1;
1974
1975 return syncFreq;
1976}
1977
1978static int dib7090_cfg_DibTx(struct dib7000p_state *state, u32 P_Kin, u32 P_Kout, u32 insertExtSynchro, u32 synchroMode, u32 syncWord, u32 syncSize)
1979{
1980 u8 index_buf;
1981 u16 rx_copy_buf[22];
1982
1983 dprintk("Configure DibStream Tx");
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001984 for (index_buf = 0; index_buf < 22; index_buf++)
Olivier Grenie713d54a2011-01-04 04:54:31 -03001985 rx_copy_buf[index_buf] = dib7000p_read_word(state, 1536+index_buf);
1986
1987 dib7000p_write_word(state, 1615, 1);
1988 dib7000p_write_word(state, 1603, P_Kin);
1989 dib7000p_write_word(state, 1605, P_Kout);
1990 dib7000p_write_word(state, 1606, insertExtSynchro);
1991 dib7000p_write_word(state, 1608, synchroMode);
1992 dib7000p_write_word(state, 1609, (syncWord >> 16) & 0xffff);
1993 dib7000p_write_word(state, 1610, syncWord & 0xffff);
1994 dib7000p_write_word(state, 1612, syncSize);
1995 dib7000p_write_word(state, 1615, 0);
1996
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001997 for (index_buf = 0; index_buf < 22; index_buf++)
Olivier Grenie713d54a2011-01-04 04:54:31 -03001998 dib7000p_write_word(state, 1536+index_buf, rx_copy_buf[index_buf]);
1999
2000 return 0;
2001}
2002
2003static int dib7090_cfg_DibRx(struct dib7000p_state *state, u32 P_Kin, u32 P_Kout, u32 synchroMode, u32 insertExtSynchro, u32 syncWord, u32 syncSize,
2004 u32 dataOutRate)
2005{
2006 u32 syncFreq;
2007
2008 dprintk("Configure DibStream Rx");
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002009 if ((P_Kin != 0) && (P_Kout != 0)) {
Olivier Grenie713d54a2011-01-04 04:54:31 -03002010 syncFreq = dib7090_calcSyncFreq(P_Kin, P_Kout, insertExtSynchro, syncSize);
2011 dib7000p_write_word(state, 1542, syncFreq);
2012 }
2013 dib7000p_write_word(state, 1554, 1);
2014 dib7000p_write_word(state, 1536, P_Kin);
2015 dib7000p_write_word(state, 1537, P_Kout);
2016 dib7000p_write_word(state, 1539, synchroMode);
2017 dib7000p_write_word(state, 1540, (syncWord >> 16) & 0xffff);
2018 dib7000p_write_word(state, 1541, syncWord & 0xffff);
2019 dib7000p_write_word(state, 1543, syncSize);
2020 dib7000p_write_word(state, 1544, dataOutRate);
2021 dib7000p_write_word(state, 1554, 0);
2022
2023 return 0;
2024}
2025
2026static int dib7090_enDivOnHostBus(struct dib7000p_state *state)
2027{
2028 u16 reg;
2029
2030 dprintk("Enable Diversity on host bus");
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002031 reg = (1 << 8) | (1 << 5);
Olivier Grenie713d54a2011-01-04 04:54:31 -03002032 dib7000p_write_word(state, 1288, reg);
2033
2034 return dib7090_cfg_DibTx(state, 5, 5, 0, 0, 0, 0);
2035}
2036
2037static int dib7090_enAdcOnHostBus(struct dib7000p_state *state)
2038{
2039 u16 reg;
2040
2041 dprintk("Enable ADC on host bus");
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002042 reg = (1 << 7) | (1 << 5);
Olivier Grenie713d54a2011-01-04 04:54:31 -03002043 dib7000p_write_word(state, 1288, reg);
2044
2045 return dib7090_cfg_DibTx(state, 20, 5, 10, 0, 0, 0);
2046}
2047
2048static int dib7090_enMpegOnHostBus(struct dib7000p_state *state)
2049{
2050 u16 reg;
2051
2052 dprintk("Enable Mpeg on host bus");
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002053 reg = (1 << 9) | (1 << 5);
Olivier Grenie713d54a2011-01-04 04:54:31 -03002054 dib7000p_write_word(state, 1288, reg);
2055
2056 return dib7090_cfg_DibTx(state, 8, 5, 0, 0, 0, 0);
2057}
2058
2059static int dib7090_enMpegInput(struct dib7000p_state *state)
2060{
2061 dprintk("Enable Mpeg input");
2062 return dib7090_cfg_DibRx(state, 8, 5, 0, 0, 0, 8, 0); /*outputRate = 8 */
2063}
2064
2065static int dib7090_enMpegMux(struct dib7000p_state *state, u16 pulseWidth, u16 enSerialMode, u16 enSerialClkDiv2)
2066{
2067 u16 reg = (1 << 7) | ((pulseWidth & 0x1f) << 2) | ((enSerialMode & 0x1) << 1) | (enSerialClkDiv2 & 0x1);
2068
2069 dprintk("Enable Mpeg mux");
2070 dib7000p_write_word(state, 1287, reg);
2071
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002072 reg &= ~(1 << 7);
Olivier Grenie713d54a2011-01-04 04:54:31 -03002073 dib7000p_write_word(state, 1287, reg);
2074
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002075 reg = (1 << 4);
Olivier Grenie713d54a2011-01-04 04:54:31 -03002076 dib7000p_write_word(state, 1288, reg);
2077
2078 return 0;
2079}
2080
2081static int dib7090_disableMpegMux(struct dib7000p_state *state)
2082{
2083 u16 reg;
2084
2085 dprintk("Disable Mpeg mux");
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002086 dib7000p_write_word(state, 1288, 0);
Olivier Grenie713d54a2011-01-04 04:54:31 -03002087
2088 reg = dib7000p_read_word(state, 1287);
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002089 reg &= ~(1 << 7);
Olivier Grenie713d54a2011-01-04 04:54:31 -03002090 dib7000p_write_word(state, 1287, reg);
2091
2092 return 0;
2093}
2094
2095static int dib7090_set_input_mode(struct dvb_frontend *fe, int mode)
2096{
2097 struct dib7000p_state *state = fe->demodulator_priv;
2098
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002099 switch (mode) {
2100 case INPUT_MODE_DIVERSITY:
Olivier Grenie713d54a2011-01-04 04:54:31 -03002101 dprintk("Enable diversity INPUT");
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002102 dib7090_cfg_DibRx(state, 5, 5, 0, 0, 0, 0, 0);
Olivier Grenie713d54a2011-01-04 04:54:31 -03002103 break;
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002104 case INPUT_MODE_MPEG:
Olivier Grenie713d54a2011-01-04 04:54:31 -03002105 dprintk("Enable Mpeg INPUT");
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002106 dib7090_cfg_DibRx(state, 8, 5, 0, 0, 0, 8, 0); /*outputRate = 8 */
Olivier Grenie713d54a2011-01-04 04:54:31 -03002107 break;
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002108 case INPUT_MODE_OFF:
2109 default:
Olivier Grenie713d54a2011-01-04 04:54:31 -03002110 dprintk("Disable INPUT");
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002111 dib7090_cfg_DibRx(state, 0, 0, 0, 0, 0, 0, 0);
Olivier Grenie713d54a2011-01-04 04:54:31 -03002112 break;
2113 }
2114 return 0;
2115}
2116
2117static int dib7090_set_diversity_in(struct dvb_frontend *fe, int onoff)
2118{
2119 switch (onoff) {
2120 case 0: /* only use the internal way - not the diversity input */
2121 dib7090_set_input_mode(fe, INPUT_MODE_MPEG);
2122 break;
2123 case 1: /* both ways */
2124 case 2: /* only the diversity input */
2125 dib7090_set_input_mode(fe, INPUT_MODE_DIVERSITY);
2126 break;
2127 }
2128
2129 return 0;
2130}
2131
2132static int dib7090_set_output_mode(struct dvb_frontend *fe, int mode)
2133{
2134 struct dib7000p_state *state = fe->demodulator_priv;
2135
2136 u16 outreg, smo_mode, fifo_threshold;
2137 u8 prefer_mpeg_mux_use = 1;
2138 int ret = 0;
2139
2140 dib7090_host_bus_drive(state, 1);
2141
2142 fifo_threshold = 1792;
2143 smo_mode = (dib7000p_read_word(state, 235) & 0x0050) | (1 << 1);
2144 outreg = dib7000p_read_word(state, 1286) & ~((1 << 10) | (0x7 << 6) | (1 << 1));
2145
2146 switch (mode) {
2147 case OUTMODE_HIGH_Z:
2148 outreg = 0;
2149 break;
2150
2151 case OUTMODE_MPEG2_SERIAL:
2152 if (prefer_mpeg_mux_use) {
2153 dprintk("Sip 7090P setting output mode TS_SERIAL using Mpeg Mux");
2154 dib7090_enMpegOnHostBus(state);
2155 dib7090_enMpegInput(state);
2156 if (state->cfg.enMpegOutput == 1)
2157 dib7090_enMpegMux(state, 3, 1, 1);
2158
2159 } else { /* Use Smooth block */
2160 dprintk("Sip 7090P setting output mode TS_SERIAL using Smooth bloc");
2161 dib7090_disableMpegMux(state);
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002162 dib7000p_write_word(state, 1288, (1 << 6));
Olivier Grenie713d54a2011-01-04 04:54:31 -03002163 outreg |= (2 << 6) | (0 << 1);
2164 }
2165 break;
2166
2167 case OUTMODE_MPEG2_PAR_GATED_CLK:
2168 if (prefer_mpeg_mux_use) {
2169 dprintk("Sip 7090P setting output mode TS_PARALLEL_GATED using Mpeg Mux");
2170 dib7090_enMpegOnHostBus(state);
2171 dib7090_enMpegInput(state);
2172 if (state->cfg.enMpegOutput == 1)
2173 dib7090_enMpegMux(state, 2, 0, 0);
2174 } else { /* Use Smooth block */
2175 dprintk("Sip 7090P setting output mode TS_PARALLEL_GATED using Smooth block");
2176 dib7090_disableMpegMux(state);
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002177 dib7000p_write_word(state, 1288, (1 << 6));
Olivier Grenie713d54a2011-01-04 04:54:31 -03002178 outreg |= (0 << 6);
2179 }
2180 break;
2181
2182 case OUTMODE_MPEG2_PAR_CONT_CLK: /* Using Smooth block only */
2183 dprintk("Sip 7090P setting output mode TS_PARALLEL_CONT using Smooth block");
2184 dib7090_disableMpegMux(state);
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002185 dib7000p_write_word(state, 1288, (1 << 6));
Olivier Grenie713d54a2011-01-04 04:54:31 -03002186 outreg |= (1 << 6);
2187 break;
2188
2189 case OUTMODE_MPEG2_FIFO: /* Using Smooth block because not supported by new Mpeg Mux bloc */
2190 dprintk("Sip 7090P setting output mode TS_FIFO using Smooth block");
2191 dib7090_disableMpegMux(state);
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002192 dib7000p_write_word(state, 1288, (1 << 6));
Olivier Grenie713d54a2011-01-04 04:54:31 -03002193 outreg |= (5 << 6);
2194 smo_mode |= (3 << 1);
2195 fifo_threshold = 512;
2196 break;
2197
2198 case OUTMODE_DIVERSITY:
2199 dprintk("Sip 7090P setting output mode MODE_DIVERSITY");
2200 dib7090_disableMpegMux(state);
2201 dib7090_enDivOnHostBus(state);
2202 break;
2203
2204 case OUTMODE_ANALOG_ADC:
2205 dprintk("Sip 7090P setting output mode MODE_ANALOG_ADC");
2206 dib7090_enAdcOnHostBus(state);
2207 break;
2208 }
2209
2210 if (state->cfg.output_mpeg2_in_188_bytes)
2211 smo_mode |= (1 << 5);
2212
2213 ret |= dib7000p_write_word(state, 235, smo_mode);
2214 ret |= dib7000p_write_word(state, 236, fifo_threshold); /* synchronous fread */
2215 ret |= dib7000p_write_word(state, 1286, outreg | (1 << 10)); /* allways set Dout active = 1 !!! */
2216
2217 return ret;
2218}
2219
2220int dib7090_tuner_sleep(struct dvb_frontend *fe, int onoff)
2221{
2222 struct dib7000p_state *state = fe->demodulator_priv;
2223 u16 en_cur_state;
2224
2225 dprintk("sleep dib7090: %d", onoff);
2226
2227 en_cur_state = dib7000p_read_word(state, 1922);
2228
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002229 if (en_cur_state > 0xff)
Olivier Grenie713d54a2011-01-04 04:54:31 -03002230 state->tuner_enable = en_cur_state;
Olivier Grenie713d54a2011-01-04 04:54:31 -03002231
2232 if (onoff)
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002233 en_cur_state &= 0x00ff;
Olivier Grenie713d54a2011-01-04 04:54:31 -03002234 else {
2235 if (state->tuner_enable != 0)
2236 en_cur_state = state->tuner_enable;
2237 }
2238
2239 dib7000p_write_word(state, 1922, en_cur_state);
2240
2241 return 0;
2242}
2243EXPORT_SYMBOL(dib7090_tuner_sleep);
2244
2245int dib7090_agc_restart(struct dvb_frontend *fe, u8 restart)
2246{
2247 dprintk("AGC restart callback: %d", restart);
2248 return 0;
2249}
2250EXPORT_SYMBOL(dib7090_agc_restart);
2251
2252int dib7090_get_adc_power(struct dvb_frontend *fe)
2253{
2254 return dib7000p_get_adc_power(fe);
2255}
2256EXPORT_SYMBOL(dib7090_get_adc_power);
2257
2258int dib7090_slave_reset(struct dvb_frontend *fe)
2259{
2260 struct dib7000p_state *state = fe->demodulator_priv;
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002261 u16 reg;
Olivier Grenie713d54a2011-01-04 04:54:31 -03002262
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002263 reg = dib7000p_read_word(state, 1794);
2264 dib7000p_write_word(state, 1794, reg | (4 << 12));
Olivier Grenie713d54a2011-01-04 04:54:31 -03002265
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002266 dib7000p_write_word(state, 1032, 0xffff);
2267 return 0;
Olivier Grenie713d54a2011-01-04 04:54:31 -03002268}
2269EXPORT_SYMBOL(dib7090_slave_reset);
2270
Patrick Boettchera75763f2006-10-18 08:34:16 -03002271static struct dvb_frontend_ops dib7000p_ops;
Olivier Grenie713d54a2011-01-04 04:54:31 -03002272struct dvb_frontend *dib7000p_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr, struct dib7000p_config *cfg)
Patrick Boettchera75763f2006-10-18 08:34:16 -03002273{
2274 struct dvb_frontend *demod;
2275 struct dib7000p_state *st;
2276 st = kzalloc(sizeof(struct dib7000p_state), GFP_KERNEL);
2277 if (st == NULL)
2278 return NULL;
2279
2280 memcpy(&st->cfg, cfg, sizeof(struct dib7000p_config));
2281 st->i2c_adap = i2c_adap;
2282 st->i2c_addr = i2c_addr;
2283 st->gpio_val = cfg->gpio_val;
2284 st->gpio_dir = cfg->gpio_dir;
2285
Steven Totha38d6e32008-04-22 15:37:01 -03002286 /* Ensure the output mode remains at the previous default if it's
2287 * not specifically set by the caller.
2288 */
Olivier Grenie713d54a2011-01-04 04:54:31 -03002289 if ((st->cfg.output_mode != OUTMODE_MPEG2_SERIAL) && (st->cfg.output_mode != OUTMODE_MPEG2_PAR_GATED_CLK))
Steven Totha38d6e32008-04-22 15:37:01 -03002290 st->cfg.output_mode = OUTMODE_MPEG2_FIFO;
2291
Olivier Grenie713d54a2011-01-04 04:54:31 -03002292 demod = &st->demod;
Patrick Boettchera75763f2006-10-18 08:34:16 -03002293 demod->demodulator_priv = st;
2294 memcpy(&st->demod.ops, &dib7000p_ops, sizeof(struct dvb_frontend_ops));
2295
Olivier Grenie713d54a2011-01-04 04:54:31 -03002296 dib7000p_write_word(st, 1287, 0x0003); /* sram lead in, rdy */
Olivier Grenieeac1fe12009-09-23 13:41:27 -03002297
Patrick Boettchera75763f2006-10-18 08:34:16 -03002298 if (dib7000p_identify(st) != 0)
2299 goto error;
2300
Olivier Grenie713d54a2011-01-04 04:54:31 -03002301 st->version = dib7000p_read_word(st, 897);
2302
Martin Samek7646b9d2009-09-30 22:59:09 -03002303 /* FIXME: make sure the dev.parent field is initialized, or else
Olivier Grenie713d54a2011-01-04 04:54:31 -03002304 request_firmware() will hit an OOPS (this should be moved somewhere
2305 more common) */
Martin Samek7646b9d2009-09-30 22:59:09 -03002306
Patrick Boettchera75763f2006-10-18 08:34:16 -03002307 dibx000_init_i2c_master(&st->i2c_master, DIB7000P, st->i2c_adap, st->i2c_addr);
2308
Olivier Grenie713d54a2011-01-04 04:54:31 -03002309 /* init 7090 tuner adapter */
2310 strncpy(st->dib7090_tuner_adap.name, "DiB7090 tuner interface", sizeof(st->dib7090_tuner_adap.name));
2311 st->dib7090_tuner_adap.algo = &dib7090_tuner_xfer_algo;
2312 st->dib7090_tuner_adap.algo_data = NULL;
2313 st->dib7090_tuner_adap.dev.parent = st->i2c_adap->dev.parent;
2314 i2c_set_adapdata(&st->dib7090_tuner_adap, st);
2315 i2c_add_adapter(&st->dib7090_tuner_adap);
2316
Patrick Boettchera75763f2006-10-18 08:34:16 -03002317 dib7000p_demod_reset(st);
2318
Olivier Grenie713d54a2011-01-04 04:54:31 -03002319 if (st->version == SOC7090) {
2320 dib7090_set_output_mode(demod, st->cfg.output_mode);
2321 dib7090_set_diversity_in(demod, 0);
2322 }
2323
Patrick Boettchera75763f2006-10-18 08:34:16 -03002324 return demod;
2325
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002326error:
Patrick Boettchera75763f2006-10-18 08:34:16 -03002327 kfree(st);
2328 return NULL;
2329}
2330EXPORT_SYMBOL(dib7000p_attach);
2331
2332static struct dvb_frontend_ops dib7000p_ops = {
2333 .info = {
Olivier Grenie713d54a2011-01-04 04:54:31 -03002334 .name = "DiBcom 7000PC",
2335 .type = FE_OFDM,
2336 .frequency_min = 44250000,
2337 .frequency_max = 867250000,
2338 .frequency_stepsize = 62500,
2339 .caps = FE_CAN_INVERSION_AUTO |
2340 FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
2341 FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
2342 FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO |
2343 FE_CAN_TRANSMISSION_MODE_AUTO | FE_CAN_GUARD_INTERVAL_AUTO | FE_CAN_RECOVER | FE_CAN_HIERARCHY_AUTO,
2344 },
Patrick Boettchera75763f2006-10-18 08:34:16 -03002345
Olivier Grenie713d54a2011-01-04 04:54:31 -03002346 .release = dib7000p_release,
Patrick Boettchera75763f2006-10-18 08:34:16 -03002347
Olivier Grenie713d54a2011-01-04 04:54:31 -03002348 .init = dib7000p_wakeup,
2349 .sleep = dib7000p_sleep,
Patrick Boettchera75763f2006-10-18 08:34:16 -03002350
Olivier Grenie713d54a2011-01-04 04:54:31 -03002351 .set_frontend = dib7000p_set_frontend,
2352 .get_tune_settings = dib7000p_fe_get_tune_settings,
2353 .get_frontend = dib7000p_get_frontend,
Patrick Boettchera75763f2006-10-18 08:34:16 -03002354
Olivier Grenie713d54a2011-01-04 04:54:31 -03002355 .read_status = dib7000p_read_status,
2356 .read_ber = dib7000p_read_ber,
Patrick Boettchera75763f2006-10-18 08:34:16 -03002357 .read_signal_strength = dib7000p_read_signal_strength,
Olivier Grenie713d54a2011-01-04 04:54:31 -03002358 .read_snr = dib7000p_read_snr,
2359 .read_ucblocks = dib7000p_read_unc_blocks,
Patrick Boettchera75763f2006-10-18 08:34:16 -03002360};
2361
Olivier Grenie713d54a2011-01-04 04:54:31 -03002362MODULE_AUTHOR("Olivier Grenie <ogrenie@dibcom.fr>");
Patrick Boettchera75763f2006-10-18 08:34:16 -03002363MODULE_AUTHOR("Patrick Boettcher <pboettcher@dibcom.fr>");
2364MODULE_DESCRIPTION("Driver for the DiBcom 7000PC COFDM demodulator");
2365MODULE_LICENSE("GPL");