blob: c92c1a0d7472369922d64268482157b07d23aed3 [file] [log] [blame]
Patrick Boettchera75763f2006-10-18 08:34:16 -03001/*
2 * Linux-DVB Driver for DiBcom's second generation DiB7000P (PC).
3 *
Patrick Boettcherb6884a12007-07-27 10:08:51 -03004 * Copyright (C) 2005-7 DiBcom (http://www.dibcom.fr/)
Patrick Boettchera75763f2006-10-18 08:34:16 -03005 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License as
8 * published by the Free Software Foundation, version 2.
9 */
10#include <linux/kernel.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090011#include <linux/slab.h>
Patrick Boettchera75763f2006-10-18 08:34:16 -030012#include <linux/i2c.h>
Patrick Boettcher79fcce32011-08-03 12:08:21 -030013#include <linux/mutex.h>
Patrick Boettchera75763f2006-10-18 08:34:16 -030014
Olivier Grenieef801962009-09-15 06:46:52 -030015#include "dvb_math.h"
Patrick Boettchera75763f2006-10-18 08:34:16 -030016#include "dvb_frontend.h"
17
18#include "dib7000p.h"
19
20static int debug;
21module_param(debug, int, 0644);
22MODULE_PARM_DESC(debug, "turn on debugging (default: 0)");
23
Matt Doran8f6956c2007-07-31 07:09:30 -030024static int buggy_sfn_workaround;
25module_param(buggy_sfn_workaround, int, 0644);
Patrick Boettcher8d999962007-07-31 10:36:06 -030026MODULE_PARM_DESC(buggy_sfn_workaround, "Enable work-around for buggy SFNs (default: 0)");
Matt Doran8f6956c2007-07-31 07:09:30 -030027
Patrick Boettcherb6884a12007-07-27 10:08:51 -030028#define dprintk(args...) do { if (debug) { printk(KERN_DEBUG "DiB7000P: "); printk(args); printk("\n"); } } while (0)
Patrick Boettchera75763f2006-10-18 08:34:16 -030029
Olivier Grenie713d54a2011-01-04 04:54:31 -030030struct i2c_device {
31 struct i2c_adapter *i2c_adap;
32 u8 i2c_addr;
33};
34
Patrick Boettchera75763f2006-10-18 08:34:16 -030035struct dib7000p_state {
36 struct dvb_frontend demod;
Olivier Grenie713d54a2011-01-04 04:54:31 -030037 struct dib7000p_config cfg;
Patrick Boettchera75763f2006-10-18 08:34:16 -030038
39 u8 i2c_addr;
Olivier Grenie713d54a2011-01-04 04:54:31 -030040 struct i2c_adapter *i2c_adap;
Patrick Boettchera75763f2006-10-18 08:34:16 -030041
42 struct dibx000_i2c_master i2c_master;
43
44 u16 wbd_ref;
45
Olivier Grenie713d54a2011-01-04 04:54:31 -030046 u8 current_band;
Patrick Boettcher904a82e2008-01-25 07:31:58 -030047 u32 current_bandwidth;
Patrick Boettchera75763f2006-10-18 08:34:16 -030048 struct dibx000_agc_config *current_agc;
49 u32 timf;
50
Olivier Grenie713d54a2011-01-04 04:54:31 -030051 u8 div_force_off:1;
52 u8 div_state:1;
Patrick Boettcher01373a52007-07-30 12:49:04 -030053 u16 div_sync_wait;
Patrick Boettcherb6884a12007-07-27 10:08:51 -030054
55 u8 agc_state;
56
Patrick Boettchera75763f2006-10-18 08:34:16 -030057 u16 gpio_dir;
58 u16 gpio_val;
Matt Doran8f6956c2007-07-31 07:09:30 -030059
Olivier Grenie713d54a2011-01-04 04:54:31 -030060 u8 sfn_workaround_active:1;
61
62#define SOC7090 0x7090
63 u16 version;
64
65 u16 tuner_enable;
66 struct i2c_adapter dib7090_tuner_adap;
Olivier Grenie5a0deee2011-05-03 12:27:33 -030067
68 /* for the I2C transfer */
69 struct i2c_msg msg[2];
70 u8 i2c_write_buffer[4];
71 u8 i2c_read_buffer[2];
Patrick Boettcher79fcce32011-08-03 12:08:21 -030072 struct mutex i2c_buffer_lock;
Olivier Grenie2e802862011-08-05 10:39:15 -030073
74 u8 input_mode_mpeg;
Patrick Boettchera75763f2006-10-18 08:34:16 -030075};
76
77enum dib7000p_power_mode {
78 DIB7000P_POWER_ALL = 0,
Patrick Boettcherb6884a12007-07-27 10:08:51 -030079 DIB7000P_POWER_ANALOG_ADC,
Patrick Boettchera75763f2006-10-18 08:34:16 -030080 DIB7000P_POWER_INTERFACE_ONLY,
81};
82
Olivier Grenie2e802862011-08-05 10:39:15 -030083/* dib7090 specific fonctions */
Olivier Grenie713d54a2011-01-04 04:54:31 -030084static int dib7090_set_output_mode(struct dvb_frontend *fe, int mode);
85static int dib7090_set_diversity_in(struct dvb_frontend *fe, int onoff);
Olivier Grenie2e802862011-08-05 10:39:15 -030086static void dib7090_setDibTxMux(struct dib7000p_state *state, int mode);
87static void dib7090_setHostBusMux(struct dib7000p_state *state, int mode);
Olivier Grenie713d54a2011-01-04 04:54:31 -030088
Patrick Boettchera75763f2006-10-18 08:34:16 -030089static u16 dib7000p_read_word(struct dib7000p_state *state, u16 reg)
90{
Patrick Boettcher79fcce32011-08-03 12:08:21 -030091 u16 ret;
92
93 if (mutex_lock_interruptible(&state->i2c_buffer_lock) < 0) {
94 dprintk("could not acquire lock");
95 return 0;
96 }
97
Olivier Grenie5a0deee2011-05-03 12:27:33 -030098 state->i2c_write_buffer[0] = reg >> 8;
99 state->i2c_write_buffer[1] = reg & 0xff;
Patrick Boettchera75763f2006-10-18 08:34:16 -0300100
Olivier Grenie5a0deee2011-05-03 12:27:33 -0300101 memset(state->msg, 0, 2 * sizeof(struct i2c_msg));
102 state->msg[0].addr = state->i2c_addr >> 1;
103 state->msg[0].flags = 0;
104 state->msg[0].buf = state->i2c_write_buffer;
105 state->msg[0].len = 2;
106 state->msg[1].addr = state->i2c_addr >> 1;
107 state->msg[1].flags = I2C_M_RD;
108 state->msg[1].buf = state->i2c_read_buffer;
109 state->msg[1].len = 2;
110
111 if (i2c_transfer(state->i2c_adap, state->msg, 2) != 2)
Olivier Grenie713d54a2011-01-04 04:54:31 -0300112 dprintk("i2c read error on %d", reg);
Patrick Boettchera75763f2006-10-18 08:34:16 -0300113
Patrick Boettcher79fcce32011-08-03 12:08:21 -0300114 ret = (state->i2c_read_buffer[0] << 8) | state->i2c_read_buffer[1];
115 mutex_unlock(&state->i2c_buffer_lock);
116 return ret;
Patrick Boettchera75763f2006-10-18 08:34:16 -0300117}
118
119static int dib7000p_write_word(struct dib7000p_state *state, u16 reg, u16 val)
120{
Patrick Boettcher79fcce32011-08-03 12:08:21 -0300121 int ret;
122
123 if (mutex_lock_interruptible(&state->i2c_buffer_lock) < 0) {
124 dprintk("could not acquire lock");
125 return -EINVAL;
126 }
127
Olivier Grenie5a0deee2011-05-03 12:27:33 -0300128 state->i2c_write_buffer[0] = (reg >> 8) & 0xff;
129 state->i2c_write_buffer[1] = reg & 0xff;
130 state->i2c_write_buffer[2] = (val >> 8) & 0xff;
131 state->i2c_write_buffer[3] = val & 0xff;
132
133 memset(&state->msg[0], 0, sizeof(struct i2c_msg));
134 state->msg[0].addr = state->i2c_addr >> 1;
135 state->msg[0].flags = 0;
136 state->msg[0].buf = state->i2c_write_buffer;
137 state->msg[0].len = 4;
138
Patrick Boettcher79fcce32011-08-03 12:08:21 -0300139 ret = (i2c_transfer(state->i2c_adap, state->msg, 1) != 1 ?
140 -EREMOTEIO : 0);
141 mutex_unlock(&state->i2c_buffer_lock);
142 return ret;
Patrick Boettchera75763f2006-10-18 08:34:16 -0300143}
Olivier Grenie713d54a2011-01-04 04:54:31 -0300144
145static void dib7000p_write_tab(struct dib7000p_state *state, u16 * buf)
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300146{
147 u16 l = 0, r, *n;
148 n = buf;
149 l = *n++;
150 while (l) {
151 r = *n++;
152
153 do {
154 dib7000p_write_word(state, r, *n++);
155 r++;
156 } while (--l);
157 l = *n++;
158 }
159}
160
Patrick Boettchera75763f2006-10-18 08:34:16 -0300161static int dib7000p_set_output_mode(struct dib7000p_state *state, int mode)
162{
Olivier Grenie713d54a2011-01-04 04:54:31 -0300163 int ret = 0;
Patrick Boettchera75763f2006-10-18 08:34:16 -0300164 u16 outreg, fifo_threshold, smo_mode;
165
166 outreg = 0;
167 fifo_threshold = 1792;
Olivier Grenieeac1fe12009-09-23 13:41:27 -0300168 smo_mode = (dib7000p_read_word(state, 235) & 0x0050) | (1 << 1);
Patrick Boettchera75763f2006-10-18 08:34:16 -0300169
Olivier Grenie713d54a2011-01-04 04:54:31 -0300170 dprintk("setting output mode for demod %p to %d", &state->demod, mode);
Patrick Boettchera75763f2006-10-18 08:34:16 -0300171
172 switch (mode) {
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300173 case OUTMODE_MPEG2_PAR_GATED_CLK:
Olivier Grenie713d54a2011-01-04 04:54:31 -0300174 outreg = (1 << 10); /* 0x0400 */
175 break;
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300176 case OUTMODE_MPEG2_PAR_CONT_CLK:
Olivier Grenie713d54a2011-01-04 04:54:31 -0300177 outreg = (1 << 10) | (1 << 6); /* 0x0440 */
178 break;
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300179 case OUTMODE_MPEG2_SERIAL:
Olivier Grenie713d54a2011-01-04 04:54:31 -0300180 outreg = (1 << 10) | (2 << 6) | (0 << 1); /* 0x0480 */
181 break;
182 case OUTMODE_DIVERSITY:
183 if (state->cfg.hostbus_diversity)
184 outreg = (1 << 10) | (4 << 6); /* 0x0500 */
185 else
186 outreg = (1 << 11);
187 break;
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300188 case OUTMODE_MPEG2_FIFO:
Olivier Grenie713d54a2011-01-04 04:54:31 -0300189 smo_mode |= (3 << 1);
190 fifo_threshold = 512;
191 outreg = (1 << 10) | (5 << 6);
192 break;
193 case OUTMODE_ANALOG_ADC:
194 outreg = (1 << 10) | (3 << 6);
195 break;
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300196 case OUTMODE_HIGH_Z:
Olivier Grenie713d54a2011-01-04 04:54:31 -0300197 outreg = 0;
198 break;
199 default:
200 dprintk("Unhandled output_mode passed to be set for demod %p", &state->demod);
201 break;
Patrick Boettchera75763f2006-10-18 08:34:16 -0300202 }
203
204 if (state->cfg.output_mpeg2_in_188_bytes)
Olivier Grenie713d54a2011-01-04 04:54:31 -0300205 smo_mode |= (1 << 5);
Patrick Boettchera75763f2006-10-18 08:34:16 -0300206
Olivier Grenie713d54a2011-01-04 04:54:31 -0300207 ret |= dib7000p_write_word(state, 235, smo_mode);
208 ret |= dib7000p_write_word(state, 236, fifo_threshold); /* synchronous fread */
209 if (state->version != SOC7090)
210 ret |= dib7000p_write_word(state, 1286, outreg); /* P_Div_active */
Patrick Boettchera75763f2006-10-18 08:34:16 -0300211
212 return ret;
213}
214
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300215static int dib7000p_set_diversity_in(struct dvb_frontend *demod, int onoff)
216{
217 struct dib7000p_state *state = demod->demodulator_priv;
218
219 if (state->div_force_off) {
Olivier Grenie713d54a2011-01-04 04:54:31 -0300220 dprintk("diversity combination deactivated - forced by COFDM parameters");
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300221 onoff = 0;
Olivier Grenieeac1fe12009-09-23 13:41:27 -0300222 dib7000p_write_word(state, 207, 0);
223 } else
224 dib7000p_write_word(state, 207, (state->div_sync_wait << 4) | (1 << 2) | (2 << 0));
225
Olivier Grenie713d54a2011-01-04 04:54:31 -0300226 state->div_state = (u8) onoff;
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300227
228 if (onoff) {
229 dib7000p_write_word(state, 204, 6);
230 dib7000p_write_word(state, 205, 16);
231 /* P_dvsy_sync_mode = 0, P_dvsy_sync_enable=1, P_dvcb_comb_mode=2 */
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300232 } else {
233 dib7000p_write_word(state, 204, 1);
234 dib7000p_write_word(state, 205, 0);
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300235 }
236
237 return 0;
238}
239
Patrick Boettchera75763f2006-10-18 08:34:16 -0300240static int dib7000p_set_power_mode(struct dib7000p_state *state, enum dib7000p_power_mode mode)
241{
242 /* by default everything is powered off */
Olivier Grenie713d54a2011-01-04 04:54:31 -0300243 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 -0300244
245 /* now, depending on the requested mode, we power on */
246 switch (mode) {
247 /* power up everything in the demod */
Olivier Grenie713d54a2011-01-04 04:54:31 -0300248 case DIB7000P_POWER_ALL:
249 reg_774 = 0x0000;
250 reg_775 = 0x0000;
251 reg_776 = 0x0;
252 reg_899 = 0x0;
253 if (state->version == SOC7090)
254 reg_1280 &= 0x001f;
255 else
256 reg_1280 &= 0x01ff;
257 break;
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300258
Olivier Grenie713d54a2011-01-04 04:54:31 -0300259 case DIB7000P_POWER_ANALOG_ADC:
260 /* dem, cfg, iqc, sad, agc */
261 reg_774 &= ~((1 << 15) | (1 << 14) | (1 << 11) | (1 << 10) | (1 << 9));
262 /* nud */
263 reg_776 &= ~((1 << 0));
264 /* Dout */
265 if (state->version != SOC7090)
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300266 reg_1280 &= ~((1 << 11));
Olivier Grenie713d54a2011-01-04 04:54:31 -0300267 reg_1280 &= ~(1 << 6);
268 /* fall through wanted to enable the interfaces */
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300269
Patrick Boettchera75763f2006-10-18 08:34:16 -0300270 /* just leave power on the control-interfaces: GPIO and (I2C or SDIO) */
Olivier Grenie713d54a2011-01-04 04:54:31 -0300271 case DIB7000P_POWER_INTERFACE_ONLY: /* TODO power up either SDIO or I2C */
272 if (state->version == SOC7090)
273 reg_1280 &= ~((1 << 7) | (1 << 5));
274 else
Patrick Boettchera75763f2006-10-18 08:34:16 -0300275 reg_1280 &= ~((1 << 14) | (1 << 13) | (1 << 12) | (1 << 10));
Olivier Grenie713d54a2011-01-04 04:54:31 -0300276 break;
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300277
Patrick Boettchera75763f2006-10-18 08:34:16 -0300278/* TODO following stuff is just converted from the dib7000-driver - check when is used what */
279 }
280
Olivier Grenie713d54a2011-01-04 04:54:31 -0300281 dib7000p_write_word(state, 774, reg_774);
282 dib7000p_write_word(state, 775, reg_775);
283 dib7000p_write_word(state, 776, reg_776);
Patrick Boettchera75763f2006-10-18 08:34:16 -0300284 dib7000p_write_word(state, 1280, reg_1280);
Olivier Grenie2e802862011-08-05 10:39:15 -0300285 if (state->version != SOC7090)
286 dib7000p_write_word(state, 899, reg_899);
Patrick Boettchera75763f2006-10-18 08:34:16 -0300287
288 return 0;
289}
290
291static void dib7000p_set_adc_state(struct dib7000p_state *state, enum dibx000_adc_states no)
292{
Olivier Grenie2e802862011-08-05 10:39:15 -0300293 u16 reg_908 = 0, reg_909 = 0;
Olivier Grenie713d54a2011-01-04 04:54:31 -0300294 u16 reg;
Patrick Boettchera75763f2006-10-18 08:34:16 -0300295
Olivier Grenie2e802862011-08-05 10:39:15 -0300296 if (state->version != SOC7090) {
297 reg_908 = dib7000p_read_word(state, 908);
298 reg_909 = dib7000p_read_word(state, 909);
299 }
300
Patrick Boettchera75763f2006-10-18 08:34:16 -0300301 switch (no) {
Olivier Grenie713d54a2011-01-04 04:54:31 -0300302 case DIBX000_SLOW_ADC_ON:
303 if (state->version == SOC7090) {
304 reg = dib7000p_read_word(state, 1925);
305
306 dib7000p_write_word(state, 1925, reg | (1 << 4) | (1 << 2)); /* en_slowAdc = 1 & reset_sladc = 1 */
307
308 reg = dib7000p_read_word(state, 1925); /* read acces to make it works... strange ... */
309 msleep(200);
310 dib7000p_write_word(state, 1925, reg & ~(1 << 4)); /* en_slowAdc = 1 & reset_sladc = 0 */
311
312 reg = dib7000p_read_word(state, 72) & ~((0x3 << 14) | (0x3 << 12));
313 dib7000p_write_word(state, 72, reg | (1 << 14) | (3 << 12) | 524); /* ref = Vin1 => Vbg ; sel = Vin0 or Vin3 ; (Vin2 = Vcm) */
314 } else {
Patrick Boettchera75763f2006-10-18 08:34:16 -0300315 reg_909 |= (1 << 1) | (1 << 0);
316 dib7000p_write_word(state, 909, reg_909);
317 reg_909 &= ~(1 << 1);
Olivier Grenie713d54a2011-01-04 04:54:31 -0300318 }
319 break;
Patrick Boettchera75763f2006-10-18 08:34:16 -0300320
Olivier Grenie713d54a2011-01-04 04:54:31 -0300321 case DIBX000_SLOW_ADC_OFF:
322 if (state->version == SOC7090) {
323 reg = dib7000p_read_word(state, 1925);
324 dib7000p_write_word(state, 1925, (reg & ~(1 << 2)) | (1 << 4)); /* reset_sladc = 1 en_slowAdc = 0 */
325 } else
326 reg_909 |= (1 << 1) | (1 << 0);
327 break;
Patrick Boettchera75763f2006-10-18 08:34:16 -0300328
Olivier Grenie713d54a2011-01-04 04:54:31 -0300329 case DIBX000_ADC_ON:
330 reg_908 &= 0x0fff;
331 reg_909 &= 0x0003;
332 break;
Patrick Boettchera75763f2006-10-18 08:34:16 -0300333
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300334 case DIBX000_ADC_OFF:
Olivier Grenie713d54a2011-01-04 04:54:31 -0300335 reg_908 |= (1 << 14) | (1 << 13) | (1 << 12);
336 reg_909 |= (1 << 5) | (1 << 4) | (1 << 3) | (1 << 2);
337 break;
Patrick Boettchera75763f2006-10-18 08:34:16 -0300338
Olivier Grenie713d54a2011-01-04 04:54:31 -0300339 case DIBX000_VBG_ENABLE:
340 reg_908 &= ~(1 << 15);
341 break;
Patrick Boettchera75763f2006-10-18 08:34:16 -0300342
Olivier Grenie713d54a2011-01-04 04:54:31 -0300343 case DIBX000_VBG_DISABLE:
344 reg_908 |= (1 << 15);
345 break;
Patrick Boettchera75763f2006-10-18 08:34:16 -0300346
Olivier Grenie713d54a2011-01-04 04:54:31 -0300347 default:
348 break;
Patrick Boettchera75763f2006-10-18 08:34:16 -0300349 }
350
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300351// dprintk( "908: %x, 909: %x\n", reg_908, reg_909);
Patrick Boettchera75763f2006-10-18 08:34:16 -0300352
Olivier Grenie970d14c2010-09-07 12:50:46 -0300353 reg_909 |= (state->cfg.disable_sample_and_hold & 1) << 4;
Olivier Grenie90e12ce2010-09-07 12:50:45 -0300354 reg_908 |= (state->cfg.enable_current_mirror & 1) << 7;
355
Olivier Grenie2e802862011-08-05 10:39:15 -0300356 if (state->version != SOC7090) {
357 dib7000p_write_word(state, 908, reg_908);
358 dib7000p_write_word(state, 909, reg_909);
359 }
Patrick Boettchera75763f2006-10-18 08:34:16 -0300360}
361
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300362static int dib7000p_set_bandwidth(struct dib7000p_state *state, u32 bw)
Patrick Boettchera75763f2006-10-18 08:34:16 -0300363{
Patrick Boettchera75763f2006-10-18 08:34:16 -0300364 u32 timf;
365
366 // store the current bandwidth for later use
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300367 state->current_bandwidth = bw;
Patrick Boettchera75763f2006-10-18 08:34:16 -0300368
369 if (state->timf == 0) {
Olivier Grenie713d54a2011-01-04 04:54:31 -0300370 dprintk("using default timf");
Patrick Boettchera75763f2006-10-18 08:34:16 -0300371 timf = state->cfg.bw->timf;
372 } else {
Olivier Grenie713d54a2011-01-04 04:54:31 -0300373 dprintk("using updated timf");
Patrick Boettchera75763f2006-10-18 08:34:16 -0300374 timf = state->timf;
375 }
376
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300377 timf = timf * (bw / 50) / 160;
Patrick Boettchera75763f2006-10-18 08:34:16 -0300378
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300379 dib7000p_write_word(state, 23, (u16) ((timf >> 16) & 0xffff));
Olivier Grenie713d54a2011-01-04 04:54:31 -0300380 dib7000p_write_word(state, 24, (u16) ((timf) & 0xffff));
Patrick Boettchera75763f2006-10-18 08:34:16 -0300381
382 return 0;
383}
384
385static int dib7000p_sad_calib(struct dib7000p_state *state)
386{
387/* internal */
Patrick Boettchera75763f2006-10-18 08:34:16 -0300388 dib7000p_write_word(state, 73, (0 << 1) | (0 << 0));
Olivier Grenie713d54a2011-01-04 04:54:31 -0300389
390 if (state->version == SOC7090)
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300391 dib7000p_write_word(state, 74, 2048);
Olivier Grenie713d54a2011-01-04 04:54:31 -0300392 else
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300393 dib7000p_write_word(state, 74, 776);
Patrick Boettchera75763f2006-10-18 08:34:16 -0300394
395 /* do the calibration */
396 dib7000p_write_word(state, 73, (1 << 0));
397 dib7000p_write_word(state, 73, (0 << 0));
398
399 msleep(1);
400
401 return 0;
402}
403
Patrick Boettcher01373a52007-07-30 12:49:04 -0300404int dib7000p_set_wbd_ref(struct dvb_frontend *demod, u16 value)
405{
406 struct dib7000p_state *state = demod->demodulator_priv;
407 if (value > 4095)
408 value = 4095;
409 state->wbd_ref = value;
410 return dib7000p_write_word(state, 105, (dib7000p_read_word(state, 105) & 0xf000) | value);
411}
Patrick Boettcher01373a52007-07-30 12:49:04 -0300412EXPORT_SYMBOL(dib7000p_set_wbd_ref);
Olivier Grenie713d54a2011-01-04 04:54:31 -0300413
Olivier Grenie6724a2f2011-08-05 13:49:33 -0300414int dib7000p_get_agc_values(struct dvb_frontend *fe,
415 u16 *agc_global, u16 *agc1, u16 *agc2, u16 *wbd)
416{
417 struct dib7000p_state *state = fe->demodulator_priv;
418
419 if (agc_global != NULL)
420 *agc_global = dib7000p_read_word(state, 394);
421 if (agc1 != NULL)
422 *agc1 = dib7000p_read_word(state, 392);
423 if (agc2 != NULL)
424 *agc2 = dib7000p_read_word(state, 393);
425 if (wbd != NULL)
426 *wbd = dib7000p_read_word(state, 397);
427
428 return 0;
429}
430EXPORT_SYMBOL(dib7000p_get_agc_values);
431
Patrick Boettchera75763f2006-10-18 08:34:16 -0300432static void dib7000p_reset_pll(struct dib7000p_state *state)
433{
434 struct dibx000_bandwidth_config *bw = &state->cfg.bw[0];
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300435 u16 clk_cfg0;
Patrick Boettchera75763f2006-10-18 08:34:16 -0300436
Olivier Grenie713d54a2011-01-04 04:54:31 -0300437 if (state->version == SOC7090) {
438 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 -0300439
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300440 while (((dib7000p_read_word(state, 1856) >> 15) & 0x1) != 1)
441 ;
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300442
Olivier Grenie713d54a2011-01-04 04:54:31 -0300443 dib7000p_write_word(state, 1857, dib7000p_read_word(state, 1857) | (!bw->pll_bypass << 15));
444 } else {
445 /* force PLL bypass */
446 clk_cfg0 = (1 << 15) | ((bw->pll_ratio & 0x3f) << 9) |
447 (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 -0300448
Olivier Grenie713d54a2011-01-04 04:54:31 -0300449 dib7000p_write_word(state, 900, clk_cfg0);
450
451 /* P_pll_cfg */
452 dib7000p_write_word(state, 903, (bw->pll_prediv << 5) | (((bw->pll_ratio >> 6) & 0x3) << 3) | (bw->pll_range << 1) | bw->pll_reset);
453 clk_cfg0 = (bw->pll_bypass << 15) | (clk_cfg0 & 0x7fff);
454 dib7000p_write_word(state, 900, clk_cfg0);
455 }
456
457 dib7000p_write_word(state, 18, (u16) (((bw->internal * 1000) >> 16) & 0xffff));
458 dib7000p_write_word(state, 19, (u16) ((bw->internal * 1000) & 0xffff));
459 dib7000p_write_word(state, 21, (u16) ((bw->ifreq >> 16) & 0xffff));
460 dib7000p_write_word(state, 22, (u16) ((bw->ifreq) & 0xffff));
Patrick Boettchera75763f2006-10-18 08:34:16 -0300461
462 dib7000p_write_word(state, 72, bw->sad_cfg);
463}
464
Olivier Grenie713d54a2011-01-04 04:54:31 -0300465static u32 dib7000p_get_internal_freq(struct dib7000p_state *state)
466{
467 u32 internal = (u32) dib7000p_read_word(state, 18) << 16;
468 internal |= (u32) dib7000p_read_word(state, 19);
469 internal /= 1000;
470
471 return internal;
472}
473
474int dib7000p_update_pll(struct dvb_frontend *fe, struct dibx000_bandwidth_config *bw)
475{
476 struct dib7000p_state *state = fe->demodulator_priv;
477 u16 reg_1857, reg_1856 = dib7000p_read_word(state, 1856);
478 u8 loopdiv, prediv;
479 u32 internal, xtal;
480
481 /* get back old values */
482 prediv = reg_1856 & 0x3f;
483 loopdiv = (reg_1856 >> 6) & 0x3f;
484
485 if ((bw != NULL) && (bw->pll_prediv != prediv || bw->pll_ratio != loopdiv)) {
486 dprintk("Updating pll (prediv: old = %d new = %d ; loopdiv : old = %d new = %d)", prediv, bw->pll_prediv, loopdiv, bw->pll_ratio);
487 reg_1856 &= 0xf000;
488 reg_1857 = dib7000p_read_word(state, 1857);
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300489 dib7000p_write_word(state, 1857, reg_1857 & ~(1 << 15));
Olivier Grenie713d54a2011-01-04 04:54:31 -0300490
491 dib7000p_write_word(state, 1856, reg_1856 | ((bw->pll_ratio & 0x3f) << 6) | (bw->pll_prediv & 0x3f));
492
493 /* write new system clk into P_sec_len */
494 internal = dib7000p_get_internal_freq(state);
495 xtal = (internal / loopdiv) * prediv;
496 internal = 1000 * (xtal / bw->pll_prediv) * bw->pll_ratio; /* new internal */
497 dib7000p_write_word(state, 18, (u16) ((internal >> 16) & 0xffff));
498 dib7000p_write_word(state, 19, (u16) (internal & 0xffff));
499
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300500 dib7000p_write_word(state, 1857, reg_1857 | (1 << 15));
Olivier Grenie713d54a2011-01-04 04:54:31 -0300501
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300502 while (((dib7000p_read_word(state, 1856) >> 15) & 0x1) != 1)
Olivier Grenie713d54a2011-01-04 04:54:31 -0300503 dprintk("Waiting for PLL to lock");
Olivier Grenie713d54a2011-01-04 04:54:31 -0300504
505 return 0;
506 }
507 return -EIO;
508}
509EXPORT_SYMBOL(dib7000p_update_pll);
510
Patrick Boettchera75763f2006-10-18 08:34:16 -0300511static int dib7000p_reset_gpio(struct dib7000p_state *st)
512{
513 /* reset the GPIOs */
Olivier Grenie713d54a2011-01-04 04:54:31 -0300514 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 -0300515
516 dib7000p_write_word(st, 1029, st->gpio_dir);
517 dib7000p_write_word(st, 1030, st->gpio_val);
518
519 /* TODO 1031 is P_gpio_od */
520
521 dib7000p_write_word(st, 1032, st->cfg.gpio_pwm_pos);
522
523 dib7000p_write_word(st, 1037, st->cfg.pwm_freq_div);
524 return 0;
525}
526
Patrick Boettcher01373a52007-07-30 12:49:04 -0300527static int dib7000p_cfg_gpio(struct dib7000p_state *st, u8 num, u8 dir, u8 val)
528{
529 st->gpio_dir = dib7000p_read_word(st, 1029);
Olivier Grenie713d54a2011-01-04 04:54:31 -0300530 st->gpio_dir &= ~(1 << num); /* reset the direction bit */
531 st->gpio_dir |= (dir & 0x1) << num; /* set the new direction */
Patrick Boettcher01373a52007-07-30 12:49:04 -0300532 dib7000p_write_word(st, 1029, st->gpio_dir);
533
534 st->gpio_val = dib7000p_read_word(st, 1030);
Olivier Grenie713d54a2011-01-04 04:54:31 -0300535 st->gpio_val &= ~(1 << num); /* reset the direction bit */
536 st->gpio_val |= (val & 0x01) << num; /* set the new value */
Patrick Boettcher01373a52007-07-30 12:49:04 -0300537 dib7000p_write_word(st, 1030, st->gpio_val);
538
539 return 0;
540}
541
542int dib7000p_set_gpio(struct dvb_frontend *demod, u8 num, u8 dir, u8 val)
543{
544 struct dib7000p_state *state = demod->demodulator_priv;
545 return dib7000p_cfg_gpio(state, num, dir, val);
546}
Patrick Boettcher01373a52007-07-30 12:49:04 -0300547EXPORT_SYMBOL(dib7000p_set_gpio);
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300548
Olivier Grenie713d54a2011-01-04 04:54:31 -0300549static u16 dib7000p_defaults[] = {
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300550 // auto search configuration
551 3, 2,
Olivier Grenie713d54a2011-01-04 04:54:31 -0300552 0x0004,
Olivier Grenie2e802862011-08-05 10:39:15 -0300553 (1<<3)|(1<<11)|(1<<12)|(1<<13),
Olivier Grenie713d54a2011-01-04 04:54:31 -0300554 0x0814, /* Equal Lock */
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300555
556 12, 6,
Olivier Grenie713d54a2011-01-04 04:54:31 -0300557 0x001b,
558 0x7740,
559 0x005b,
560 0x8d80,
561 0x01c9,
562 0xc380,
563 0x0000,
564 0x0080,
565 0x0000,
566 0x0090,
567 0x0001,
568 0xd4c0,
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300569
570 1, 26,
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300571 0x6680,
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300572
573 /* set ADC level to -16 */
574 11, 79,
Olivier Grenie713d54a2011-01-04 04:54:31 -0300575 (1 << 13) - 825 - 117,
576 (1 << 13) - 837 - 117,
577 (1 << 13) - 811 - 117,
578 (1 << 13) - 766 - 117,
579 (1 << 13) - 737 - 117,
580 (1 << 13) - 693 - 117,
581 (1 << 13) - 648 - 117,
582 (1 << 13) - 619 - 117,
583 (1 << 13) - 575 - 117,
584 (1 << 13) - 531 - 117,
585 (1 << 13) - 501 - 117,
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300586
587 1, 142,
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300588 0x0410,
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300589
590 /* disable power smoothing */
591 8, 145,
Olivier Grenie713d54a2011-01-04 04:54:31 -0300592 0,
593 0,
594 0,
595 0,
596 0,
597 0,
598 0,
599 0,
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300600
601 1, 154,
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300602 1 << 13,
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300603
604 1, 168,
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300605 0x0ccd,
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300606
607 1, 183,
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300608 0x200f,
Olivier Grenie713d54a2011-01-04 04:54:31 -0300609
610 1, 212,
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300611 0x169,
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300612
613 5, 187,
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300614 0x023d,
615 0x00a4,
616 0x00a4,
617 0x7ff0,
618 0x3ccc,
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300619
620 1, 198,
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300621 0x800,
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300622
623 1, 222,
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300624 0x0010,
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300625
626 1, 235,
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300627 0x0062,
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300628
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300629 0,
630};
631
Patrick Boettchera75763f2006-10-18 08:34:16 -0300632static int dib7000p_demod_reset(struct dib7000p_state *state)
633{
634 dib7000p_set_power_mode(state, DIB7000P_POWER_ALL);
635
Olivier Grenie713d54a2011-01-04 04:54:31 -0300636 if (state->version == SOC7090)
637 dibx000_reset_i2c_master(&state->i2c_master);
638
Patrick Boettchera75763f2006-10-18 08:34:16 -0300639 dib7000p_set_adc_state(state, DIBX000_VBG_ENABLE);
640
641 /* restart all parts */
Olivier Grenie713d54a2011-01-04 04:54:31 -0300642 dib7000p_write_word(state, 770, 0xffff);
643 dib7000p_write_word(state, 771, 0xffff);
644 dib7000p_write_word(state, 772, 0x001f);
Olivier Grenie713d54a2011-01-04 04:54:31 -0300645 dib7000p_write_word(state, 1280, 0x001f - ((1 << 4) | (1 << 3)));
Patrick Boettchera75763f2006-10-18 08:34:16 -0300646
Olivier Grenie713d54a2011-01-04 04:54:31 -0300647 dib7000p_write_word(state, 770, 0);
648 dib7000p_write_word(state, 771, 0);
649 dib7000p_write_word(state, 772, 0);
Patrick Boettchera75763f2006-10-18 08:34:16 -0300650 dib7000p_write_word(state, 1280, 0);
651
Olivier Grenie2e802862011-08-05 10:39:15 -0300652 if (state->version != SOC7090) {
653 dib7000p_write_word(state, 898, 0x0003);
654 dib7000p_write_word(state, 898, 0);
655 }
656
Patrick Boettchera75763f2006-10-18 08:34:16 -0300657 /* default */
658 dib7000p_reset_pll(state);
659
660 if (dib7000p_reset_gpio(state) != 0)
Olivier Grenie713d54a2011-01-04 04:54:31 -0300661 dprintk("GPIO reset was not successful.");
Patrick Boettchera75763f2006-10-18 08:34:16 -0300662
Olivier Grenie713d54a2011-01-04 04:54:31 -0300663 if (state->version == SOC7090) {
664 dib7000p_write_word(state, 899, 0);
665
666 /* impulse noise */
667 dib7000p_write_word(state, 42, (1<<5) | 3); /* P_iqc_thsat_ipc = 1 ; P_iqc_win2 = 3 */
668 dib7000p_write_word(state, 43, 0x2d4); /*-300 fag P_iqc_dect_min = -280 */
669 dib7000p_write_word(state, 44, 300); /* 300 fag P_iqc_dect_min = +280 */
Olivier Grenie2e802862011-08-05 10:39:15 -0300670 dib7000p_write_word(state, 273, (0<<6) | 30);
Olivier Grenie713d54a2011-01-04 04:54:31 -0300671 }
Patrick Boettchera75763f2006-10-18 08:34:16 -0300672 if (dib7000p_set_output_mode(state, OUTMODE_HIGH_Z) != 0)
Olivier Grenie713d54a2011-01-04 04:54:31 -0300673 dprintk("OUTPUT_MODE could not be reset.");
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300674
675 dib7000p_set_adc_state(state, DIBX000_SLOW_ADC_ON);
676 dib7000p_sad_calib(state);
677 dib7000p_set_adc_state(state, DIBX000_SLOW_ADC_OFF);
678
Olivier Grenie713d54a2011-01-04 04:54:31 -0300679 /* unforce divstr regardless whether i2c enumeration was done or not */
680 dib7000p_write_word(state, 1285, dib7000p_read_word(state, 1285) & ~(1 << 1));
681
682 dib7000p_set_bandwidth(state, 8000);
683
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300684 if (state->version == SOC7090) {
Olivier Grenie2e802862011-08-05 10:39:15 -0300685 dib7000p_write_word(state, 36, 0x0755);/* P_iqc_impnc_on =1 & P_iqc_corr_inh = 1 for impulsive noise */
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300686 } else {
Olivier Grenie713d54a2011-01-04 04:54:31 -0300687 if (state->cfg.tuner_is_baseband)
688 dib7000p_write_word(state, 36, 0x0755);
689 else
690 dib7000p_write_word(state, 36, 0x1f55);
691 }
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300692
693 dib7000p_write_tab(state, dib7000p_defaults);
Olivier Grenie2e802862011-08-05 10:39:15 -0300694 if (state->version != SOC7090) {
695 dib7000p_write_word(state, 901, 0x0006);
696 dib7000p_write_word(state, 902, (3 << 10) | (1 << 6));
697 dib7000p_write_word(state, 905, 0x2c8e);
698 }
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300699
Patrick Boettchera75763f2006-10-18 08:34:16 -0300700 dib7000p_set_power_mode(state, DIB7000P_POWER_INTERFACE_ONLY);
701
702 return 0;
703}
704
Patrick Boettchera75763f2006-10-18 08:34:16 -0300705static void dib7000p_pll_clk_cfg(struct dib7000p_state *state)
706{
707 u16 tmp = 0;
708 tmp = dib7000p_read_word(state, 903);
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300709 dib7000p_write_word(state, 903, (tmp | 0x1));
Patrick Boettchera75763f2006-10-18 08:34:16 -0300710 tmp = dib7000p_read_word(state, 900);
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300711 dib7000p_write_word(state, 900, (tmp & 0x7fff) | (1 << 6));
Patrick Boettchera75763f2006-10-18 08:34:16 -0300712}
713
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300714static void dib7000p_restart_agc(struct dib7000p_state *state)
Patrick Boettchera75763f2006-10-18 08:34:16 -0300715{
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300716 // P_restart_iqc & P_restart_agc
717 dib7000p_write_word(state, 770, (1 << 11) | (1 << 9));
718 dib7000p_write_word(state, 770, 0x0000);
Patrick Boettchera75763f2006-10-18 08:34:16 -0300719}
720
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300721static int dib7000p_update_lna(struct dib7000p_state *state)
Patrick Boettchera75763f2006-10-18 08:34:16 -0300722{
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300723 u16 dyn_gain;
724
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300725 if (state->cfg.update_lna) {
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300726 dyn_gain = dib7000p_read_word(state, 394);
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300727 if (state->cfg.update_lna(&state->demod, dyn_gain)) {
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300728 dib7000p_restart_agc(state);
729 return 1;
730 }
731 }
732
733 return 0;
734}
735
736static int dib7000p_set_agc_config(struct dib7000p_state *state, u8 band)
737{
738 struct dibx000_agc_config *agc = NULL;
739 int i;
740 if (state->current_band == band && state->current_agc != NULL)
741 return 0;
742 state->current_band = band;
743
744 for (i = 0; i < state->cfg.agc_config_count; i++)
745 if (state->cfg.agc[i].band_caps & band) {
746 agc = &state->cfg.agc[i];
747 break;
748 }
749
750 if (agc == NULL) {
Olivier Grenie713d54a2011-01-04 04:54:31 -0300751 dprintk("no valid AGC configuration found for band 0x%02x", band);
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300752 return -EINVAL;
753 }
754
755 state->current_agc = agc;
756
757 /* AGC */
Olivier Grenie713d54a2011-01-04 04:54:31 -0300758 dib7000p_write_word(state, 75, agc->setup);
759 dib7000p_write_word(state, 76, agc->inv_gain);
760 dib7000p_write_word(state, 77, agc->time_stabiliz);
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300761 dib7000p_write_word(state, 100, (agc->alpha_level << 12) | agc->thlock);
762
763 // Demod AGC loop configuration
764 dib7000p_write_word(state, 101, (agc->alpha_mant << 5) | agc->alpha_exp);
Olivier Grenie713d54a2011-01-04 04:54:31 -0300765 dib7000p_write_word(state, 102, (agc->beta_mant << 6) | agc->beta_exp);
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300766
767 /* AGC continued */
Olivier Grenie713d54a2011-01-04 04:54:31 -0300768 dprintk("WBD: ref: %d, sel: %d, active: %d, alpha: %d",
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300769 state->wbd_ref != 0 ? state->wbd_ref : agc->wbd_ref, agc->wbd_sel, !agc->perform_agc_softsplit, agc->wbd_sel);
770
771 if (state->wbd_ref != 0)
772 dib7000p_write_word(state, 105, (agc->wbd_inv << 12) | state->wbd_ref);
773 else
774 dib7000p_write_word(state, 105, (agc->wbd_inv << 12) | agc->wbd_ref);
775
776 dib7000p_write_word(state, 106, (agc->wbd_sel << 13) | (agc->wbd_alpha << 9) | (agc->perform_agc_softsplit << 8));
777
Olivier Grenie713d54a2011-01-04 04:54:31 -0300778 dib7000p_write_word(state, 107, agc->agc1_max);
779 dib7000p_write_word(state, 108, agc->agc1_min);
780 dib7000p_write_word(state, 109, agc->agc2_max);
781 dib7000p_write_word(state, 110, agc->agc2_min);
782 dib7000p_write_word(state, 111, (agc->agc1_pt1 << 8) | agc->agc1_pt2);
783 dib7000p_write_word(state, 112, agc->agc1_pt3);
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300784 dib7000p_write_word(state, 113, (agc->agc1_slope1 << 8) | agc->agc1_slope2);
Olivier Grenie713d54a2011-01-04 04:54:31 -0300785 dib7000p_write_word(state, 114, (agc->agc2_pt1 << 8) | agc->agc2_pt2);
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300786 dib7000p_write_word(state, 115, (agc->agc2_slope1 << 8) | agc->agc2_slope2);
787 return 0;
788}
789
Olivier Grenie713d54a2011-01-04 04:54:31 -0300790static void dib7000p_set_dds(struct dib7000p_state *state, s32 offset_khz)
791{
792 u32 internal = dib7000p_get_internal_freq(state);
793 s32 unit_khz_dds_val = 67108864 / (internal); /* 2**26 / Fsampling is the unit 1KHz offset */
794 u32 abs_offset_khz = ABS(offset_khz);
795 u32 dds = state->cfg.bw->ifreq & 0x1ffffff;
796 u8 invert = !!(state->cfg.bw->ifreq & (1 << 25));
797
798 dprintk("setting a frequency offset of %dkHz internal freq = %d invert = %d", offset_khz, internal, invert);
799
800 if (offset_khz < 0)
801 unit_khz_dds_val *= -1;
802
803 /* IF tuner */
804 if (invert)
805 dds -= (abs_offset_khz * unit_khz_dds_val); /* /100 because of /100 on the unit_khz_dds_val line calc for better accuracy */
806 else
807 dds += (abs_offset_khz * unit_khz_dds_val);
808
809 if (abs_offset_khz <= (internal / 2)) { /* Max dds offset is the half of the demod freq */
810 dib7000p_write_word(state, 21, (u16) (((dds >> 16) & 0x1ff) | (0 << 10) | (invert << 9)));
811 dib7000p_write_word(state, 22, (u16) (dds & 0xffff));
812 }
813}
814
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -0300815static int dib7000p_agc_startup(struct dvb_frontend *demod)
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300816{
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -0300817 struct dtv_frontend_properties *ch = &demod->dtv_property_cache;
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300818 struct dib7000p_state *state = demod->demodulator_priv;
819 int ret = -1;
820 u8 *agc_state = &state->agc_state;
821 u8 agc_split;
Olivier Grenie713d54a2011-01-04 04:54:31 -0300822 u16 reg;
823 u32 upd_demod_gain_period = 0x1000;
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300824
825 switch (state->agc_state) {
Olivier Grenie713d54a2011-01-04 04:54:31 -0300826 case 0:
Olivier Grenie713d54a2011-01-04 04:54:31 -0300827 dib7000p_set_power_mode(state, DIB7000P_POWER_ALL);
828 if (state->version == SOC7090) {
829 reg = dib7000p_read_word(state, 0x79b) & 0xff00;
830 dib7000p_write_word(state, 0x79a, upd_demod_gain_period & 0xFFFF); /* lsb */
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300831 dib7000p_write_word(state, 0x79b, reg | (1 << 14) | ((upd_demod_gain_period >> 16) & 0xFF));
Olivier Grenie713d54a2011-01-04 04:54:31 -0300832
833 /* enable adc i & q */
834 reg = dib7000p_read_word(state, 0x780);
835 dib7000p_write_word(state, 0x780, (reg | (0x3)) & (~(1 << 7)));
836 } else {
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300837 dib7000p_set_adc_state(state, DIBX000_ADC_ON);
838 dib7000p_pll_clk_cfg(state);
Olivier Grenie713d54a2011-01-04 04:54:31 -0300839 }
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300840
Olivier Grenie713d54a2011-01-04 04:54:31 -0300841 if (dib7000p_set_agc_config(state, BAND_OF_FREQUENCY(ch->frequency / 1000)) != 0)
842 return -1;
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300843
Olivier Grenie713d54a2011-01-04 04:54:31 -0300844 dib7000p_set_dds(state, 0);
845 ret = 7;
846 (*agc_state)++;
847 break;
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300848
Olivier Grenie713d54a2011-01-04 04:54:31 -0300849 case 1:
Olivier Grenie713d54a2011-01-04 04:54:31 -0300850 if (state->cfg.agc_control)
851 state->cfg.agc_control(&state->demod, 1);
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300852
Olivier Grenie713d54a2011-01-04 04:54:31 -0300853 dib7000p_write_word(state, 78, 32768);
854 if (!state->current_agc->perform_agc_softsplit) {
855 /* we are using the wbd - so slow AGC startup */
856 /* force 0 split on WBD and restart AGC */
857 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 -0300858 (*agc_state)++;
859 ret = 5;
Olivier Grenie713d54a2011-01-04 04:54:31 -0300860 } else {
861 /* default AGC startup */
862 (*agc_state) = 4;
863 /* wait AGC rough lock time */
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300864 ret = 7;
Olivier Grenie713d54a2011-01-04 04:54:31 -0300865 }
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300866
Olivier Grenie713d54a2011-01-04 04:54:31 -0300867 dib7000p_restart_agc(state);
868 break;
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300869
Olivier Grenie713d54a2011-01-04 04:54:31 -0300870 case 2: /* fast split search path after 5sec */
871 dib7000p_write_word(state, 75, state->current_agc->setup | (1 << 4)); /* freeze AGC loop */
872 dib7000p_write_word(state, 106, (state->current_agc->wbd_sel << 13) | (2 << 9) | (0 << 8)); /* fast split search 0.25kHz */
873 (*agc_state)++;
874 ret = 14;
875 break;
876
877 case 3: /* split search ended */
878 agc_split = (u8) dib7000p_read_word(state, 396); /* store the split value for the next time */
879 dib7000p_write_word(state, 78, dib7000p_read_word(state, 394)); /* set AGC gain start value */
880
881 dib7000p_write_word(state, 75, state->current_agc->setup); /* std AGC loop */
882 dib7000p_write_word(state, 106, (state->current_agc->wbd_sel << 13) | (state->current_agc->wbd_alpha << 9) | agc_split); /* standard split search */
883
884 dib7000p_restart_agc(state);
885
886 dprintk("SPLIT %p: %hd", demod, agc_split);
887
888 (*agc_state)++;
889 ret = 5;
890 break;
891
892 case 4: /* LNA startup */
Olivier Grenie713d54a2011-01-04 04:54:31 -0300893 ret = 7;
894
895 if (dib7000p_update_lna(state))
Olivier Grenie713d54a2011-01-04 04:54:31 -0300896 ret = 5;
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300897 else
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300898 (*agc_state)++;
Olivier Grenie713d54a2011-01-04 04:54:31 -0300899 break;
900
901 case 5:
902 if (state->cfg.agc_control)
903 state->cfg.agc_control(&state->demod, 0);
904 (*agc_state)++;
905 break;
906 default:
907 break;
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300908 }
909 return ret;
910}
911
912static void dib7000p_update_timf(struct dib7000p_state *state)
913{
914 u32 timf = (dib7000p_read_word(state, 427) << 16) | dib7000p_read_word(state, 428);
915 state->timf = timf * 160 / (state->current_bandwidth / 50);
916 dib7000p_write_word(state, 23, (u16) (timf >> 16));
917 dib7000p_write_word(state, 24, (u16) (timf & 0xffff));
Olivier Grenie713d54a2011-01-04 04:54:31 -0300918 dprintk("updated timf_frequency: %d (default: %d)", state->timf, state->cfg.bw->timf);
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300919
920}
921
Olivier Grenie713d54a2011-01-04 04:54:31 -0300922u32 dib7000p_ctrl_timf(struct dvb_frontend *fe, u8 op, u32 timf)
923{
924 struct dib7000p_state *state = fe->demodulator_priv;
925 switch (op) {
926 case DEMOD_TIMF_SET:
927 state->timf = timf;
928 break;
929 case DEMOD_TIMF_UPDATE:
930 dib7000p_update_timf(state);
931 break;
932 case DEMOD_TIMF_GET:
933 break;
934 }
935 dib7000p_set_bandwidth(state, state->current_bandwidth);
936 return state->timf;
937}
938EXPORT_SYMBOL(dib7000p_ctrl_timf);
939
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -0300940static void dib7000p_set_channel(struct dib7000p_state *state,
941 struct dtv_frontend_properties *ch, u8 seq)
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300942{
943 u16 value, est[4];
944
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -0300945 dib7000p_set_bandwidth(state, BANDWIDTH_TO_KHZ(ch->bandwidth_hz));
Patrick Boettchera75763f2006-10-18 08:34:16 -0300946
947 /* nfft, guard, qam, alpha */
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300948 value = 0;
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -0300949 switch (ch->transmission_mode) {
Olivier Grenie713d54a2011-01-04 04:54:31 -0300950 case TRANSMISSION_MODE_2K:
951 value |= (0 << 7);
952 break;
Mauro Carvalho Chehab46f72962011-01-16 13:01:20 -0200953 case TRANSMISSION_MODE_4K:
Olivier Grenie713d54a2011-01-04 04:54:31 -0300954 value |= (2 << 7);
955 break;
956 default:
957 case TRANSMISSION_MODE_8K:
958 value |= (1 << 7);
959 break;
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300960 }
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -0300961 switch (ch->guard_interval) {
Olivier Grenie713d54a2011-01-04 04:54:31 -0300962 case GUARD_INTERVAL_1_32:
963 value |= (0 << 5);
964 break;
965 case GUARD_INTERVAL_1_16:
966 value |= (1 << 5);
967 break;
968 case GUARD_INTERVAL_1_4:
969 value |= (3 << 5);
970 break;
971 default:
972 case GUARD_INTERVAL_1_8:
973 value |= (2 << 5);
974 break;
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300975 }
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -0300976 switch (ch->modulation) {
Olivier Grenie713d54a2011-01-04 04:54:31 -0300977 case QPSK:
978 value |= (0 << 3);
979 break;
980 case QAM_16:
981 value |= (1 << 3);
982 break;
983 default:
984 case QAM_64:
985 value |= (2 << 3);
986 break;
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300987 }
988 switch (HIERARCHY_1) {
Olivier Grenie713d54a2011-01-04 04:54:31 -0300989 case HIERARCHY_2:
990 value |= 2;
991 break;
992 case HIERARCHY_4:
993 value |= 4;
994 break;
995 default:
996 case HIERARCHY_1:
997 value |= 1;
998 break;
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300999 }
1000 dib7000p_write_word(state, 0, value);
Olivier Grenie713d54a2011-01-04 04:54:31 -03001001 dib7000p_write_word(state, 5, (seq << 4) | 1); /* do not force tps, search list 0 */
Patrick Boettchera75763f2006-10-18 08:34:16 -03001002
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001003 /* P_dintl_native, P_dintlv_inv, P_hrch, P_code_rate, P_select_hp */
1004 value = 0;
1005 if (1 != 0)
1006 value |= (1 << 6);
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -03001007 if (ch->hierarchy == 1)
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001008 value |= (1 << 4);
1009 if (1 == 1)
1010 value |= 1;
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -03001011 switch ((ch->hierarchy == 0 || 1 == 1) ? ch->code_rate_HP : ch->code_rate_LP) {
Olivier Grenie713d54a2011-01-04 04:54:31 -03001012 case FEC_2_3:
1013 value |= (2 << 1);
1014 break;
1015 case FEC_3_4:
1016 value |= (3 << 1);
1017 break;
1018 case FEC_5_6:
1019 value |= (5 << 1);
1020 break;
1021 case FEC_7_8:
1022 value |= (7 << 1);
1023 break;
1024 default:
1025 case FEC_1_2:
1026 value |= (1 << 1);
1027 break;
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001028 }
1029 dib7000p_write_word(state, 208, value);
1030
1031 /* offset loop parameters */
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001032 dib7000p_write_word(state, 26, 0x6680);
1033 dib7000p_write_word(state, 32, 0x0003);
1034 dib7000p_write_word(state, 29, 0x1273);
1035 dib7000p_write_word(state, 33, 0x0005);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001036
1037 /* P_dvsy_sync_wait */
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -03001038 switch (ch->transmission_mode) {
Olivier Grenie713d54a2011-01-04 04:54:31 -03001039 case TRANSMISSION_MODE_8K:
1040 value = 256;
1041 break;
1042 case TRANSMISSION_MODE_4K:
1043 value = 128;
1044 break;
1045 case TRANSMISSION_MODE_2K:
1046 default:
1047 value = 64;
1048 break;
Patrick Boettchera75763f2006-10-18 08:34:16 -03001049 }
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -03001050 switch (ch->guard_interval) {
Olivier Grenie713d54a2011-01-04 04:54:31 -03001051 case GUARD_INTERVAL_1_16:
1052 value *= 2;
1053 break;
1054 case GUARD_INTERVAL_1_8:
1055 value *= 4;
1056 break;
1057 case GUARD_INTERVAL_1_4:
1058 value *= 8;
1059 break;
1060 default:
1061 case GUARD_INTERVAL_1_32:
1062 value *= 1;
1063 break;
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001064 }
Olivier Grenie970d14c2010-09-07 12:50:46 -03001065 if (state->cfg.diversity_delay == 0)
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001066 state->div_sync_wait = (value * 3) / 2 + 48;
Olivier Grenie970d14c2010-09-07 12:50:46 -03001067 else
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001068 state->div_sync_wait = (value * 3) / 2 + state->cfg.diversity_delay;
Patrick Boettchera75763f2006-10-18 08:34:16 -03001069
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001070 /* deactive the possibility of diversity reception if extended interleaver */
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -03001071 state->div_force_off = !1 && ch->transmission_mode != TRANSMISSION_MODE_8K;
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001072 dib7000p_set_diversity_in(&state->demod, state->div_state);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001073
1074 /* channel estimation fine configuration */
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -03001075 switch (ch->modulation) {
Olivier Grenie713d54a2011-01-04 04:54:31 -03001076 case QAM_64:
1077 est[0] = 0x0148; /* P_adp_regul_cnt 0.04 */
1078 est[1] = 0xfff0; /* P_adp_noise_cnt -0.002 */
1079 est[2] = 0x00a4; /* P_adp_regul_ext 0.02 */
1080 est[3] = 0xfff8; /* P_adp_noise_ext -0.001 */
1081 break;
1082 case QAM_16:
1083 est[0] = 0x023d; /* P_adp_regul_cnt 0.07 */
1084 est[1] = 0xffdf; /* P_adp_noise_cnt -0.004 */
1085 est[2] = 0x00a4; /* P_adp_regul_ext 0.02 */
1086 est[3] = 0xfff0; /* P_adp_noise_ext -0.002 */
1087 break;
1088 default:
1089 est[0] = 0x099a; /* P_adp_regul_cnt 0.3 */
1090 est[1] = 0xffae; /* P_adp_noise_cnt -0.01 */
1091 est[2] = 0x0333; /* P_adp_regul_ext 0.1 */
1092 est[3] = 0xfff8; /* P_adp_noise_ext -0.002 */
1093 break;
Patrick Boettchera75763f2006-10-18 08:34:16 -03001094 }
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001095 for (value = 0; value < 4; value++)
1096 dib7000p_write_word(state, 187 + value, est[value]);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001097}
1098
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -03001099static int dib7000p_autosearch_start(struct dvb_frontend *demod)
Patrick Boettchera75763f2006-10-18 08:34:16 -03001100{
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -03001101 struct dtv_frontend_properties *ch = &demod->dtv_property_cache;
Patrick Boettchera75763f2006-10-18 08:34:16 -03001102 struct dib7000p_state *state = demod->demodulator_priv;
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -03001103 struct dtv_frontend_properties schan;
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001104 u32 value, factor;
Olivier Grenie713d54a2011-01-04 04:54:31 -03001105 u32 internal = dib7000p_get_internal_freq(state);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001106
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001107 schan = *ch;
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -03001108 schan.modulation = QAM_64;
1109 schan.guard_interval = GUARD_INTERVAL_1_32;
1110 schan.transmission_mode = TRANSMISSION_MODE_8K;
1111 schan.code_rate_HP = FEC_2_3;
1112 schan.code_rate_LP = FEC_3_4;
1113 schan.hierarchy = 0;
Patrick Boettchera75763f2006-10-18 08:34:16 -03001114
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001115 dib7000p_set_channel(state, &schan, 7);
1116
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -03001117 factor = BANDWIDTH_TO_KHZ(ch->bandwidth_hz);
Olivier Grenie2e802862011-08-05 10:39:15 -03001118 if (factor >= 5000) {
1119 if (state->version == SOC7090)
1120 factor = 2;
1121 else
1122 factor = 1;
1123 } else
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001124 factor = 6;
Patrick Boettchera75763f2006-10-18 08:34:16 -03001125
Olivier Grenie713d54a2011-01-04 04:54:31 -03001126 value = 30 * internal * factor;
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001127 dib7000p_write_word(state, 6, (u16) ((value >> 16) & 0xffff));
1128 dib7000p_write_word(state, 7, (u16) (value & 0xffff));
Olivier Grenie713d54a2011-01-04 04:54:31 -03001129 value = 100 * internal * factor;
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001130 dib7000p_write_word(state, 8, (u16) ((value >> 16) & 0xffff));
1131 dib7000p_write_word(state, 9, (u16) (value & 0xffff));
Olivier Grenie713d54a2011-01-04 04:54:31 -03001132 value = 500 * internal * factor;
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001133 dib7000p_write_word(state, 10, (u16) ((value >> 16) & 0xffff));
1134 dib7000p_write_word(state, 11, (u16) (value & 0xffff));
Patrick Boettchera75763f2006-10-18 08:34:16 -03001135
1136 value = dib7000p_read_word(state, 0);
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001137 dib7000p_write_word(state, 0, (u16) ((1 << 9) | value));
Patrick Boettchera75763f2006-10-18 08:34:16 -03001138 dib7000p_read_word(state, 1284);
1139 dib7000p_write_word(state, 0, (u16) value);
1140
1141 return 0;
1142}
1143
1144static int dib7000p_autosearch_is_irq(struct dvb_frontend *demod)
1145{
1146 struct dib7000p_state *state = demod->demodulator_priv;
1147 u16 irq_pending = dib7000p_read_word(state, 1284);
1148
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001149 if (irq_pending & 0x1)
Patrick Boettchera75763f2006-10-18 08:34:16 -03001150 return 1;
1151
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001152 if (irq_pending & 0x2)
Patrick Boettchera75763f2006-10-18 08:34:16 -03001153 return 2;
1154
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001155 return 0;
Patrick Boettchera75763f2006-10-18 08:34:16 -03001156}
1157
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001158static void dib7000p_spur_protect(struct dib7000p_state *state, u32 rf_khz, u32 bw)
1159{
Olivier Grenie713d54a2011-01-04 04:54:31 -03001160 static s16 notch[] = { 16143, 14402, 12238, 9713, 6902, 3888, 759, -2392 };
1161 static u8 sine[] = { 0, 2, 3, 5, 6, 8, 9, 11, 13, 14, 16, 17, 19, 20, 22,
1162 24, 25, 27, 28, 30, 31, 33, 34, 36, 38, 39, 41, 42, 44, 45, 47, 48, 50, 51,
1163 53, 55, 56, 58, 59, 61, 62, 64, 65, 67, 68, 70, 71, 73, 74, 76, 77, 79, 80,
1164 82, 83, 85, 86, 88, 89, 91, 92, 94, 95, 97, 98, 99, 101, 102, 104, 105,
1165 107, 108, 109, 111, 112, 114, 115, 117, 118, 119, 121, 122, 123, 125, 126,
1166 128, 129, 130, 132, 133, 134, 136, 137, 138, 140, 141, 142, 144, 145, 146,
1167 147, 149, 150, 151, 152, 154, 155, 156, 157, 159, 160, 161, 162, 164, 165,
1168 166, 167, 168, 170, 171, 172, 173, 174, 175, 177, 178, 179, 180, 181, 182,
1169 183, 184, 185, 186, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198,
1170 199, 200, 201, 202, 203, 204, 205, 206, 207, 207, 208, 209, 210, 211, 212,
1171 213, 214, 215, 215, 216, 217, 218, 219, 220, 220, 221, 222, 223, 224, 224,
1172 225, 226, 227, 227, 228, 229, 229, 230, 231, 231, 232, 233, 233, 234, 235,
1173 235, 236, 237, 237, 238, 238, 239, 239, 240, 241, 241, 242, 242, 243, 243,
1174 244, 244, 245, 245, 245, 246, 246, 247, 247, 248, 248, 248, 249, 249, 249,
1175 250, 250, 250, 251, 251, 251, 252, 252, 252, 252, 253, 253, 253, 253, 254,
1176 254, 254, 254, 254, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
1177 255, 255, 255, 255, 255, 255
1178 };
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001179
1180 u32 xtal = state->cfg.bw->xtal_hz / 1000;
Julia Lawall75b697f2009-08-01 16:48:41 -03001181 int f_rel = DIV_ROUND_CLOSEST(rf_khz, xtal) * xtal - rf_khz;
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001182 int k;
Olivier Grenie713d54a2011-01-04 04:54:31 -03001183 int coef_re[8], coef_im[8];
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001184 int bw_khz = bw;
1185 u32 pha;
1186
Olivier Grenie713d54a2011-01-04 04:54:31 -03001187 dprintk("relative position of the Spur: %dk (RF: %dk, XTAL: %dk)", f_rel, rf_khz, xtal);
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001188
Olivier Grenie713d54a2011-01-04 04:54:31 -03001189 if (f_rel < -bw_khz / 2 || f_rel > bw_khz / 2)
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001190 return;
1191
1192 bw_khz /= 100;
1193
Olivier Grenie713d54a2011-01-04 04:54:31 -03001194 dib7000p_write_word(state, 142, 0x0610);
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001195
1196 for (k = 0; k < 8; k++) {
Olivier Grenie713d54a2011-01-04 04:54:31 -03001197 pha = ((f_rel * (k + 1) * 112 * 80 / bw_khz) / 1000) & 0x3ff;
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001198
Olivier Grenie713d54a2011-01-04 04:54:31 -03001199 if (pha == 0) {
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001200 coef_re[k] = 256;
1201 coef_im[k] = 0;
Olivier Grenie713d54a2011-01-04 04:54:31 -03001202 } else if (pha < 256) {
1203 coef_re[k] = sine[256 - (pha & 0xff)];
1204 coef_im[k] = sine[pha & 0xff];
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001205 } else if (pha == 256) {
1206 coef_re[k] = 0;
1207 coef_im[k] = 256;
1208 } else if (pha < 512) {
Olivier Grenie713d54a2011-01-04 04:54:31 -03001209 coef_re[k] = -sine[pha & 0xff];
1210 coef_im[k] = sine[256 - (pha & 0xff)];
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001211 } else if (pha == 512) {
1212 coef_re[k] = -256;
1213 coef_im[k] = 0;
1214 } else if (pha < 768) {
Olivier Grenie713d54a2011-01-04 04:54:31 -03001215 coef_re[k] = -sine[256 - (pha & 0xff)];
1216 coef_im[k] = -sine[pha & 0xff];
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001217 } else if (pha == 768) {
1218 coef_re[k] = 0;
1219 coef_im[k] = -256;
1220 } else {
Olivier Grenie713d54a2011-01-04 04:54:31 -03001221 coef_re[k] = sine[pha & 0xff];
1222 coef_im[k] = -sine[256 - (pha & 0xff)];
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001223 }
1224
1225 coef_re[k] *= notch[k];
Olivier Grenie713d54a2011-01-04 04:54:31 -03001226 coef_re[k] += (1 << 14);
1227 if (coef_re[k] >= (1 << 24))
1228 coef_re[k] = (1 << 24) - 1;
1229 coef_re[k] /= (1 << 15);
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001230
1231 coef_im[k] *= notch[k];
Olivier Grenie713d54a2011-01-04 04:54:31 -03001232 coef_im[k] += (1 << 14);
1233 if (coef_im[k] >= (1 << 24))
1234 coef_im[k] = (1 << 24) - 1;
1235 coef_im[k] /= (1 << 15);
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001236
Olivier Grenie713d54a2011-01-04 04:54:31 -03001237 dprintk("PALF COEF: %d re: %d im: %d", k, coef_re[k], coef_im[k]);
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001238
1239 dib7000p_write_word(state, 143, (0 << 14) | (k << 10) | (coef_re[k] & 0x3ff));
1240 dib7000p_write_word(state, 144, coef_im[k] & 0x3ff);
1241 dib7000p_write_word(state, 143, (1 << 14) | (k << 10) | (coef_re[k] & 0x3ff));
1242 }
Olivier Grenie713d54a2011-01-04 04:54:31 -03001243 dib7000p_write_word(state, 143, 0);
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001244}
1245
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -03001246static int dib7000p_tune(struct dvb_frontend *demod)
Patrick Boettchera75763f2006-10-18 08:34:16 -03001247{
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -03001248 struct dtv_frontend_properties *ch = &demod->dtv_property_cache;
Patrick Boettchera75763f2006-10-18 08:34:16 -03001249 struct dib7000p_state *state = demod->demodulator_priv;
1250 u16 tmp = 0;
1251
1252 if (ch != NULL)
1253 dib7000p_set_channel(state, ch, 0);
1254 else
1255 return -EINVAL;
1256
1257 // restart demod
1258 dib7000p_write_word(state, 770, 0x4000);
1259 dib7000p_write_word(state, 770, 0x0000);
1260 msleep(45);
1261
1262 /* 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 -03001263 tmp = (0 << 14) | (4 << 10) | (0 << 9) | (3 << 5) | (1 << 4) | (0x3);
1264 if (state->sfn_workaround_active) {
Olivier Grenie713d54a2011-01-04 04:54:31 -03001265 dprintk("SFN workaround is active");
Matt Doran8f6956c2007-07-31 07:09:30 -03001266 tmp |= (1 << 9);
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001267 dib7000p_write_word(state, 166, 0x4000);
Matt Doran8f6956c2007-07-31 07:09:30 -03001268 } else {
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001269 dib7000p_write_word(state, 166, 0x0000);
Matt Doran8f6956c2007-07-31 07:09:30 -03001270 }
1271 dib7000p_write_word(state, 29, tmp);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001272
1273 // never achieved a lock with that bandwidth so far - wait for osc-freq to update
1274 if (state->timf == 0)
1275 msleep(200);
1276
1277 /* offset loop parameters */
1278
1279 /* P_timf_alpha, P_corm_alpha=6, P_corm_thres=0x80 */
1280 tmp = (6 << 8) | 0x80;
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -03001281 switch (ch->transmission_mode) {
Olivier Grenie713d54a2011-01-04 04:54:31 -03001282 case TRANSMISSION_MODE_2K:
1283 tmp |= (2 << 12);
1284 break;
Mauro Carvalho Chehab46f72962011-01-16 13:01:20 -02001285 case TRANSMISSION_MODE_4K:
Olivier Grenie713d54a2011-01-04 04:54:31 -03001286 tmp |= (3 << 12);
1287 break;
1288 default:
1289 case TRANSMISSION_MODE_8K:
1290 tmp |= (4 << 12);
1291 break;
Patrick Boettchera75763f2006-10-18 08:34:16 -03001292 }
Olivier Grenie713d54a2011-01-04 04:54:31 -03001293 dib7000p_write_word(state, 26, tmp); /* timf_a(6xxx) */
Patrick Boettchera75763f2006-10-18 08:34:16 -03001294
1295 /* P_ctrl_freeze_pha_shift=0, P_ctrl_pha_off_max */
1296 tmp = (0 << 4);
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -03001297 switch (ch->transmission_mode) {
Olivier Grenie713d54a2011-01-04 04:54:31 -03001298 case TRANSMISSION_MODE_2K:
1299 tmp |= 0x6;
1300 break;
Mauro Carvalho Chehab46f72962011-01-16 13:01:20 -02001301 case TRANSMISSION_MODE_4K:
Olivier Grenie713d54a2011-01-04 04:54:31 -03001302 tmp |= 0x7;
1303 break;
1304 default:
1305 case TRANSMISSION_MODE_8K:
1306 tmp |= 0x8;
1307 break;
Patrick Boettchera75763f2006-10-18 08:34:16 -03001308 }
Olivier Grenie713d54a2011-01-04 04:54:31 -03001309 dib7000p_write_word(state, 32, tmp);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001310
1311 /* P_ctrl_sfreq_inh=0, P_ctrl_sfreq_step */
1312 tmp = (0 << 4);
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -03001313 switch (ch->transmission_mode) {
Olivier Grenie713d54a2011-01-04 04:54:31 -03001314 case TRANSMISSION_MODE_2K:
1315 tmp |= 0x6;
1316 break;
1317 case TRANSMISSION_MODE_4K:
1318 tmp |= 0x7;
1319 break;
1320 default:
1321 case TRANSMISSION_MODE_8K:
1322 tmp |= 0x8;
1323 break;
Patrick Boettchera75763f2006-10-18 08:34:16 -03001324 }
Olivier Grenie713d54a2011-01-04 04:54:31 -03001325 dib7000p_write_word(state, 33, tmp);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001326
Olivier Grenie713d54a2011-01-04 04:54:31 -03001327 tmp = dib7000p_read_word(state, 509);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001328 if (!((tmp >> 6) & 0x1)) {
1329 /* restart the fec */
Olivier Grenie713d54a2011-01-04 04:54:31 -03001330 tmp = dib7000p_read_word(state, 771);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001331 dib7000p_write_word(state, 771, tmp | (1 << 1));
1332 dib7000p_write_word(state, 771, tmp);
Olivier Grenie713d54a2011-01-04 04:54:31 -03001333 msleep(40);
1334 tmp = dib7000p_read_word(state, 509);
1335 }
1336 // we achieved a lock - it's time to update the osc freq
1337 if ((tmp >> 6) & 0x1) {
1338 dib7000p_update_timf(state);
1339 /* P_timf_alpha += 2 */
1340 tmp = dib7000p_read_word(state, 26);
1341 dib7000p_write_word(state, 26, (tmp & ~(0xf << 12)) | ((((tmp >> 12) & 0xf) + 5) << 12));
Patrick Boettchera75763f2006-10-18 08:34:16 -03001342 }
1343
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001344 if (state->cfg.spur_protect)
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -03001345 dib7000p_spur_protect(state, ch->frequency / 1000, BANDWIDTH_TO_KHZ(ch->bandwidth_hz));
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001346
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -03001347 dib7000p_set_bandwidth(state, BANDWIDTH_TO_KHZ(ch->bandwidth_hz));
Patrick Boettchera75763f2006-10-18 08:34:16 -03001348 return 0;
1349}
1350
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001351static int dib7000p_wakeup(struct dvb_frontend *demod)
Patrick Boettchera75763f2006-10-18 08:34:16 -03001352{
Patrick Boettchera75763f2006-10-18 08:34:16 -03001353 struct dib7000p_state *state = demod->demodulator_priv;
Patrick Boettchera75763f2006-10-18 08:34:16 -03001354 dib7000p_set_power_mode(state, DIB7000P_POWER_ALL);
1355 dib7000p_set_adc_state(state, DIBX000_SLOW_ADC_ON);
Olivier Grenie713d54a2011-01-04 04:54:31 -03001356 if (state->version == SOC7090)
1357 dib7000p_sad_calib(state);
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001358 return 0;
Patrick Boettchera75763f2006-10-18 08:34:16 -03001359}
1360
1361static int dib7000p_sleep(struct dvb_frontend *demod)
1362{
1363 struct dib7000p_state *state = demod->demodulator_priv;
Olivier Grenie713d54a2011-01-04 04:54:31 -03001364 if (state->version == SOC7090)
Olivier Grenie2e802862011-08-05 10:39:15 -03001365 return dib7000p_set_power_mode(state, DIB7000P_POWER_INTERFACE_ONLY);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001366 return dib7000p_set_output_mode(state, OUTMODE_HIGH_Z) | dib7000p_set_power_mode(state, DIB7000P_POWER_INTERFACE_ONLY);
1367}
1368
1369static int dib7000p_identify(struct dib7000p_state *st)
1370{
1371 u16 value;
Olivier Grenie713d54a2011-01-04 04:54:31 -03001372 dprintk("checking demod on I2C address: %d (%x)", st->i2c_addr, st->i2c_addr);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001373
1374 if ((value = dib7000p_read_word(st, 768)) != 0x01b3) {
Olivier Grenie713d54a2011-01-04 04:54:31 -03001375 dprintk("wrong Vendor ID (read=0x%x)", value);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001376 return -EREMOTEIO;
1377 }
1378
1379 if ((value = dib7000p_read_word(st, 769)) != 0x4000) {
Olivier Grenie713d54a2011-01-04 04:54:31 -03001380 dprintk("wrong Device ID (%x)", value);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001381 return -EREMOTEIO;
1382 }
1383
1384 return 0;
1385}
1386
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -03001387static int dib7000p_get_frontend(struct dvb_frontend *fe,
1388 struct dtv_frontend_properties *fep)
Patrick Boettchera75763f2006-10-18 08:34:16 -03001389{
1390 struct dib7000p_state *state = fe->demodulator_priv;
Olivier Grenie713d54a2011-01-04 04:54:31 -03001391 u16 tps = dib7000p_read_word(state, 463);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001392
1393 fep->inversion = INVERSION_AUTO;
1394
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -03001395 fep->bandwidth_hz = BANDWIDTH_TO_HZ(state->current_bandwidth);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001396
1397 switch ((tps >> 8) & 0x3) {
Olivier Grenie713d54a2011-01-04 04:54:31 -03001398 case 0:
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -03001399 fep->transmission_mode = TRANSMISSION_MODE_2K;
Olivier Grenie713d54a2011-01-04 04:54:31 -03001400 break;
1401 case 1:
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -03001402 fep->transmission_mode = TRANSMISSION_MODE_8K;
Olivier Grenie713d54a2011-01-04 04:54:31 -03001403 break;
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -03001404 /* case 2: fep->transmission_mode = TRANSMISSION_MODE_4K; break; */
Patrick Boettchera75763f2006-10-18 08:34:16 -03001405 }
1406
1407 switch (tps & 0x3) {
Olivier Grenie713d54a2011-01-04 04:54:31 -03001408 case 0:
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -03001409 fep->guard_interval = GUARD_INTERVAL_1_32;
Olivier Grenie713d54a2011-01-04 04:54:31 -03001410 break;
1411 case 1:
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -03001412 fep->guard_interval = GUARD_INTERVAL_1_16;
Olivier Grenie713d54a2011-01-04 04:54:31 -03001413 break;
1414 case 2:
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -03001415 fep->guard_interval = GUARD_INTERVAL_1_8;
Olivier Grenie713d54a2011-01-04 04:54:31 -03001416 break;
1417 case 3:
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -03001418 fep->guard_interval = GUARD_INTERVAL_1_4;
Olivier Grenie713d54a2011-01-04 04:54:31 -03001419 break;
Patrick Boettchera75763f2006-10-18 08:34:16 -03001420 }
1421
1422 switch ((tps >> 14) & 0x3) {
Olivier Grenie713d54a2011-01-04 04:54:31 -03001423 case 0:
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -03001424 fep->modulation = QPSK;
Olivier Grenie713d54a2011-01-04 04:54:31 -03001425 break;
1426 case 1:
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -03001427 fep->modulation = QAM_16;
Olivier Grenie713d54a2011-01-04 04:54:31 -03001428 break;
1429 case 2:
1430 default:
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -03001431 fep->modulation = QAM_64;
Olivier Grenie713d54a2011-01-04 04:54:31 -03001432 break;
Patrick Boettchera75763f2006-10-18 08:34:16 -03001433 }
1434
1435 /* as long as the frontend_param structure is fixed for hierarchical transmission I refuse to use it */
1436 /* (tps >> 13) & 0x1 == hrch is used, (tps >> 10) & 0x7 == alpha */
1437
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -03001438 fep->hierarchy = HIERARCHY_NONE;
Patrick Boettchera75763f2006-10-18 08:34:16 -03001439 switch ((tps >> 5) & 0x7) {
Olivier Grenie713d54a2011-01-04 04:54:31 -03001440 case 1:
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -03001441 fep->code_rate_HP = FEC_1_2;
Olivier Grenie713d54a2011-01-04 04:54:31 -03001442 break;
1443 case 2:
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -03001444 fep->code_rate_HP = FEC_2_3;
Olivier Grenie713d54a2011-01-04 04:54:31 -03001445 break;
1446 case 3:
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -03001447 fep->code_rate_HP = FEC_3_4;
Olivier Grenie713d54a2011-01-04 04:54:31 -03001448 break;
1449 case 5:
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -03001450 fep->code_rate_HP = FEC_5_6;
Olivier Grenie713d54a2011-01-04 04:54:31 -03001451 break;
1452 case 7:
1453 default:
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -03001454 fep->code_rate_HP = FEC_7_8;
Olivier Grenie713d54a2011-01-04 04:54:31 -03001455 break;
Patrick Boettchera75763f2006-10-18 08:34:16 -03001456
1457 }
1458
1459 switch ((tps >> 2) & 0x7) {
Olivier Grenie713d54a2011-01-04 04:54:31 -03001460 case 1:
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -03001461 fep->code_rate_LP = FEC_1_2;
Olivier Grenie713d54a2011-01-04 04:54:31 -03001462 break;
1463 case 2:
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -03001464 fep->code_rate_LP = FEC_2_3;
Olivier Grenie713d54a2011-01-04 04:54:31 -03001465 break;
1466 case 3:
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -03001467 fep->code_rate_LP = FEC_3_4;
Olivier Grenie713d54a2011-01-04 04:54:31 -03001468 break;
1469 case 5:
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -03001470 fep->code_rate_LP = FEC_5_6;
Olivier Grenie713d54a2011-01-04 04:54:31 -03001471 break;
1472 case 7:
1473 default:
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -03001474 fep->code_rate_LP = FEC_7_8;
Olivier Grenie713d54a2011-01-04 04:54:31 -03001475 break;
Patrick Boettchera75763f2006-10-18 08:34:16 -03001476 }
1477
1478 /* native interleaver: (dib7000p_read_word(state, 464) >> 5) & 0x1 */
1479
1480 return 0;
1481}
1482
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -03001483static int dib7000p_set_frontend(struct dvb_frontend *fe)
Patrick Boettchera75763f2006-10-18 08:34:16 -03001484{
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -03001485 struct dtv_frontend_properties *fep = &fe->dtv_property_cache, tmp;
Patrick Boettchera75763f2006-10-18 08:34:16 -03001486 struct dib7000p_state *state = fe->demodulator_priv;
Soeren Moch853ea132008-01-25 06:27:06 -03001487 int time, ret;
Patrick Boettchera75763f2006-10-18 08:34:16 -03001488
Olivier Grenie2e802862011-08-05 10:39:15 -03001489 if (state->version == SOC7090)
Olivier Grenie713d54a2011-01-04 04:54:31 -03001490 dib7090_set_diversity_in(fe, 0);
Olivier Grenie2e802862011-08-05 10:39:15 -03001491 else
Olivier Grenie713d54a2011-01-04 04:54:31 -03001492 dib7000p_set_output_mode(state, OUTMODE_HIGH_Z);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001493
Olivier Grenie713d54a2011-01-04 04:54:31 -03001494 /* maybe the parameter has been changed */
Matt Doran8f6956c2007-07-31 07:09:30 -03001495 state->sfn_workaround_active = buggy_sfn_workaround;
1496
Patrick Boettchera75763f2006-10-18 08:34:16 -03001497 if (fe->ops.tuner_ops.set_params)
Mauro Carvalho Chehab14d24d12011-12-24 12:24:33 -03001498 fe->ops.tuner_ops.set_params(fe);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001499
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001500 /* start up the AGC */
1501 state->agc_state = 0;
1502 do {
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -03001503 time = dib7000p_agc_startup(fe);
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001504 if (time != -1)
1505 msleep(time);
1506 } while (time != -1);
1507
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -03001508 if (fep->transmission_mode == TRANSMISSION_MODE_AUTO ||
1509 fep->guard_interval == GUARD_INTERVAL_AUTO || fep->modulation == QAM_AUTO || fep->code_rate_HP == FEC_AUTO) {
Patrick Boettchera75763f2006-10-18 08:34:16 -03001510 int i = 800, found;
1511
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -03001512 tmp = *fep;
1513 dib7000p_autosearch_start(fe);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001514 do {
1515 msleep(1);
1516 found = dib7000p_autosearch_is_irq(fe);
1517 } while (found == 0 && i--);
1518
Olivier Grenie713d54a2011-01-04 04:54:31 -03001519 dprintk("autosearch returns: %d", found);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001520 if (found == 0 || found == 1)
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001521 return 0;
Patrick Boettchera75763f2006-10-18 08:34:16 -03001522
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -03001523 dib7000p_get_frontend(fe, &tmp);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001524 }
1525
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -03001526 ret = dib7000p_tune(fe);
Soeren Moch853ea132008-01-25 06:27:06 -03001527
Patrick Boettchera75763f2006-10-18 08:34:16 -03001528 /* make this a config parameter */
Olivier Grenie2e802862011-08-05 10:39:15 -03001529 if (state->version == SOC7090) {
Olivier Grenie713d54a2011-01-04 04:54:31 -03001530 dib7090_set_output_mode(fe, state->cfg.output_mode);
Olivier Grenie2e802862011-08-05 10:39:15 -03001531 if (state->cfg.enMpegOutput == 0) {
1532 dib7090_setDibTxMux(state, MPEG_ON_DIBTX);
1533 dib7090_setHostBusMux(state, DIBTX_ON_HOSTBUS);
1534 }
1535 } else
Olivier Grenie713d54a2011-01-04 04:54:31 -03001536 dib7000p_set_output_mode(state, state->cfg.output_mode);
1537
1538 return ret;
Patrick Boettchera75763f2006-10-18 08:34:16 -03001539}
1540
Olivier Grenie713d54a2011-01-04 04:54:31 -03001541static int dib7000p_read_status(struct dvb_frontend *fe, fe_status_t * stat)
Patrick Boettchera75763f2006-10-18 08:34:16 -03001542{
1543 struct dib7000p_state *state = fe->demodulator_priv;
1544 u16 lock = dib7000p_read_word(state, 509);
1545
1546 *stat = 0;
1547
1548 if (lock & 0x8000)
1549 *stat |= FE_HAS_SIGNAL;
1550 if (lock & 0x3000)
1551 *stat |= FE_HAS_CARRIER;
1552 if (lock & 0x0100)
1553 *stat |= FE_HAS_VITERBI;
1554 if (lock & 0x0010)
1555 *stat |= FE_HAS_SYNC;
Olivier Grenie713d54a2011-01-04 04:54:31 -03001556 if ((lock & 0x0038) == 0x38)
Patrick Boettchera75763f2006-10-18 08:34:16 -03001557 *stat |= FE_HAS_LOCK;
1558
1559 return 0;
1560}
1561
Olivier Grenie713d54a2011-01-04 04:54:31 -03001562static int dib7000p_read_ber(struct dvb_frontend *fe, u32 * ber)
Patrick Boettchera75763f2006-10-18 08:34:16 -03001563{
1564 struct dib7000p_state *state = fe->demodulator_priv;
1565 *ber = (dib7000p_read_word(state, 500) << 16) | dib7000p_read_word(state, 501);
1566 return 0;
1567}
1568
Olivier Grenie713d54a2011-01-04 04:54:31 -03001569static int dib7000p_read_unc_blocks(struct dvb_frontend *fe, u32 * unc)
Patrick Boettchera75763f2006-10-18 08:34:16 -03001570{
1571 struct dib7000p_state *state = fe->demodulator_priv;
1572 *unc = dib7000p_read_word(state, 506);
1573 return 0;
1574}
1575
Olivier Grenie713d54a2011-01-04 04:54:31 -03001576static int dib7000p_read_signal_strength(struct dvb_frontend *fe, u16 * strength)
Patrick Boettchera75763f2006-10-18 08:34:16 -03001577{
1578 struct dib7000p_state *state = fe->demodulator_priv;
1579 u16 val = dib7000p_read_word(state, 394);
1580 *strength = 65535 - val;
1581 return 0;
1582}
1583
Olivier Grenie713d54a2011-01-04 04:54:31 -03001584static int dib7000p_read_snr(struct dvb_frontend *fe, u16 * snr)
Patrick Boettchera75763f2006-10-18 08:34:16 -03001585{
Olivier Grenieef801962009-09-15 06:46:52 -03001586 struct dib7000p_state *state = fe->demodulator_priv;
1587 u16 val;
1588 s32 signal_mant, signal_exp, noise_mant, noise_exp;
1589 u32 result = 0;
1590
1591 val = dib7000p_read_word(state, 479);
1592 noise_mant = (val >> 4) & 0xff;
1593 noise_exp = ((val & 0xf) << 2);
1594 val = dib7000p_read_word(state, 480);
1595 noise_exp += ((val >> 14) & 0x3);
1596 if ((noise_exp & 0x20) != 0)
1597 noise_exp -= 0x40;
1598
1599 signal_mant = (val >> 6) & 0xFF;
Olivier Grenie713d54a2011-01-04 04:54:31 -03001600 signal_exp = (val & 0x3F);
Olivier Grenieef801962009-09-15 06:46:52 -03001601 if ((signal_exp & 0x20) != 0)
1602 signal_exp -= 0x40;
1603
1604 if (signal_mant != 0)
Olivier Grenie713d54a2011-01-04 04:54:31 -03001605 result = intlog10(2) * 10 * signal_exp + 10 * intlog10(signal_mant);
Olivier Grenieef801962009-09-15 06:46:52 -03001606 else
1607 result = intlog10(2) * 10 * signal_exp - 100;
1608
1609 if (noise_mant != 0)
Olivier Grenie713d54a2011-01-04 04:54:31 -03001610 result -= intlog10(2) * 10 * noise_exp + 10 * intlog10(noise_mant);
Olivier Grenieef801962009-09-15 06:46:52 -03001611 else
1612 result -= intlog10(2) * 10 * noise_exp - 100;
1613
1614 *snr = result / ((1 << 24) / 10);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001615 return 0;
1616}
1617
Olivier Grenie713d54a2011-01-04 04:54:31 -03001618static int dib7000p_fe_get_tune_settings(struct dvb_frontend *fe, struct dvb_frontend_tune_settings *tune)
Patrick Boettchera75763f2006-10-18 08:34:16 -03001619{
1620 tune->min_delay_ms = 1000;
1621 return 0;
1622}
1623
1624static void dib7000p_release(struct dvb_frontend *demod)
1625{
1626 struct dib7000p_state *st = demod->demodulator_priv;
1627 dibx000_exit_i2c_master(&st->i2c_master);
Olivier Grenie713d54a2011-01-04 04:54:31 -03001628 i2c_del_adapter(&st->dib7090_tuner_adap);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001629 kfree(st);
1630}
1631
1632int dib7000pc_detection(struct i2c_adapter *i2c_adap)
1633{
Olivier Grenie5a0deee2011-05-03 12:27:33 -03001634 u8 *tx, *rx;
Patrick Boettchera75763f2006-10-18 08:34:16 -03001635 struct i2c_msg msg[2] = {
Olivier Grenie5a0deee2011-05-03 12:27:33 -03001636 {.addr = 18 >> 1, .flags = 0, .len = 2},
1637 {.addr = 18 >> 1, .flags = I2C_M_RD, .len = 2},
Patrick Boettchera75763f2006-10-18 08:34:16 -03001638 };
Olivier Grenie5a0deee2011-05-03 12:27:33 -03001639 int ret = 0;
1640
1641 tx = kzalloc(2*sizeof(u8), GFP_KERNEL);
1642 if (!tx)
1643 return -ENOMEM;
1644 rx = kzalloc(2*sizeof(u8), GFP_KERNEL);
1645 if (!rx) {
Olivier Grenie5a0deee2011-05-03 12:27:33 -03001646 ret = -ENOMEM;
Dan Carpenter0c61cc3b2011-08-06 05:00:34 -03001647 goto rx_memory_error;
Olivier Grenie5a0deee2011-05-03 12:27:33 -03001648 }
1649
1650 msg[0].buf = tx;
1651 msg[1].buf = rx;
Patrick Boettchera75763f2006-10-18 08:34:16 -03001652
1653 tx[0] = 0x03;
1654 tx[1] = 0x00;
1655
1656 if (i2c_transfer(i2c_adap, msg, 2) == 2)
1657 if (rx[0] == 0x01 && rx[1] == 0xb3) {
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001658 dprintk("-D- DiB7000PC detected");
Patrick Boettchera75763f2006-10-18 08:34:16 -03001659 return 1;
1660 }
1661
1662 msg[0].addr = msg[1].addr = 0x40;
1663
1664 if (i2c_transfer(i2c_adap, msg, 2) == 2)
1665 if (rx[0] == 0x01 && rx[1] == 0xb3) {
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001666 dprintk("-D- DiB7000PC detected");
Patrick Boettchera75763f2006-10-18 08:34:16 -03001667 return 1;
1668 }
1669
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001670 dprintk("-D- DiB7000PC not detected");
Olivier Grenie5a0deee2011-05-03 12:27:33 -03001671
1672 kfree(rx);
1673rx_memory_error:
1674 kfree(tx);
1675 return ret;
Patrick Boettchera75763f2006-10-18 08:34:16 -03001676}
1677EXPORT_SYMBOL(dib7000pc_detection);
1678
Olivier Grenie713d54a2011-01-04 04:54:31 -03001679struct i2c_adapter *dib7000p_get_i2c_master(struct dvb_frontend *demod, enum dibx000_i2c_interface intf, int gating)
Patrick Boettchera75763f2006-10-18 08:34:16 -03001680{
1681 struct dib7000p_state *st = demod->demodulator_priv;
1682 return dibx000_get_i2c_adapter(&st->i2c_master, intf, gating);
1683}
1684EXPORT_SYMBOL(dib7000p_get_i2c_master);
1685
Olivier Grenief8731f42009-09-18 04:08:43 -03001686int dib7000p_pid_filter_ctrl(struct dvb_frontend *fe, u8 onoff)
1687{
Olivier Grenie713d54a2011-01-04 04:54:31 -03001688 struct dib7000p_state *state = fe->demodulator_priv;
1689 u16 val = dib7000p_read_word(state, 235) & 0xffef;
1690 val |= (onoff & 0x1) << 4;
1691 dprintk("PID filter enabled %d", onoff);
1692 return dib7000p_write_word(state, 235, val);
Olivier Grenief8731f42009-09-18 04:08:43 -03001693}
1694EXPORT_SYMBOL(dib7000p_pid_filter_ctrl);
1695
1696int dib7000p_pid_filter(struct dvb_frontend *fe, u8 id, u16 pid, u8 onoff)
1697{
Olivier Grenie713d54a2011-01-04 04:54:31 -03001698 struct dib7000p_state *state = fe->demodulator_priv;
1699 dprintk("PID filter: index %x, PID %d, OnOff %d", id, pid, onoff);
1700 return dib7000p_write_word(state, 241 + id, onoff ? (1 << 13) | pid : 0);
Olivier Grenief8731f42009-09-18 04:08:43 -03001701}
1702EXPORT_SYMBOL(dib7000p_pid_filter);
1703
Patrick Boettchera75763f2006-10-18 08:34:16 -03001704int dib7000p_i2c_enumeration(struct i2c_adapter *i2c, int no_of_demods, u8 default_addr, struct dib7000p_config cfg[])
1705{
Randy Dunlap30d81bb2010-02-08 20:30:44 -03001706 struct dib7000p_state *dpst;
Patrick Boettchera75763f2006-10-18 08:34:16 -03001707 int k = 0;
1708 u8 new_addr = 0;
1709
Randy Dunlap30d81bb2010-02-08 20:30:44 -03001710 dpst = kzalloc(sizeof(struct dib7000p_state), GFP_KERNEL);
1711 if (!dpst)
Andrew Morton0b427602010-04-27 19:09:45 -03001712 return -ENOMEM;
Randy Dunlap30d81bb2010-02-08 20:30:44 -03001713
1714 dpst->i2c_adap = i2c;
Patrick Boettcher79fcce32011-08-03 12:08:21 -03001715 mutex_init(&dpst->i2c_buffer_lock);
Randy Dunlap30d81bb2010-02-08 20:30:44 -03001716
Olivier Grenie713d54a2011-01-04 04:54:31 -03001717 for (k = no_of_demods - 1; k >= 0; k--) {
Randy Dunlap30d81bb2010-02-08 20:30:44 -03001718 dpst->cfg = cfg[k];
Patrick Boettchera75763f2006-10-18 08:34:16 -03001719
1720 /* designated i2c address */
Olivier Grenie713d54a2011-01-04 04:54:31 -03001721 if (cfg[k].default_i2c_addr != 0)
1722 new_addr = cfg[k].default_i2c_addr + (k << 1);
1723 else
1724 new_addr = (0x40 + k) << 1;
Randy Dunlap30d81bb2010-02-08 20:30:44 -03001725 dpst->i2c_addr = new_addr;
Olivier Grenie713d54a2011-01-04 04:54:31 -03001726 dib7000p_write_word(dpst, 1287, 0x0003); /* sram lead in, rdy */
Randy Dunlap30d81bb2010-02-08 20:30:44 -03001727 if (dib7000p_identify(dpst) != 0) {
1728 dpst->i2c_addr = default_addr;
Olivier Grenie713d54a2011-01-04 04:54:31 -03001729 dib7000p_write_word(dpst, 1287, 0x0003); /* sram lead in, rdy */
Randy Dunlap30d81bb2010-02-08 20:30:44 -03001730 if (dib7000p_identify(dpst) != 0) {
Patrick Boettchera75763f2006-10-18 08:34:16 -03001731 dprintk("DiB7000P #%d: not identified\n", k);
Randy Dunlap30d81bb2010-02-08 20:30:44 -03001732 kfree(dpst);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001733 return -EIO;
1734 }
1735 }
1736
1737 /* start diversity to pull_down div_str - just for i2c-enumeration */
Randy Dunlap30d81bb2010-02-08 20:30:44 -03001738 dib7000p_set_output_mode(dpst, OUTMODE_DIVERSITY);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001739
1740 /* set new i2c address and force divstart */
Randy Dunlap30d81bb2010-02-08 20:30:44 -03001741 dib7000p_write_word(dpst, 1285, (new_addr << 2) | 0x2);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001742
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001743 dprintk("IC %d initialized (to i2c_address 0x%x)", k, new_addr);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001744 }
1745
1746 for (k = 0; k < no_of_demods; k++) {
Randy Dunlap30d81bb2010-02-08 20:30:44 -03001747 dpst->cfg = cfg[k];
Olivier Grenie713d54a2011-01-04 04:54:31 -03001748 if (cfg[k].default_i2c_addr != 0)
1749 dpst->i2c_addr = (cfg[k].default_i2c_addr + k) << 1;
1750 else
1751 dpst->i2c_addr = (0x40 + k) << 1;
Patrick Boettchera75763f2006-10-18 08:34:16 -03001752
1753 // unforce divstr
Randy Dunlap30d81bb2010-02-08 20:30:44 -03001754 dib7000p_write_word(dpst, 1285, dpst->i2c_addr << 2);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001755
1756 /* deactivate div - it was just for i2c-enumeration */
Randy Dunlap30d81bb2010-02-08 20:30:44 -03001757 dib7000p_set_output_mode(dpst, OUTMODE_HIGH_Z);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001758 }
1759
Randy Dunlap30d81bb2010-02-08 20:30:44 -03001760 kfree(dpst);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001761 return 0;
1762}
1763EXPORT_SYMBOL(dib7000p_i2c_enumeration);
1764
Olivier Grenie713d54a2011-01-04 04:54:31 -03001765static const s32 lut_1000ln_mant[] = {
1766 6908, 6956, 7003, 7047, 7090, 7131, 7170, 7208, 7244, 7279, 7313, 7346, 7377, 7408, 7438, 7467, 7495, 7523, 7549, 7575, 7600
1767};
1768
1769static s32 dib7000p_get_adc_power(struct dvb_frontend *fe)
1770{
1771 struct dib7000p_state *state = fe->demodulator_priv;
1772 u32 tmp_val = 0, exp = 0, mant = 0;
1773 s32 pow_i;
1774 u16 buf[2];
1775 u8 ix = 0;
1776
1777 buf[0] = dib7000p_read_word(state, 0x184);
1778 buf[1] = dib7000p_read_word(state, 0x185);
1779 pow_i = (buf[0] << 16) | buf[1];
1780 dprintk("raw pow_i = %d", pow_i);
1781
1782 tmp_val = pow_i;
1783 while (tmp_val >>= 1)
1784 exp++;
1785
1786 mant = (pow_i * 1000 / (1 << exp));
1787 dprintk(" mant = %d exp = %d", mant / 1000, exp);
1788
1789 ix = (u8) ((mant - 1000) / 100); /* index of the LUT */
1790 dprintk(" ix = %d", ix);
1791
1792 pow_i = (lut_1000ln_mant[ix] + 693 * (exp - 20) - 6908);
1793 pow_i = (pow_i << 8) / 1000;
1794 dprintk(" pow_i = %d", pow_i);
1795
1796 return pow_i;
1797}
1798
1799static int map_addr_to_serpar_number(struct i2c_msg *msg)
1800{
1801 if ((msg->buf[0] <= 15))
1802 msg->buf[0] -= 1;
1803 else if (msg->buf[0] == 17)
1804 msg->buf[0] = 15;
1805 else if (msg->buf[0] == 16)
1806 msg->buf[0] = 17;
1807 else if (msg->buf[0] == 19)
1808 msg->buf[0] = 16;
1809 else if (msg->buf[0] >= 21 && msg->buf[0] <= 25)
1810 msg->buf[0] -= 3;
1811 else if (msg->buf[0] == 28)
1812 msg->buf[0] = 23;
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001813 else
Olivier Grenie713d54a2011-01-04 04:54:31 -03001814 return -EINVAL;
Olivier Grenie713d54a2011-01-04 04:54:31 -03001815 return 0;
1816}
1817
1818static int w7090p_tuner_write_serpar(struct i2c_adapter *i2c_adap, struct i2c_msg msg[], int num)
1819{
1820 struct dib7000p_state *state = i2c_get_adapdata(i2c_adap);
1821 u8 n_overflow = 1;
1822 u16 i = 1000;
1823 u16 serpar_num = msg[0].buf[0];
1824
1825 while (n_overflow == 1 && i) {
1826 n_overflow = (dib7000p_read_word(state, 1984) >> 1) & 0x1;
1827 i--;
1828 if (i == 0)
1829 dprintk("Tuner ITF: write busy (overflow)");
1830 }
1831 dib7000p_write_word(state, 1985, (1 << 6) | (serpar_num & 0x3f));
1832 dib7000p_write_word(state, 1986, (msg[0].buf[1] << 8) | msg[0].buf[2]);
1833
1834 return num;
1835}
1836
1837static int w7090p_tuner_read_serpar(struct i2c_adapter *i2c_adap, struct i2c_msg msg[], int num)
1838{
1839 struct dib7000p_state *state = i2c_get_adapdata(i2c_adap);
1840 u8 n_overflow = 1, n_empty = 1;
1841 u16 i = 1000;
1842 u16 serpar_num = msg[0].buf[0];
1843 u16 read_word;
1844
1845 while (n_overflow == 1 && i) {
1846 n_overflow = (dib7000p_read_word(state, 1984) >> 1) & 0x1;
1847 i--;
1848 if (i == 0)
1849 dprintk("TunerITF: read busy (overflow)");
1850 }
1851 dib7000p_write_word(state, 1985, (0 << 6) | (serpar_num & 0x3f));
1852
1853 i = 1000;
1854 while (n_empty == 1 && i) {
1855 n_empty = dib7000p_read_word(state, 1984) & 0x1;
1856 i--;
1857 if (i == 0)
1858 dprintk("TunerITF: read busy (empty)");
1859 }
1860 read_word = dib7000p_read_word(state, 1987);
1861 msg[1].buf[0] = (read_word >> 8) & 0xff;
1862 msg[1].buf[1] = (read_word) & 0xff;
1863
1864 return num;
1865}
1866
1867static int w7090p_tuner_rw_serpar(struct i2c_adapter *i2c_adap, struct i2c_msg msg[], int num)
1868{
1869 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... */
1870 if (num == 1) { /* write */
1871 return w7090p_tuner_write_serpar(i2c_adap, msg, 1);
1872 } else { /* read */
1873 return w7090p_tuner_read_serpar(i2c_adap, msg, 2);
1874 }
1875 }
1876 return num;
1877}
1878
Olivier Greniea685dbb2011-08-05 14:10:40 -03001879static int dib7090p_rw_on_apb(struct i2c_adapter *i2c_adap,
1880 struct i2c_msg msg[], int num, u16 apb_address)
Olivier Grenie713d54a2011-01-04 04:54:31 -03001881{
1882 struct dib7000p_state *state = i2c_get_adapdata(i2c_adap);
1883 u16 word;
1884
1885 if (num == 1) { /* write */
1886 dib7000p_write_word(state, apb_address, ((msg[0].buf[1] << 8) | (msg[0].buf[2])));
1887 } else {
1888 word = dib7000p_read_word(state, apb_address);
1889 msg[1].buf[0] = (word >> 8) & 0xff;
1890 msg[1].buf[1] = (word) & 0xff;
1891 }
1892
1893 return num;
1894}
1895
1896static int dib7090_tuner_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg msg[], int num)
1897{
1898 struct dib7000p_state *state = i2c_get_adapdata(i2c_adap);
1899
1900 u16 apb_address = 0, word;
1901 int i = 0;
1902 switch (msg[0].buf[0]) {
1903 case 0x12:
1904 apb_address = 1920;
1905 break;
1906 case 0x14:
1907 apb_address = 1921;
1908 break;
1909 case 0x24:
1910 apb_address = 1922;
1911 break;
1912 case 0x1a:
1913 apb_address = 1923;
1914 break;
1915 case 0x22:
1916 apb_address = 1924;
1917 break;
1918 case 0x33:
1919 apb_address = 1926;
1920 break;
1921 case 0x34:
1922 apb_address = 1927;
1923 break;
1924 case 0x35:
1925 apb_address = 1928;
1926 break;
1927 case 0x36:
1928 apb_address = 1929;
1929 break;
1930 case 0x37:
1931 apb_address = 1930;
1932 break;
1933 case 0x38:
1934 apb_address = 1931;
1935 break;
1936 case 0x39:
1937 apb_address = 1932;
1938 break;
1939 case 0x2a:
1940 apb_address = 1935;
1941 break;
1942 case 0x2b:
1943 apb_address = 1936;
1944 break;
1945 case 0x2c:
1946 apb_address = 1937;
1947 break;
1948 case 0x2d:
1949 apb_address = 1938;
1950 break;
1951 case 0x2e:
1952 apb_address = 1939;
1953 break;
1954 case 0x2f:
1955 apb_address = 1940;
1956 break;
1957 case 0x30:
1958 apb_address = 1941;
1959 break;
1960 case 0x31:
1961 apb_address = 1942;
1962 break;
1963 case 0x32:
1964 apb_address = 1943;
1965 break;
1966 case 0x3e:
1967 apb_address = 1944;
1968 break;
1969 case 0x3f:
1970 apb_address = 1945;
1971 break;
1972 case 0x40:
1973 apb_address = 1948;
1974 break;
1975 case 0x25:
1976 apb_address = 914;
1977 break;
1978 case 0x26:
1979 apb_address = 915;
1980 break;
1981 case 0x27:
Olivier Grenie2e802862011-08-05 10:39:15 -03001982 apb_address = 917;
Olivier Grenie713d54a2011-01-04 04:54:31 -03001983 break;
1984 case 0x28:
Olivier Grenie2e802862011-08-05 10:39:15 -03001985 apb_address = 916;
Olivier Grenie713d54a2011-01-04 04:54:31 -03001986 break;
1987 case 0x1d:
1988 i = ((dib7000p_read_word(state, 72) >> 12) & 0x3);
1989 word = dib7000p_read_word(state, 384 + i);
1990 msg[1].buf[0] = (word >> 8) & 0xff;
1991 msg[1].buf[1] = (word) & 0xff;
1992 return num;
1993 case 0x1f:
1994 if (num == 1) { /* write */
1995 word = (u16) ((msg[0].buf[1] << 8) | msg[0].buf[2]);
1996 word &= 0x3;
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001997 word = (dib7000p_read_word(state, 72) & ~(3 << 12)) | (word << 12);
Olivier Grenie713d54a2011-01-04 04:54:31 -03001998 dib7000p_write_word(state, 72, word); /* Set the proper input */
1999 return num;
2000 }
2001 }
2002
2003 if (apb_address != 0) /* R/W acces via APB */
2004 return dib7090p_rw_on_apb(i2c_adap, msg, num, apb_address);
2005 else /* R/W access via SERPAR */
2006 return w7090p_tuner_rw_serpar(i2c_adap, msg, num);
2007
2008 return 0;
2009}
2010
2011static u32 dib7000p_i2c_func(struct i2c_adapter *adapter)
2012{
2013 return I2C_FUNC_I2C;
2014}
2015
2016static struct i2c_algorithm dib7090_tuner_xfer_algo = {
2017 .master_xfer = dib7090_tuner_xfer,
2018 .functionality = dib7000p_i2c_func,
2019};
2020
2021struct i2c_adapter *dib7090_get_i2c_tuner(struct dvb_frontend *fe)
2022{
2023 struct dib7000p_state *st = fe->demodulator_priv;
2024 return &st->dib7090_tuner_adap;
2025}
2026EXPORT_SYMBOL(dib7090_get_i2c_tuner);
2027
2028static int dib7090_host_bus_drive(struct dib7000p_state *state, u8 drive)
2029{
2030 u16 reg;
2031
2032 /* drive host bus 2, 3, 4 */
2033 reg = dib7000p_read_word(state, 1798) & ~((0x7) | (0x7 << 6) | (0x7 << 12));
2034 reg |= (drive << 12) | (drive << 6) | drive;
2035 dib7000p_write_word(state, 1798, reg);
2036
2037 /* drive host bus 5,6 */
2038 reg = dib7000p_read_word(state, 1799) & ~((0x7 << 2) | (0x7 << 8));
2039 reg |= (drive << 8) | (drive << 2);
2040 dib7000p_write_word(state, 1799, reg);
2041
2042 /* drive host bus 7, 8, 9 */
2043 reg = dib7000p_read_word(state, 1800) & ~((0x7) | (0x7 << 6) | (0x7 << 12));
2044 reg |= (drive << 12) | (drive << 6) | drive;
2045 dib7000p_write_word(state, 1800, reg);
2046
2047 /* drive host bus 10, 11 */
2048 reg = dib7000p_read_word(state, 1801) & ~((0x7 << 2) | (0x7 << 8));
2049 reg |= (drive << 8) | (drive << 2);
2050 dib7000p_write_word(state, 1801, reg);
2051
2052 /* drive host bus 12, 13, 14 */
2053 reg = dib7000p_read_word(state, 1802) & ~((0x7) | (0x7 << 6) | (0x7 << 12));
2054 reg |= (drive << 12) | (drive << 6) | drive;
2055 dib7000p_write_word(state, 1802, reg);
2056
2057 return 0;
2058}
2059
2060static u32 dib7090_calcSyncFreq(u32 P_Kin, u32 P_Kout, u32 insertExtSynchro, u32 syncSize)
2061{
2062 u32 quantif = 3;
2063 u32 nom = (insertExtSynchro * P_Kin + syncSize);
2064 u32 denom = P_Kout;
2065 u32 syncFreq = ((nom << quantif) / denom);
2066
2067 if ((syncFreq & ((1 << quantif) - 1)) != 0)
2068 syncFreq = (syncFreq >> quantif) + 1;
2069 else
2070 syncFreq = (syncFreq >> quantif);
2071
2072 if (syncFreq != 0)
2073 syncFreq = syncFreq - 1;
2074
2075 return syncFreq;
2076}
2077
2078static int dib7090_cfg_DibTx(struct dib7000p_state *state, u32 P_Kin, u32 P_Kout, u32 insertExtSynchro, u32 synchroMode, u32 syncWord, u32 syncSize)
2079{
Olivier Grenie713d54a2011-01-04 04:54:31 -03002080 dprintk("Configure DibStream Tx");
Olivier Grenie713d54a2011-01-04 04:54:31 -03002081
2082 dib7000p_write_word(state, 1615, 1);
2083 dib7000p_write_word(state, 1603, P_Kin);
2084 dib7000p_write_word(state, 1605, P_Kout);
2085 dib7000p_write_word(state, 1606, insertExtSynchro);
2086 dib7000p_write_word(state, 1608, synchroMode);
2087 dib7000p_write_word(state, 1609, (syncWord >> 16) & 0xffff);
2088 dib7000p_write_word(state, 1610, syncWord & 0xffff);
2089 dib7000p_write_word(state, 1612, syncSize);
2090 dib7000p_write_word(state, 1615, 0);
2091
Olivier Grenie713d54a2011-01-04 04:54:31 -03002092 return 0;
2093}
2094
2095static int dib7090_cfg_DibRx(struct dib7000p_state *state, u32 P_Kin, u32 P_Kout, u32 synchroMode, u32 insertExtSynchro, u32 syncWord, u32 syncSize,
2096 u32 dataOutRate)
2097{
2098 u32 syncFreq;
2099
2100 dprintk("Configure DibStream Rx");
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002101 if ((P_Kin != 0) && (P_Kout != 0)) {
Olivier Grenie713d54a2011-01-04 04:54:31 -03002102 syncFreq = dib7090_calcSyncFreq(P_Kin, P_Kout, insertExtSynchro, syncSize);
2103 dib7000p_write_word(state, 1542, syncFreq);
2104 }
2105 dib7000p_write_word(state, 1554, 1);
2106 dib7000p_write_word(state, 1536, P_Kin);
2107 dib7000p_write_word(state, 1537, P_Kout);
2108 dib7000p_write_word(state, 1539, synchroMode);
2109 dib7000p_write_word(state, 1540, (syncWord >> 16) & 0xffff);
2110 dib7000p_write_word(state, 1541, syncWord & 0xffff);
2111 dib7000p_write_word(state, 1543, syncSize);
2112 dib7000p_write_word(state, 1544, dataOutRate);
2113 dib7000p_write_word(state, 1554, 0);
2114
2115 return 0;
2116}
2117
Olivier Grenie2e802862011-08-05 10:39:15 -03002118static void dib7090_enMpegMux(struct dib7000p_state *state, int onoff)
Olivier Grenie713d54a2011-01-04 04:54:31 -03002119{
Olivier Grenie2e802862011-08-05 10:39:15 -03002120 u16 reg_1287 = dib7000p_read_word(state, 1287);
Olivier Grenie713d54a2011-01-04 04:54:31 -03002121
Olivier Grenie2e802862011-08-05 10:39:15 -03002122 switch (onoff) {
2123 case 1:
2124 reg_1287 &= ~(1<<7);
2125 break;
2126 case 0:
2127 reg_1287 |= (1<<7);
2128 break;
2129 }
Olivier Grenie713d54a2011-01-04 04:54:31 -03002130
Olivier Grenie2e802862011-08-05 10:39:15 -03002131 dib7000p_write_word(state, 1287, reg_1287);
Olivier Grenie713d54a2011-01-04 04:54:31 -03002132}
2133
Olivier Grenie2e802862011-08-05 10:39:15 -03002134static void dib7090_configMpegMux(struct dib7000p_state *state,
2135 u16 pulseWidth, u16 enSerialMode, u16 enSerialClkDiv2)
Olivier Grenie713d54a2011-01-04 04:54:31 -03002136{
Olivier Grenie713d54a2011-01-04 04:54:31 -03002137 dprintk("Enable Mpeg mux");
Olivier Grenie713d54a2011-01-04 04:54:31 -03002138
Olivier Grenie2e802862011-08-05 10:39:15 -03002139 dib7090_enMpegMux(state, 0);
Olivier Grenie713d54a2011-01-04 04:54:31 -03002140
Olivier Grenie2e802862011-08-05 10:39:15 -03002141 /* If the input mode is MPEG do not divide the serial clock */
2142 if ((enSerialMode == 1) && (state->input_mode_mpeg == 1))
2143 enSerialClkDiv2 = 0;
Olivier Grenie713d54a2011-01-04 04:54:31 -03002144
Olivier Grenie2e802862011-08-05 10:39:15 -03002145 dib7000p_write_word(state, 1287, ((pulseWidth & 0x1f) << 2)
2146 | ((enSerialMode & 0x1) << 1)
2147 | (enSerialClkDiv2 & 0x1));
2148
2149 dib7090_enMpegMux(state, 1);
Olivier Grenie713d54a2011-01-04 04:54:31 -03002150}
2151
Olivier Grenie2e802862011-08-05 10:39:15 -03002152static void dib7090_setDibTxMux(struct dib7000p_state *state, int mode)
Olivier Grenie713d54a2011-01-04 04:54:31 -03002153{
Olivier Grenie2e802862011-08-05 10:39:15 -03002154 u16 reg_1288 = dib7000p_read_word(state, 1288) & ~(0x7 << 7);
Olivier Grenie713d54a2011-01-04 04:54:31 -03002155
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002156 switch (mode) {
Olivier Grenie2e802862011-08-05 10:39:15 -03002157 case MPEG_ON_DIBTX:
2158 dprintk("SET MPEG ON DIBSTREAM TX");
2159 dib7090_cfg_DibTx(state, 8, 5, 0, 0, 0, 0);
2160 reg_1288 |= (1<<9);
Olivier Grenie713d54a2011-01-04 04:54:31 -03002161 break;
Olivier Grenie2e802862011-08-05 10:39:15 -03002162 case DIV_ON_DIBTX:
2163 dprintk("SET DIV_OUT ON DIBSTREAM TX");
2164 dib7090_cfg_DibTx(state, 5, 5, 0, 0, 0, 0);
2165 reg_1288 |= (1<<8);
Olivier Grenie713d54a2011-01-04 04:54:31 -03002166 break;
Olivier Grenie2e802862011-08-05 10:39:15 -03002167 case ADC_ON_DIBTX:
2168 dprintk("SET ADC_OUT ON DIBSTREAM TX");
2169 dib7090_cfg_DibTx(state, 20, 5, 10, 0, 0, 0);
2170 reg_1288 |= (1<<7);
2171 break;
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002172 default:
Olivier Grenie713d54a2011-01-04 04:54:31 -03002173 break;
2174 }
Olivier Grenie2e802862011-08-05 10:39:15 -03002175 dib7000p_write_word(state, 1288, reg_1288);
Olivier Grenie713d54a2011-01-04 04:54:31 -03002176}
2177
Olivier Grenie2e802862011-08-05 10:39:15 -03002178static void dib7090_setHostBusMux(struct dib7000p_state *state, int mode)
Olivier Grenie713d54a2011-01-04 04:54:31 -03002179{
Olivier Grenie2e802862011-08-05 10:39:15 -03002180 u16 reg_1288 = dib7000p_read_word(state, 1288) & ~(0x7 << 4);
2181
2182 switch (mode) {
2183 case DEMOUT_ON_HOSTBUS:
2184 dprintk("SET DEM OUT OLD INTERF ON HOST BUS");
2185 dib7090_enMpegMux(state, 0);
2186 reg_1288 |= (1<<6);
2187 break;
2188 case DIBTX_ON_HOSTBUS:
2189 dprintk("SET DIBSTREAM TX ON HOST BUS");
2190 dib7090_enMpegMux(state, 0);
2191 reg_1288 |= (1<<5);
2192 break;
2193 case MPEG_ON_HOSTBUS:
2194 dprintk("SET MPEG MUX ON HOST BUS");
2195 reg_1288 |= (1<<4);
2196 break;
2197 default:
2198 break;
2199 }
2200 dib7000p_write_word(state, 1288, reg_1288);
2201}
2202
2203int dib7090_set_diversity_in(struct dvb_frontend *fe, int onoff)
2204{
2205 struct dib7000p_state *state = fe->demodulator_priv;
2206 u16 reg_1287;
2207
Olivier Grenie713d54a2011-01-04 04:54:31 -03002208 switch (onoff) {
Olivier Grenie2e802862011-08-05 10:39:15 -03002209 case 0: /* only use the internal way - not the diversity input */
2210 dprintk("%s mode OFF : by default Enable Mpeg INPUT", __func__);
2211 dib7090_cfg_DibRx(state, 8, 5, 0, 0, 0, 8, 0);
2212
2213 /* Do not divide the serial clock of MPEG MUX */
2214 /* in SERIAL MODE in case input mode MPEG is used */
2215 reg_1287 = dib7000p_read_word(state, 1287);
2216 /* enSerialClkDiv2 == 1 ? */
2217 if ((reg_1287 & 0x1) == 1) {
2218 /* force enSerialClkDiv2 = 0 */
2219 reg_1287 &= ~0x1;
2220 dib7000p_write_word(state, 1287, reg_1287);
2221 }
2222 state->input_mode_mpeg = 1;
2223 break;
2224 case 1: /* both ways */
2225 case 2: /* only the diversity input */
2226 dprintk("%s ON : Enable diversity INPUT", __func__);
2227 dib7090_cfg_DibRx(state, 5, 5, 0, 0, 0, 0, 0);
2228 state->input_mode_mpeg = 0;
2229 break;
Olivier Grenie713d54a2011-01-04 04:54:31 -03002230 }
2231
Olivier Grenie2e802862011-08-05 10:39:15 -03002232 dib7000p_set_diversity_in(&state->demod, onoff);
Olivier Grenie713d54a2011-01-04 04:54:31 -03002233 return 0;
2234}
2235
2236static int dib7090_set_output_mode(struct dvb_frontend *fe, int mode)
2237{
2238 struct dib7000p_state *state = fe->demodulator_priv;
2239
2240 u16 outreg, smo_mode, fifo_threshold;
2241 u8 prefer_mpeg_mux_use = 1;
2242 int ret = 0;
2243
2244 dib7090_host_bus_drive(state, 1);
2245
2246 fifo_threshold = 1792;
2247 smo_mode = (dib7000p_read_word(state, 235) & 0x0050) | (1 << 1);
2248 outreg = dib7000p_read_word(state, 1286) & ~((1 << 10) | (0x7 << 6) | (1 << 1));
2249
2250 switch (mode) {
2251 case OUTMODE_HIGH_Z:
2252 outreg = 0;
2253 break;
2254
2255 case OUTMODE_MPEG2_SERIAL:
2256 if (prefer_mpeg_mux_use) {
Olivier Grenie2e802862011-08-05 10:39:15 -03002257 dprintk("setting output mode TS_SERIAL using Mpeg Mux");
2258 dib7090_configMpegMux(state, 3, 1, 1);
2259 dib7090_setHostBusMux(state, MPEG_ON_HOSTBUS);
2260 } else {/* Use Smooth block */
2261 dprintk("setting output mode TS_SERIAL using Smooth bloc");
2262 dib7090_setHostBusMux(state, DEMOUT_ON_HOSTBUS);
2263 outreg |= (2<<6) | (0 << 1);
Olivier Grenie713d54a2011-01-04 04:54:31 -03002264 }
2265 break;
2266
2267 case OUTMODE_MPEG2_PAR_GATED_CLK:
2268 if (prefer_mpeg_mux_use) {
Olivier Grenie2e802862011-08-05 10:39:15 -03002269 dprintk("setting output mode TS_PARALLEL_GATED using Mpeg Mux");
2270 dib7090_configMpegMux(state, 2, 0, 0);
2271 dib7090_setHostBusMux(state, MPEG_ON_HOSTBUS);
2272 } else { /* Use Smooth block */
2273 dprintk("setting output mode TS_PARALLEL_GATED using Smooth block");
2274 dib7090_setHostBusMux(state, DEMOUT_ON_HOSTBUS);
2275 outreg |= (0<<6);
Olivier Grenie713d54a2011-01-04 04:54:31 -03002276 }
2277 break;
2278
2279 case OUTMODE_MPEG2_PAR_CONT_CLK: /* Using Smooth block only */
Olivier Grenie2e802862011-08-05 10:39:15 -03002280 dprintk("setting output mode TS_PARALLEL_CONT using Smooth block");
2281 dib7090_setHostBusMux(state, DEMOUT_ON_HOSTBUS);
2282 outreg |= (1<<6);
Olivier Grenie713d54a2011-01-04 04:54:31 -03002283 break;
2284
2285 case OUTMODE_MPEG2_FIFO: /* Using Smooth block because not supported by new Mpeg Mux bloc */
Olivier Grenie2e802862011-08-05 10:39:15 -03002286 dprintk("setting output mode TS_FIFO using Smooth block");
2287 dib7090_setHostBusMux(state, DEMOUT_ON_HOSTBUS);
2288 outreg |= (5<<6);
Olivier Grenie713d54a2011-01-04 04:54:31 -03002289 smo_mode |= (3 << 1);
2290 fifo_threshold = 512;
2291 break;
2292
2293 case OUTMODE_DIVERSITY:
Olivier Grenie2e802862011-08-05 10:39:15 -03002294 dprintk("setting output mode MODE_DIVERSITY");
2295 dib7090_setDibTxMux(state, DIV_ON_DIBTX);
2296 dib7090_setHostBusMux(state, DIBTX_ON_HOSTBUS);
Olivier Grenie713d54a2011-01-04 04:54:31 -03002297 break;
2298
2299 case OUTMODE_ANALOG_ADC:
Olivier Grenie2e802862011-08-05 10:39:15 -03002300 dprintk("setting output mode MODE_ANALOG_ADC");
2301 dib7090_setDibTxMux(state, ADC_ON_DIBTX);
2302 dib7090_setHostBusMux(state, DIBTX_ON_HOSTBUS);
Olivier Grenie713d54a2011-01-04 04:54:31 -03002303 break;
2304 }
Olivier Grenie2e802862011-08-05 10:39:15 -03002305 if (mode != OUTMODE_HIGH_Z)
2306 outreg |= (1 << 10);
Olivier Grenie713d54a2011-01-04 04:54:31 -03002307
2308 if (state->cfg.output_mpeg2_in_188_bytes)
2309 smo_mode |= (1 << 5);
2310
2311 ret |= dib7000p_write_word(state, 235, smo_mode);
2312 ret |= dib7000p_write_word(state, 236, fifo_threshold); /* synchronous fread */
Olivier Grenie2e802862011-08-05 10:39:15 -03002313 ret |= dib7000p_write_word(state, 1286, outreg);
Olivier Grenie713d54a2011-01-04 04:54:31 -03002314
2315 return ret;
2316}
2317
2318int dib7090_tuner_sleep(struct dvb_frontend *fe, int onoff)
2319{
2320 struct dib7000p_state *state = fe->demodulator_priv;
2321 u16 en_cur_state;
2322
2323 dprintk("sleep dib7090: %d", onoff);
2324
2325 en_cur_state = dib7000p_read_word(state, 1922);
2326
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002327 if (en_cur_state > 0xff)
Olivier Grenie713d54a2011-01-04 04:54:31 -03002328 state->tuner_enable = en_cur_state;
Olivier Grenie713d54a2011-01-04 04:54:31 -03002329
2330 if (onoff)
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002331 en_cur_state &= 0x00ff;
Olivier Grenie713d54a2011-01-04 04:54:31 -03002332 else {
2333 if (state->tuner_enable != 0)
2334 en_cur_state = state->tuner_enable;
2335 }
2336
2337 dib7000p_write_word(state, 1922, en_cur_state);
2338
2339 return 0;
2340}
2341EXPORT_SYMBOL(dib7090_tuner_sleep);
2342
Olivier Grenie713d54a2011-01-04 04:54:31 -03002343int dib7090_get_adc_power(struct dvb_frontend *fe)
2344{
2345 return dib7000p_get_adc_power(fe);
2346}
2347EXPORT_SYMBOL(dib7090_get_adc_power);
2348
2349int dib7090_slave_reset(struct dvb_frontend *fe)
2350{
2351 struct dib7000p_state *state = fe->demodulator_priv;
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002352 u16 reg;
Olivier Grenie713d54a2011-01-04 04:54:31 -03002353
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002354 reg = dib7000p_read_word(state, 1794);
2355 dib7000p_write_word(state, 1794, reg | (4 << 12));
Olivier Grenie713d54a2011-01-04 04:54:31 -03002356
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002357 dib7000p_write_word(state, 1032, 0xffff);
2358 return 0;
Olivier Grenie713d54a2011-01-04 04:54:31 -03002359}
2360EXPORT_SYMBOL(dib7090_slave_reset);
2361
Patrick Boettchera75763f2006-10-18 08:34:16 -03002362static struct dvb_frontend_ops dib7000p_ops;
Olivier Grenie713d54a2011-01-04 04:54:31 -03002363struct dvb_frontend *dib7000p_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr, struct dib7000p_config *cfg)
Patrick Boettchera75763f2006-10-18 08:34:16 -03002364{
2365 struct dvb_frontend *demod;
2366 struct dib7000p_state *st;
2367 st = kzalloc(sizeof(struct dib7000p_state), GFP_KERNEL);
2368 if (st == NULL)
2369 return NULL;
2370
2371 memcpy(&st->cfg, cfg, sizeof(struct dib7000p_config));
2372 st->i2c_adap = i2c_adap;
2373 st->i2c_addr = i2c_addr;
2374 st->gpio_val = cfg->gpio_val;
2375 st->gpio_dir = cfg->gpio_dir;
2376
Steven Totha38d6e32008-04-22 15:37:01 -03002377 /* Ensure the output mode remains at the previous default if it's
2378 * not specifically set by the caller.
2379 */
Olivier Grenie713d54a2011-01-04 04:54:31 -03002380 if ((st->cfg.output_mode != OUTMODE_MPEG2_SERIAL) && (st->cfg.output_mode != OUTMODE_MPEG2_PAR_GATED_CLK))
Steven Totha38d6e32008-04-22 15:37:01 -03002381 st->cfg.output_mode = OUTMODE_MPEG2_FIFO;
2382
Olivier Grenie713d54a2011-01-04 04:54:31 -03002383 demod = &st->demod;
Patrick Boettchera75763f2006-10-18 08:34:16 -03002384 demod->demodulator_priv = st;
2385 memcpy(&st->demod.ops, &dib7000p_ops, sizeof(struct dvb_frontend_ops));
Patrick Boettcher79fcce32011-08-03 12:08:21 -03002386 mutex_init(&st->i2c_buffer_lock);
Patrick Boettchera75763f2006-10-18 08:34:16 -03002387
Olivier Grenie713d54a2011-01-04 04:54:31 -03002388 dib7000p_write_word(st, 1287, 0x0003); /* sram lead in, rdy */
Olivier Grenieeac1fe12009-09-23 13:41:27 -03002389
Patrick Boettchera75763f2006-10-18 08:34:16 -03002390 if (dib7000p_identify(st) != 0)
2391 goto error;
2392
Olivier Grenie713d54a2011-01-04 04:54:31 -03002393 st->version = dib7000p_read_word(st, 897);
2394
Martin Samek7646b9d2009-09-30 22:59:09 -03002395 /* FIXME: make sure the dev.parent field is initialized, or else
Patrick Boettcher79fcce32011-08-03 12:08:21 -03002396 request_firmware() will hit an OOPS (this should be moved somewhere
2397 more common) */
2398 st->i2c_master.gated_tuner_i2c_adap.dev.parent = i2c_adap->dev.parent;
Martin Samek7646b9d2009-09-30 22:59:09 -03002399
Devin Heitmueller85ec9d72009-07-20 00:45:25 -03002400 /* FIXME: make sure the dev.parent field is initialized, or else
2401 request_firmware() will hit an OOPS (this should be moved somewhere
2402 more common) */
2403 st->i2c_master.gated_tuner_i2c_adap.dev.parent = i2c_adap->dev.parent;
2404
Patrick Boettchera75763f2006-10-18 08:34:16 -03002405 dibx000_init_i2c_master(&st->i2c_master, DIB7000P, st->i2c_adap, st->i2c_addr);
2406
Olivier Grenie713d54a2011-01-04 04:54:31 -03002407 /* init 7090 tuner adapter */
2408 strncpy(st->dib7090_tuner_adap.name, "DiB7090 tuner interface", sizeof(st->dib7090_tuner_adap.name));
2409 st->dib7090_tuner_adap.algo = &dib7090_tuner_xfer_algo;
2410 st->dib7090_tuner_adap.algo_data = NULL;
2411 st->dib7090_tuner_adap.dev.parent = st->i2c_adap->dev.parent;
2412 i2c_set_adapdata(&st->dib7090_tuner_adap, st);
2413 i2c_add_adapter(&st->dib7090_tuner_adap);
2414
Patrick Boettchera75763f2006-10-18 08:34:16 -03002415 dib7000p_demod_reset(st);
2416
Olivier Grenie713d54a2011-01-04 04:54:31 -03002417 if (st->version == SOC7090) {
2418 dib7090_set_output_mode(demod, st->cfg.output_mode);
2419 dib7090_set_diversity_in(demod, 0);
2420 }
2421
Patrick Boettchera75763f2006-10-18 08:34:16 -03002422 return demod;
2423
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002424error:
Patrick Boettchera75763f2006-10-18 08:34:16 -03002425 kfree(st);
2426 return NULL;
2427}
2428EXPORT_SYMBOL(dib7000p_attach);
2429
2430static struct dvb_frontend_ops dib7000p_ops = {
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -03002431 .delsys = { SYS_DVBT },
Patrick Boettchera75763f2006-10-18 08:34:16 -03002432 .info = {
Olivier Grenie713d54a2011-01-04 04:54:31 -03002433 .name = "DiBcom 7000PC",
2434 .type = FE_OFDM,
2435 .frequency_min = 44250000,
2436 .frequency_max = 867250000,
2437 .frequency_stepsize = 62500,
2438 .caps = FE_CAN_INVERSION_AUTO |
2439 FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
2440 FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
2441 FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO |
2442 FE_CAN_TRANSMISSION_MODE_AUTO | FE_CAN_GUARD_INTERVAL_AUTO | FE_CAN_RECOVER | FE_CAN_HIERARCHY_AUTO,
2443 },
Patrick Boettchera75763f2006-10-18 08:34:16 -03002444
Olivier Grenie713d54a2011-01-04 04:54:31 -03002445 .release = dib7000p_release,
Patrick Boettchera75763f2006-10-18 08:34:16 -03002446
Olivier Grenie713d54a2011-01-04 04:54:31 -03002447 .init = dib7000p_wakeup,
2448 .sleep = dib7000p_sleep,
Patrick Boettchera75763f2006-10-18 08:34:16 -03002449
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -03002450 .set_frontend = dib7000p_set_frontend,
Olivier Grenie713d54a2011-01-04 04:54:31 -03002451 .get_tune_settings = dib7000p_fe_get_tune_settings,
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -03002452 .get_frontend = dib7000p_get_frontend,
Patrick Boettchera75763f2006-10-18 08:34:16 -03002453
Olivier Grenie713d54a2011-01-04 04:54:31 -03002454 .read_status = dib7000p_read_status,
2455 .read_ber = dib7000p_read_ber,
Patrick Boettchera75763f2006-10-18 08:34:16 -03002456 .read_signal_strength = dib7000p_read_signal_strength,
Olivier Grenie713d54a2011-01-04 04:54:31 -03002457 .read_snr = dib7000p_read_snr,
2458 .read_ucblocks = dib7000p_read_unc_blocks,
Patrick Boettchera75763f2006-10-18 08:34:16 -03002459};
2460
Olivier Grenie713d54a2011-01-04 04:54:31 -03002461MODULE_AUTHOR("Olivier Grenie <ogrenie@dibcom.fr>");
Patrick Boettchera75763f2006-10-18 08:34:16 -03002462MODULE_AUTHOR("Patrick Boettcher <pboettcher@dibcom.fr>");
2463MODULE_DESCRIPTION("Driver for the DiBcom 7000PC COFDM demodulator");
2464MODULE_LICENSE("GPL");