blob: 5ceadc285b3ad59ef187d4c074db352ff1155d5c [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 Chehab7c61d802011-12-30 11:30:21 -03001387static int dib7000p_get_frontend(struct dvb_frontend *fe)
Patrick Boettchera75763f2006-10-18 08:34:16 -03001388{
Mauro Carvalho Chehab7c61d802011-12-30 11:30:21 -03001389 struct dtv_frontend_properties *fep = &fe->dtv_property_cache;
Patrick Boettchera75763f2006-10-18 08:34:16 -03001390 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 Chehab7c61d802011-12-30 11:30:21 -03001485 struct dtv_frontend_properties *fep = &fe->dtv_property_cache;
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 dib7000p_autosearch_start(fe);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001513 do {
1514 msleep(1);
1515 found = dib7000p_autosearch_is_irq(fe);
1516 } while (found == 0 && i--);
1517
Olivier Grenie713d54a2011-01-04 04:54:31 -03001518 dprintk("autosearch returns: %d", found);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001519 if (found == 0 || found == 1)
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001520 return 0;
Patrick Boettchera75763f2006-10-18 08:34:16 -03001521
Mauro Carvalho Chehab7c61d802011-12-30 11:30:21 -03001522 dib7000p_get_frontend(fe);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001523 }
1524
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -03001525 ret = dib7000p_tune(fe);
Soeren Moch853ea132008-01-25 06:27:06 -03001526
Patrick Boettchera75763f2006-10-18 08:34:16 -03001527 /* make this a config parameter */
Olivier Grenie2e802862011-08-05 10:39:15 -03001528 if (state->version == SOC7090) {
Olivier Grenie713d54a2011-01-04 04:54:31 -03001529 dib7090_set_output_mode(fe, state->cfg.output_mode);
Olivier Grenie2e802862011-08-05 10:39:15 -03001530 if (state->cfg.enMpegOutput == 0) {
1531 dib7090_setDibTxMux(state, MPEG_ON_DIBTX);
1532 dib7090_setHostBusMux(state, DIBTX_ON_HOSTBUS);
1533 }
1534 } else
Olivier Grenie713d54a2011-01-04 04:54:31 -03001535 dib7000p_set_output_mode(state, state->cfg.output_mode);
1536
1537 return ret;
Patrick Boettchera75763f2006-10-18 08:34:16 -03001538}
1539
Olivier Grenie713d54a2011-01-04 04:54:31 -03001540static int dib7000p_read_status(struct dvb_frontend *fe, fe_status_t * stat)
Patrick Boettchera75763f2006-10-18 08:34:16 -03001541{
1542 struct dib7000p_state *state = fe->demodulator_priv;
1543 u16 lock = dib7000p_read_word(state, 509);
1544
1545 *stat = 0;
1546
1547 if (lock & 0x8000)
1548 *stat |= FE_HAS_SIGNAL;
1549 if (lock & 0x3000)
1550 *stat |= FE_HAS_CARRIER;
1551 if (lock & 0x0100)
1552 *stat |= FE_HAS_VITERBI;
1553 if (lock & 0x0010)
1554 *stat |= FE_HAS_SYNC;
Olivier Grenie713d54a2011-01-04 04:54:31 -03001555 if ((lock & 0x0038) == 0x38)
Patrick Boettchera75763f2006-10-18 08:34:16 -03001556 *stat |= FE_HAS_LOCK;
1557
1558 return 0;
1559}
1560
Olivier Grenie713d54a2011-01-04 04:54:31 -03001561static int dib7000p_read_ber(struct dvb_frontend *fe, u32 * ber)
Patrick Boettchera75763f2006-10-18 08:34:16 -03001562{
1563 struct dib7000p_state *state = fe->demodulator_priv;
1564 *ber = (dib7000p_read_word(state, 500) << 16) | dib7000p_read_word(state, 501);
1565 return 0;
1566}
1567
Olivier Grenie713d54a2011-01-04 04:54:31 -03001568static int dib7000p_read_unc_blocks(struct dvb_frontend *fe, u32 * unc)
Patrick Boettchera75763f2006-10-18 08:34:16 -03001569{
1570 struct dib7000p_state *state = fe->demodulator_priv;
1571 *unc = dib7000p_read_word(state, 506);
1572 return 0;
1573}
1574
Olivier Grenie713d54a2011-01-04 04:54:31 -03001575static int dib7000p_read_signal_strength(struct dvb_frontend *fe, u16 * strength)
Patrick Boettchera75763f2006-10-18 08:34:16 -03001576{
1577 struct dib7000p_state *state = fe->demodulator_priv;
1578 u16 val = dib7000p_read_word(state, 394);
1579 *strength = 65535 - val;
1580 return 0;
1581}
1582
Olivier Grenie713d54a2011-01-04 04:54:31 -03001583static int dib7000p_read_snr(struct dvb_frontend *fe, u16 * snr)
Patrick Boettchera75763f2006-10-18 08:34:16 -03001584{
Olivier Grenieef801962009-09-15 06:46:52 -03001585 struct dib7000p_state *state = fe->demodulator_priv;
1586 u16 val;
1587 s32 signal_mant, signal_exp, noise_mant, noise_exp;
1588 u32 result = 0;
1589
1590 val = dib7000p_read_word(state, 479);
1591 noise_mant = (val >> 4) & 0xff;
1592 noise_exp = ((val & 0xf) << 2);
1593 val = dib7000p_read_word(state, 480);
1594 noise_exp += ((val >> 14) & 0x3);
1595 if ((noise_exp & 0x20) != 0)
1596 noise_exp -= 0x40;
1597
1598 signal_mant = (val >> 6) & 0xFF;
Olivier Grenie713d54a2011-01-04 04:54:31 -03001599 signal_exp = (val & 0x3F);
Olivier Grenieef801962009-09-15 06:46:52 -03001600 if ((signal_exp & 0x20) != 0)
1601 signal_exp -= 0x40;
1602
1603 if (signal_mant != 0)
Olivier Grenie713d54a2011-01-04 04:54:31 -03001604 result = intlog10(2) * 10 * signal_exp + 10 * intlog10(signal_mant);
Olivier Grenieef801962009-09-15 06:46:52 -03001605 else
1606 result = intlog10(2) * 10 * signal_exp - 100;
1607
1608 if (noise_mant != 0)
Olivier Grenie713d54a2011-01-04 04:54:31 -03001609 result -= intlog10(2) * 10 * noise_exp + 10 * intlog10(noise_mant);
Olivier Grenieef801962009-09-15 06:46:52 -03001610 else
1611 result -= intlog10(2) * 10 * noise_exp - 100;
1612
1613 *snr = result / ((1 << 24) / 10);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001614 return 0;
1615}
1616
Olivier Grenie713d54a2011-01-04 04:54:31 -03001617static int dib7000p_fe_get_tune_settings(struct dvb_frontend *fe, struct dvb_frontend_tune_settings *tune)
Patrick Boettchera75763f2006-10-18 08:34:16 -03001618{
1619 tune->min_delay_ms = 1000;
1620 return 0;
1621}
1622
1623static void dib7000p_release(struct dvb_frontend *demod)
1624{
1625 struct dib7000p_state *st = demod->demodulator_priv;
1626 dibx000_exit_i2c_master(&st->i2c_master);
Olivier Grenie713d54a2011-01-04 04:54:31 -03001627 i2c_del_adapter(&st->dib7090_tuner_adap);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001628 kfree(st);
1629}
1630
1631int dib7000pc_detection(struct i2c_adapter *i2c_adap)
1632{
Olivier Grenie5a0deee2011-05-03 12:27:33 -03001633 u8 *tx, *rx;
Patrick Boettchera75763f2006-10-18 08:34:16 -03001634 struct i2c_msg msg[2] = {
Olivier Grenie5a0deee2011-05-03 12:27:33 -03001635 {.addr = 18 >> 1, .flags = 0, .len = 2},
1636 {.addr = 18 >> 1, .flags = I2C_M_RD, .len = 2},
Patrick Boettchera75763f2006-10-18 08:34:16 -03001637 };
Olivier Grenie5a0deee2011-05-03 12:27:33 -03001638 int ret = 0;
1639
1640 tx = kzalloc(2*sizeof(u8), GFP_KERNEL);
1641 if (!tx)
1642 return -ENOMEM;
1643 rx = kzalloc(2*sizeof(u8), GFP_KERNEL);
1644 if (!rx) {
Olivier Grenie5a0deee2011-05-03 12:27:33 -03001645 ret = -ENOMEM;
Dan Carpenter0c61cc3b2011-08-06 05:00:34 -03001646 goto rx_memory_error;
Olivier Grenie5a0deee2011-05-03 12:27:33 -03001647 }
1648
1649 msg[0].buf = tx;
1650 msg[1].buf = rx;
Patrick Boettchera75763f2006-10-18 08:34:16 -03001651
1652 tx[0] = 0x03;
1653 tx[1] = 0x00;
1654
1655 if (i2c_transfer(i2c_adap, msg, 2) == 2)
1656 if (rx[0] == 0x01 && rx[1] == 0xb3) {
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001657 dprintk("-D- DiB7000PC detected");
Patrick Boettchera75763f2006-10-18 08:34:16 -03001658 return 1;
1659 }
1660
1661 msg[0].addr = msg[1].addr = 0x40;
1662
1663 if (i2c_transfer(i2c_adap, msg, 2) == 2)
1664 if (rx[0] == 0x01 && rx[1] == 0xb3) {
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001665 dprintk("-D- DiB7000PC detected");
Patrick Boettchera75763f2006-10-18 08:34:16 -03001666 return 1;
1667 }
1668
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001669 dprintk("-D- DiB7000PC not detected");
Olivier Grenie5a0deee2011-05-03 12:27:33 -03001670
1671 kfree(rx);
1672rx_memory_error:
1673 kfree(tx);
1674 return ret;
Patrick Boettchera75763f2006-10-18 08:34:16 -03001675}
1676EXPORT_SYMBOL(dib7000pc_detection);
1677
Olivier Grenie713d54a2011-01-04 04:54:31 -03001678struct i2c_adapter *dib7000p_get_i2c_master(struct dvb_frontend *demod, enum dibx000_i2c_interface intf, int gating)
Patrick Boettchera75763f2006-10-18 08:34:16 -03001679{
1680 struct dib7000p_state *st = demod->demodulator_priv;
1681 return dibx000_get_i2c_adapter(&st->i2c_master, intf, gating);
1682}
1683EXPORT_SYMBOL(dib7000p_get_i2c_master);
1684
Olivier Grenief8731f42009-09-18 04:08:43 -03001685int dib7000p_pid_filter_ctrl(struct dvb_frontend *fe, u8 onoff)
1686{
Olivier Grenie713d54a2011-01-04 04:54:31 -03001687 struct dib7000p_state *state = fe->demodulator_priv;
1688 u16 val = dib7000p_read_word(state, 235) & 0xffef;
1689 val |= (onoff & 0x1) << 4;
1690 dprintk("PID filter enabled %d", onoff);
1691 return dib7000p_write_word(state, 235, val);
Olivier Grenief8731f42009-09-18 04:08:43 -03001692}
1693EXPORT_SYMBOL(dib7000p_pid_filter_ctrl);
1694
1695int dib7000p_pid_filter(struct dvb_frontend *fe, u8 id, u16 pid, u8 onoff)
1696{
Olivier Grenie713d54a2011-01-04 04:54:31 -03001697 struct dib7000p_state *state = fe->demodulator_priv;
1698 dprintk("PID filter: index %x, PID %d, OnOff %d", id, pid, onoff);
1699 return dib7000p_write_word(state, 241 + id, onoff ? (1 << 13) | pid : 0);
Olivier Grenief8731f42009-09-18 04:08:43 -03001700}
1701EXPORT_SYMBOL(dib7000p_pid_filter);
1702
Patrick Boettchera75763f2006-10-18 08:34:16 -03001703int dib7000p_i2c_enumeration(struct i2c_adapter *i2c, int no_of_demods, u8 default_addr, struct dib7000p_config cfg[])
1704{
Randy Dunlap30d81bb2010-02-08 20:30:44 -03001705 struct dib7000p_state *dpst;
Patrick Boettchera75763f2006-10-18 08:34:16 -03001706 int k = 0;
1707 u8 new_addr = 0;
1708
Randy Dunlap30d81bb2010-02-08 20:30:44 -03001709 dpst = kzalloc(sizeof(struct dib7000p_state), GFP_KERNEL);
1710 if (!dpst)
Andrew Morton0b427602010-04-27 19:09:45 -03001711 return -ENOMEM;
Randy Dunlap30d81bb2010-02-08 20:30:44 -03001712
1713 dpst->i2c_adap = i2c;
Patrick Boettcher79fcce32011-08-03 12:08:21 -03001714 mutex_init(&dpst->i2c_buffer_lock);
Randy Dunlap30d81bb2010-02-08 20:30:44 -03001715
Olivier Grenie713d54a2011-01-04 04:54:31 -03001716 for (k = no_of_demods - 1; k >= 0; k--) {
Randy Dunlap30d81bb2010-02-08 20:30:44 -03001717 dpst->cfg = cfg[k];
Patrick Boettchera75763f2006-10-18 08:34:16 -03001718
1719 /* designated i2c address */
Olivier Grenie713d54a2011-01-04 04:54:31 -03001720 if (cfg[k].default_i2c_addr != 0)
1721 new_addr = cfg[k].default_i2c_addr + (k << 1);
1722 else
1723 new_addr = (0x40 + k) << 1;
Randy Dunlap30d81bb2010-02-08 20:30:44 -03001724 dpst->i2c_addr = new_addr;
Olivier Grenie713d54a2011-01-04 04:54:31 -03001725 dib7000p_write_word(dpst, 1287, 0x0003); /* sram lead in, rdy */
Randy Dunlap30d81bb2010-02-08 20:30:44 -03001726 if (dib7000p_identify(dpst) != 0) {
1727 dpst->i2c_addr = default_addr;
Olivier Grenie713d54a2011-01-04 04:54:31 -03001728 dib7000p_write_word(dpst, 1287, 0x0003); /* sram lead in, rdy */
Randy Dunlap30d81bb2010-02-08 20:30:44 -03001729 if (dib7000p_identify(dpst) != 0) {
Patrick Boettchera75763f2006-10-18 08:34:16 -03001730 dprintk("DiB7000P #%d: not identified\n", k);
Randy Dunlap30d81bb2010-02-08 20:30:44 -03001731 kfree(dpst);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001732 return -EIO;
1733 }
1734 }
1735
1736 /* start diversity to pull_down div_str - just for i2c-enumeration */
Randy Dunlap30d81bb2010-02-08 20:30:44 -03001737 dib7000p_set_output_mode(dpst, OUTMODE_DIVERSITY);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001738
1739 /* set new i2c address and force divstart */
Randy Dunlap30d81bb2010-02-08 20:30:44 -03001740 dib7000p_write_word(dpst, 1285, (new_addr << 2) | 0x2);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001741
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001742 dprintk("IC %d initialized (to i2c_address 0x%x)", k, new_addr);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001743 }
1744
1745 for (k = 0; k < no_of_demods; k++) {
Randy Dunlap30d81bb2010-02-08 20:30:44 -03001746 dpst->cfg = cfg[k];
Olivier Grenie713d54a2011-01-04 04:54:31 -03001747 if (cfg[k].default_i2c_addr != 0)
1748 dpst->i2c_addr = (cfg[k].default_i2c_addr + k) << 1;
1749 else
1750 dpst->i2c_addr = (0x40 + k) << 1;
Patrick Boettchera75763f2006-10-18 08:34:16 -03001751
1752 // unforce divstr
Randy Dunlap30d81bb2010-02-08 20:30:44 -03001753 dib7000p_write_word(dpst, 1285, dpst->i2c_addr << 2);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001754
1755 /* deactivate div - it was just for i2c-enumeration */
Randy Dunlap30d81bb2010-02-08 20:30:44 -03001756 dib7000p_set_output_mode(dpst, OUTMODE_HIGH_Z);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001757 }
1758
Randy Dunlap30d81bb2010-02-08 20:30:44 -03001759 kfree(dpst);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001760 return 0;
1761}
1762EXPORT_SYMBOL(dib7000p_i2c_enumeration);
1763
Olivier Grenie713d54a2011-01-04 04:54:31 -03001764static const s32 lut_1000ln_mant[] = {
1765 6908, 6956, 7003, 7047, 7090, 7131, 7170, 7208, 7244, 7279, 7313, 7346, 7377, 7408, 7438, 7467, 7495, 7523, 7549, 7575, 7600
1766};
1767
1768static s32 dib7000p_get_adc_power(struct dvb_frontend *fe)
1769{
1770 struct dib7000p_state *state = fe->demodulator_priv;
1771 u32 tmp_val = 0, exp = 0, mant = 0;
1772 s32 pow_i;
1773 u16 buf[2];
1774 u8 ix = 0;
1775
1776 buf[0] = dib7000p_read_word(state, 0x184);
1777 buf[1] = dib7000p_read_word(state, 0x185);
1778 pow_i = (buf[0] << 16) | buf[1];
1779 dprintk("raw pow_i = %d", pow_i);
1780
1781 tmp_val = pow_i;
1782 while (tmp_val >>= 1)
1783 exp++;
1784
1785 mant = (pow_i * 1000 / (1 << exp));
1786 dprintk(" mant = %d exp = %d", mant / 1000, exp);
1787
1788 ix = (u8) ((mant - 1000) / 100); /* index of the LUT */
1789 dprintk(" ix = %d", ix);
1790
1791 pow_i = (lut_1000ln_mant[ix] + 693 * (exp - 20) - 6908);
1792 pow_i = (pow_i << 8) / 1000;
1793 dprintk(" pow_i = %d", pow_i);
1794
1795 return pow_i;
1796}
1797
1798static int map_addr_to_serpar_number(struct i2c_msg *msg)
1799{
1800 if ((msg->buf[0] <= 15))
1801 msg->buf[0] -= 1;
1802 else if (msg->buf[0] == 17)
1803 msg->buf[0] = 15;
1804 else if (msg->buf[0] == 16)
1805 msg->buf[0] = 17;
1806 else if (msg->buf[0] == 19)
1807 msg->buf[0] = 16;
1808 else if (msg->buf[0] >= 21 && msg->buf[0] <= 25)
1809 msg->buf[0] -= 3;
1810 else if (msg->buf[0] == 28)
1811 msg->buf[0] = 23;
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001812 else
Olivier Grenie713d54a2011-01-04 04:54:31 -03001813 return -EINVAL;
Olivier Grenie713d54a2011-01-04 04:54:31 -03001814 return 0;
1815}
1816
1817static int w7090p_tuner_write_serpar(struct i2c_adapter *i2c_adap, struct i2c_msg msg[], int num)
1818{
1819 struct dib7000p_state *state = i2c_get_adapdata(i2c_adap);
1820 u8 n_overflow = 1;
1821 u16 i = 1000;
1822 u16 serpar_num = msg[0].buf[0];
1823
1824 while (n_overflow == 1 && i) {
1825 n_overflow = (dib7000p_read_word(state, 1984) >> 1) & 0x1;
1826 i--;
1827 if (i == 0)
1828 dprintk("Tuner ITF: write busy (overflow)");
1829 }
1830 dib7000p_write_word(state, 1985, (1 << 6) | (serpar_num & 0x3f));
1831 dib7000p_write_word(state, 1986, (msg[0].buf[1] << 8) | msg[0].buf[2]);
1832
1833 return num;
1834}
1835
1836static int w7090p_tuner_read_serpar(struct i2c_adapter *i2c_adap, struct i2c_msg msg[], int num)
1837{
1838 struct dib7000p_state *state = i2c_get_adapdata(i2c_adap);
1839 u8 n_overflow = 1, n_empty = 1;
1840 u16 i = 1000;
1841 u16 serpar_num = msg[0].buf[0];
1842 u16 read_word;
1843
1844 while (n_overflow == 1 && i) {
1845 n_overflow = (dib7000p_read_word(state, 1984) >> 1) & 0x1;
1846 i--;
1847 if (i == 0)
1848 dprintk("TunerITF: read busy (overflow)");
1849 }
1850 dib7000p_write_word(state, 1985, (0 << 6) | (serpar_num & 0x3f));
1851
1852 i = 1000;
1853 while (n_empty == 1 && i) {
1854 n_empty = dib7000p_read_word(state, 1984) & 0x1;
1855 i--;
1856 if (i == 0)
1857 dprintk("TunerITF: read busy (empty)");
1858 }
1859 read_word = dib7000p_read_word(state, 1987);
1860 msg[1].buf[0] = (read_word >> 8) & 0xff;
1861 msg[1].buf[1] = (read_word) & 0xff;
1862
1863 return num;
1864}
1865
1866static int w7090p_tuner_rw_serpar(struct i2c_adapter *i2c_adap, struct i2c_msg msg[], int num)
1867{
1868 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... */
1869 if (num == 1) { /* write */
1870 return w7090p_tuner_write_serpar(i2c_adap, msg, 1);
1871 } else { /* read */
1872 return w7090p_tuner_read_serpar(i2c_adap, msg, 2);
1873 }
1874 }
1875 return num;
1876}
1877
Olivier Greniea685dbb2011-08-05 14:10:40 -03001878static int dib7090p_rw_on_apb(struct i2c_adapter *i2c_adap,
1879 struct i2c_msg msg[], int num, u16 apb_address)
Olivier Grenie713d54a2011-01-04 04:54:31 -03001880{
1881 struct dib7000p_state *state = i2c_get_adapdata(i2c_adap);
1882 u16 word;
1883
1884 if (num == 1) { /* write */
1885 dib7000p_write_word(state, apb_address, ((msg[0].buf[1] << 8) | (msg[0].buf[2])));
1886 } else {
1887 word = dib7000p_read_word(state, apb_address);
1888 msg[1].buf[0] = (word >> 8) & 0xff;
1889 msg[1].buf[1] = (word) & 0xff;
1890 }
1891
1892 return num;
1893}
1894
1895static int dib7090_tuner_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg msg[], int num)
1896{
1897 struct dib7000p_state *state = i2c_get_adapdata(i2c_adap);
1898
1899 u16 apb_address = 0, word;
1900 int i = 0;
1901 switch (msg[0].buf[0]) {
1902 case 0x12:
1903 apb_address = 1920;
1904 break;
1905 case 0x14:
1906 apb_address = 1921;
1907 break;
1908 case 0x24:
1909 apb_address = 1922;
1910 break;
1911 case 0x1a:
1912 apb_address = 1923;
1913 break;
1914 case 0x22:
1915 apb_address = 1924;
1916 break;
1917 case 0x33:
1918 apb_address = 1926;
1919 break;
1920 case 0x34:
1921 apb_address = 1927;
1922 break;
1923 case 0x35:
1924 apb_address = 1928;
1925 break;
1926 case 0x36:
1927 apb_address = 1929;
1928 break;
1929 case 0x37:
1930 apb_address = 1930;
1931 break;
1932 case 0x38:
1933 apb_address = 1931;
1934 break;
1935 case 0x39:
1936 apb_address = 1932;
1937 break;
1938 case 0x2a:
1939 apb_address = 1935;
1940 break;
1941 case 0x2b:
1942 apb_address = 1936;
1943 break;
1944 case 0x2c:
1945 apb_address = 1937;
1946 break;
1947 case 0x2d:
1948 apb_address = 1938;
1949 break;
1950 case 0x2e:
1951 apb_address = 1939;
1952 break;
1953 case 0x2f:
1954 apb_address = 1940;
1955 break;
1956 case 0x30:
1957 apb_address = 1941;
1958 break;
1959 case 0x31:
1960 apb_address = 1942;
1961 break;
1962 case 0x32:
1963 apb_address = 1943;
1964 break;
1965 case 0x3e:
1966 apb_address = 1944;
1967 break;
1968 case 0x3f:
1969 apb_address = 1945;
1970 break;
1971 case 0x40:
1972 apb_address = 1948;
1973 break;
1974 case 0x25:
1975 apb_address = 914;
1976 break;
1977 case 0x26:
1978 apb_address = 915;
1979 break;
1980 case 0x27:
Olivier Grenie2e802862011-08-05 10:39:15 -03001981 apb_address = 917;
Olivier Grenie713d54a2011-01-04 04:54:31 -03001982 break;
1983 case 0x28:
Olivier Grenie2e802862011-08-05 10:39:15 -03001984 apb_address = 916;
Olivier Grenie713d54a2011-01-04 04:54:31 -03001985 break;
1986 case 0x1d:
1987 i = ((dib7000p_read_word(state, 72) >> 12) & 0x3);
1988 word = dib7000p_read_word(state, 384 + i);
1989 msg[1].buf[0] = (word >> 8) & 0xff;
1990 msg[1].buf[1] = (word) & 0xff;
1991 return num;
1992 case 0x1f:
1993 if (num == 1) { /* write */
1994 word = (u16) ((msg[0].buf[1] << 8) | msg[0].buf[2]);
1995 word &= 0x3;
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001996 word = (dib7000p_read_word(state, 72) & ~(3 << 12)) | (word << 12);
Olivier Grenie713d54a2011-01-04 04:54:31 -03001997 dib7000p_write_word(state, 72, word); /* Set the proper input */
1998 return num;
1999 }
2000 }
2001
2002 if (apb_address != 0) /* R/W acces via APB */
2003 return dib7090p_rw_on_apb(i2c_adap, msg, num, apb_address);
2004 else /* R/W access via SERPAR */
2005 return w7090p_tuner_rw_serpar(i2c_adap, msg, num);
2006
2007 return 0;
2008}
2009
2010static u32 dib7000p_i2c_func(struct i2c_adapter *adapter)
2011{
2012 return I2C_FUNC_I2C;
2013}
2014
2015static struct i2c_algorithm dib7090_tuner_xfer_algo = {
2016 .master_xfer = dib7090_tuner_xfer,
2017 .functionality = dib7000p_i2c_func,
2018};
2019
2020struct i2c_adapter *dib7090_get_i2c_tuner(struct dvb_frontend *fe)
2021{
2022 struct dib7000p_state *st = fe->demodulator_priv;
2023 return &st->dib7090_tuner_adap;
2024}
2025EXPORT_SYMBOL(dib7090_get_i2c_tuner);
2026
2027static int dib7090_host_bus_drive(struct dib7000p_state *state, u8 drive)
2028{
2029 u16 reg;
2030
2031 /* drive host bus 2, 3, 4 */
2032 reg = dib7000p_read_word(state, 1798) & ~((0x7) | (0x7 << 6) | (0x7 << 12));
2033 reg |= (drive << 12) | (drive << 6) | drive;
2034 dib7000p_write_word(state, 1798, reg);
2035
2036 /* drive host bus 5,6 */
2037 reg = dib7000p_read_word(state, 1799) & ~((0x7 << 2) | (0x7 << 8));
2038 reg |= (drive << 8) | (drive << 2);
2039 dib7000p_write_word(state, 1799, reg);
2040
2041 /* drive host bus 7, 8, 9 */
2042 reg = dib7000p_read_word(state, 1800) & ~((0x7) | (0x7 << 6) | (0x7 << 12));
2043 reg |= (drive << 12) | (drive << 6) | drive;
2044 dib7000p_write_word(state, 1800, reg);
2045
2046 /* drive host bus 10, 11 */
2047 reg = dib7000p_read_word(state, 1801) & ~((0x7 << 2) | (0x7 << 8));
2048 reg |= (drive << 8) | (drive << 2);
2049 dib7000p_write_word(state, 1801, reg);
2050
2051 /* drive host bus 12, 13, 14 */
2052 reg = dib7000p_read_word(state, 1802) & ~((0x7) | (0x7 << 6) | (0x7 << 12));
2053 reg |= (drive << 12) | (drive << 6) | drive;
2054 dib7000p_write_word(state, 1802, reg);
2055
2056 return 0;
2057}
2058
2059static u32 dib7090_calcSyncFreq(u32 P_Kin, u32 P_Kout, u32 insertExtSynchro, u32 syncSize)
2060{
2061 u32 quantif = 3;
2062 u32 nom = (insertExtSynchro * P_Kin + syncSize);
2063 u32 denom = P_Kout;
2064 u32 syncFreq = ((nom << quantif) / denom);
2065
2066 if ((syncFreq & ((1 << quantif) - 1)) != 0)
2067 syncFreq = (syncFreq >> quantif) + 1;
2068 else
2069 syncFreq = (syncFreq >> quantif);
2070
2071 if (syncFreq != 0)
2072 syncFreq = syncFreq - 1;
2073
2074 return syncFreq;
2075}
2076
2077static int dib7090_cfg_DibTx(struct dib7000p_state *state, u32 P_Kin, u32 P_Kout, u32 insertExtSynchro, u32 synchroMode, u32 syncWord, u32 syncSize)
2078{
Olivier Grenie713d54a2011-01-04 04:54:31 -03002079 dprintk("Configure DibStream Tx");
Olivier Grenie713d54a2011-01-04 04:54:31 -03002080
2081 dib7000p_write_word(state, 1615, 1);
2082 dib7000p_write_word(state, 1603, P_Kin);
2083 dib7000p_write_word(state, 1605, P_Kout);
2084 dib7000p_write_word(state, 1606, insertExtSynchro);
2085 dib7000p_write_word(state, 1608, synchroMode);
2086 dib7000p_write_word(state, 1609, (syncWord >> 16) & 0xffff);
2087 dib7000p_write_word(state, 1610, syncWord & 0xffff);
2088 dib7000p_write_word(state, 1612, syncSize);
2089 dib7000p_write_word(state, 1615, 0);
2090
Olivier Grenie713d54a2011-01-04 04:54:31 -03002091 return 0;
2092}
2093
2094static int dib7090_cfg_DibRx(struct dib7000p_state *state, u32 P_Kin, u32 P_Kout, u32 synchroMode, u32 insertExtSynchro, u32 syncWord, u32 syncSize,
2095 u32 dataOutRate)
2096{
2097 u32 syncFreq;
2098
2099 dprintk("Configure DibStream Rx");
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002100 if ((P_Kin != 0) && (P_Kout != 0)) {
Olivier Grenie713d54a2011-01-04 04:54:31 -03002101 syncFreq = dib7090_calcSyncFreq(P_Kin, P_Kout, insertExtSynchro, syncSize);
2102 dib7000p_write_word(state, 1542, syncFreq);
2103 }
2104 dib7000p_write_word(state, 1554, 1);
2105 dib7000p_write_word(state, 1536, P_Kin);
2106 dib7000p_write_word(state, 1537, P_Kout);
2107 dib7000p_write_word(state, 1539, synchroMode);
2108 dib7000p_write_word(state, 1540, (syncWord >> 16) & 0xffff);
2109 dib7000p_write_word(state, 1541, syncWord & 0xffff);
2110 dib7000p_write_word(state, 1543, syncSize);
2111 dib7000p_write_word(state, 1544, dataOutRate);
2112 dib7000p_write_word(state, 1554, 0);
2113
2114 return 0;
2115}
2116
Olivier Grenie2e802862011-08-05 10:39:15 -03002117static void dib7090_enMpegMux(struct dib7000p_state *state, int onoff)
Olivier Grenie713d54a2011-01-04 04:54:31 -03002118{
Olivier Grenie2e802862011-08-05 10:39:15 -03002119 u16 reg_1287 = dib7000p_read_word(state, 1287);
Olivier Grenie713d54a2011-01-04 04:54:31 -03002120
Olivier Grenie2e802862011-08-05 10:39:15 -03002121 switch (onoff) {
2122 case 1:
2123 reg_1287 &= ~(1<<7);
2124 break;
2125 case 0:
2126 reg_1287 |= (1<<7);
2127 break;
2128 }
Olivier Grenie713d54a2011-01-04 04:54:31 -03002129
Olivier Grenie2e802862011-08-05 10:39:15 -03002130 dib7000p_write_word(state, 1287, reg_1287);
Olivier Grenie713d54a2011-01-04 04:54:31 -03002131}
2132
Olivier Grenie2e802862011-08-05 10:39:15 -03002133static void dib7090_configMpegMux(struct dib7000p_state *state,
2134 u16 pulseWidth, u16 enSerialMode, u16 enSerialClkDiv2)
Olivier Grenie713d54a2011-01-04 04:54:31 -03002135{
Olivier Grenie713d54a2011-01-04 04:54:31 -03002136 dprintk("Enable Mpeg mux");
Olivier Grenie713d54a2011-01-04 04:54:31 -03002137
Olivier Grenie2e802862011-08-05 10:39:15 -03002138 dib7090_enMpegMux(state, 0);
Olivier Grenie713d54a2011-01-04 04:54:31 -03002139
Olivier Grenie2e802862011-08-05 10:39:15 -03002140 /* If the input mode is MPEG do not divide the serial clock */
2141 if ((enSerialMode == 1) && (state->input_mode_mpeg == 1))
2142 enSerialClkDiv2 = 0;
Olivier Grenie713d54a2011-01-04 04:54:31 -03002143
Olivier Grenie2e802862011-08-05 10:39:15 -03002144 dib7000p_write_word(state, 1287, ((pulseWidth & 0x1f) << 2)
2145 | ((enSerialMode & 0x1) << 1)
2146 | (enSerialClkDiv2 & 0x1));
2147
2148 dib7090_enMpegMux(state, 1);
Olivier Grenie713d54a2011-01-04 04:54:31 -03002149}
2150
Olivier Grenie2e802862011-08-05 10:39:15 -03002151static void dib7090_setDibTxMux(struct dib7000p_state *state, int mode)
Olivier Grenie713d54a2011-01-04 04:54:31 -03002152{
Olivier Grenie2e802862011-08-05 10:39:15 -03002153 u16 reg_1288 = dib7000p_read_word(state, 1288) & ~(0x7 << 7);
Olivier Grenie713d54a2011-01-04 04:54:31 -03002154
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002155 switch (mode) {
Olivier Grenie2e802862011-08-05 10:39:15 -03002156 case MPEG_ON_DIBTX:
2157 dprintk("SET MPEG ON DIBSTREAM TX");
2158 dib7090_cfg_DibTx(state, 8, 5, 0, 0, 0, 0);
2159 reg_1288 |= (1<<9);
Olivier Grenie713d54a2011-01-04 04:54:31 -03002160 break;
Olivier Grenie2e802862011-08-05 10:39:15 -03002161 case DIV_ON_DIBTX:
2162 dprintk("SET DIV_OUT ON DIBSTREAM TX");
2163 dib7090_cfg_DibTx(state, 5, 5, 0, 0, 0, 0);
2164 reg_1288 |= (1<<8);
Olivier Grenie713d54a2011-01-04 04:54:31 -03002165 break;
Olivier Grenie2e802862011-08-05 10:39:15 -03002166 case ADC_ON_DIBTX:
2167 dprintk("SET ADC_OUT ON DIBSTREAM TX");
2168 dib7090_cfg_DibTx(state, 20, 5, 10, 0, 0, 0);
2169 reg_1288 |= (1<<7);
2170 break;
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002171 default:
Olivier Grenie713d54a2011-01-04 04:54:31 -03002172 break;
2173 }
Olivier Grenie2e802862011-08-05 10:39:15 -03002174 dib7000p_write_word(state, 1288, reg_1288);
Olivier Grenie713d54a2011-01-04 04:54:31 -03002175}
2176
Olivier Grenie2e802862011-08-05 10:39:15 -03002177static void dib7090_setHostBusMux(struct dib7000p_state *state, int mode)
Olivier Grenie713d54a2011-01-04 04:54:31 -03002178{
Olivier Grenie2e802862011-08-05 10:39:15 -03002179 u16 reg_1288 = dib7000p_read_word(state, 1288) & ~(0x7 << 4);
2180
2181 switch (mode) {
2182 case DEMOUT_ON_HOSTBUS:
2183 dprintk("SET DEM OUT OLD INTERF ON HOST BUS");
2184 dib7090_enMpegMux(state, 0);
2185 reg_1288 |= (1<<6);
2186 break;
2187 case DIBTX_ON_HOSTBUS:
2188 dprintk("SET DIBSTREAM TX ON HOST BUS");
2189 dib7090_enMpegMux(state, 0);
2190 reg_1288 |= (1<<5);
2191 break;
2192 case MPEG_ON_HOSTBUS:
2193 dprintk("SET MPEG MUX ON HOST BUS");
2194 reg_1288 |= (1<<4);
2195 break;
2196 default:
2197 break;
2198 }
2199 dib7000p_write_word(state, 1288, reg_1288);
2200}
2201
2202int dib7090_set_diversity_in(struct dvb_frontend *fe, int onoff)
2203{
2204 struct dib7000p_state *state = fe->demodulator_priv;
2205 u16 reg_1287;
2206
Olivier Grenie713d54a2011-01-04 04:54:31 -03002207 switch (onoff) {
Olivier Grenie2e802862011-08-05 10:39:15 -03002208 case 0: /* only use the internal way - not the diversity input */
2209 dprintk("%s mode OFF : by default Enable Mpeg INPUT", __func__);
2210 dib7090_cfg_DibRx(state, 8, 5, 0, 0, 0, 8, 0);
2211
2212 /* Do not divide the serial clock of MPEG MUX */
2213 /* in SERIAL MODE in case input mode MPEG is used */
2214 reg_1287 = dib7000p_read_word(state, 1287);
2215 /* enSerialClkDiv2 == 1 ? */
2216 if ((reg_1287 & 0x1) == 1) {
2217 /* force enSerialClkDiv2 = 0 */
2218 reg_1287 &= ~0x1;
2219 dib7000p_write_word(state, 1287, reg_1287);
2220 }
2221 state->input_mode_mpeg = 1;
2222 break;
2223 case 1: /* both ways */
2224 case 2: /* only the diversity input */
2225 dprintk("%s ON : Enable diversity INPUT", __func__);
2226 dib7090_cfg_DibRx(state, 5, 5, 0, 0, 0, 0, 0);
2227 state->input_mode_mpeg = 0;
2228 break;
Olivier Grenie713d54a2011-01-04 04:54:31 -03002229 }
2230
Olivier Grenie2e802862011-08-05 10:39:15 -03002231 dib7000p_set_diversity_in(&state->demod, onoff);
Olivier Grenie713d54a2011-01-04 04:54:31 -03002232 return 0;
2233}
2234
2235static int dib7090_set_output_mode(struct dvb_frontend *fe, int mode)
2236{
2237 struct dib7000p_state *state = fe->demodulator_priv;
2238
2239 u16 outreg, smo_mode, fifo_threshold;
2240 u8 prefer_mpeg_mux_use = 1;
2241 int ret = 0;
2242
2243 dib7090_host_bus_drive(state, 1);
2244
2245 fifo_threshold = 1792;
2246 smo_mode = (dib7000p_read_word(state, 235) & 0x0050) | (1 << 1);
2247 outreg = dib7000p_read_word(state, 1286) & ~((1 << 10) | (0x7 << 6) | (1 << 1));
2248
2249 switch (mode) {
2250 case OUTMODE_HIGH_Z:
2251 outreg = 0;
2252 break;
2253
2254 case OUTMODE_MPEG2_SERIAL:
2255 if (prefer_mpeg_mux_use) {
Olivier Grenie2e802862011-08-05 10:39:15 -03002256 dprintk("setting output mode TS_SERIAL using Mpeg Mux");
2257 dib7090_configMpegMux(state, 3, 1, 1);
2258 dib7090_setHostBusMux(state, MPEG_ON_HOSTBUS);
2259 } else {/* Use Smooth block */
2260 dprintk("setting output mode TS_SERIAL using Smooth bloc");
2261 dib7090_setHostBusMux(state, DEMOUT_ON_HOSTBUS);
2262 outreg |= (2<<6) | (0 << 1);
Olivier Grenie713d54a2011-01-04 04:54:31 -03002263 }
2264 break;
2265
2266 case OUTMODE_MPEG2_PAR_GATED_CLK:
2267 if (prefer_mpeg_mux_use) {
Olivier Grenie2e802862011-08-05 10:39:15 -03002268 dprintk("setting output mode TS_PARALLEL_GATED using Mpeg Mux");
2269 dib7090_configMpegMux(state, 2, 0, 0);
2270 dib7090_setHostBusMux(state, MPEG_ON_HOSTBUS);
2271 } else { /* Use Smooth block */
2272 dprintk("setting output mode TS_PARALLEL_GATED using Smooth block");
2273 dib7090_setHostBusMux(state, DEMOUT_ON_HOSTBUS);
2274 outreg |= (0<<6);
Olivier Grenie713d54a2011-01-04 04:54:31 -03002275 }
2276 break;
2277
2278 case OUTMODE_MPEG2_PAR_CONT_CLK: /* Using Smooth block only */
Olivier Grenie2e802862011-08-05 10:39:15 -03002279 dprintk("setting output mode TS_PARALLEL_CONT using Smooth block");
2280 dib7090_setHostBusMux(state, DEMOUT_ON_HOSTBUS);
2281 outreg |= (1<<6);
Olivier Grenie713d54a2011-01-04 04:54:31 -03002282 break;
2283
2284 case OUTMODE_MPEG2_FIFO: /* Using Smooth block because not supported by new Mpeg Mux bloc */
Olivier Grenie2e802862011-08-05 10:39:15 -03002285 dprintk("setting output mode TS_FIFO using Smooth block");
2286 dib7090_setHostBusMux(state, DEMOUT_ON_HOSTBUS);
2287 outreg |= (5<<6);
Olivier Grenie713d54a2011-01-04 04:54:31 -03002288 smo_mode |= (3 << 1);
2289 fifo_threshold = 512;
2290 break;
2291
2292 case OUTMODE_DIVERSITY:
Olivier Grenie2e802862011-08-05 10:39:15 -03002293 dprintk("setting output mode MODE_DIVERSITY");
2294 dib7090_setDibTxMux(state, DIV_ON_DIBTX);
2295 dib7090_setHostBusMux(state, DIBTX_ON_HOSTBUS);
Olivier Grenie713d54a2011-01-04 04:54:31 -03002296 break;
2297
2298 case OUTMODE_ANALOG_ADC:
Olivier Grenie2e802862011-08-05 10:39:15 -03002299 dprintk("setting output mode MODE_ANALOG_ADC");
2300 dib7090_setDibTxMux(state, ADC_ON_DIBTX);
2301 dib7090_setHostBusMux(state, DIBTX_ON_HOSTBUS);
Olivier Grenie713d54a2011-01-04 04:54:31 -03002302 break;
2303 }
Olivier Grenie2e802862011-08-05 10:39:15 -03002304 if (mode != OUTMODE_HIGH_Z)
2305 outreg |= (1 << 10);
Olivier Grenie713d54a2011-01-04 04:54:31 -03002306
2307 if (state->cfg.output_mpeg2_in_188_bytes)
2308 smo_mode |= (1 << 5);
2309
2310 ret |= dib7000p_write_word(state, 235, smo_mode);
2311 ret |= dib7000p_write_word(state, 236, fifo_threshold); /* synchronous fread */
Olivier Grenie2e802862011-08-05 10:39:15 -03002312 ret |= dib7000p_write_word(state, 1286, outreg);
Olivier Grenie713d54a2011-01-04 04:54:31 -03002313
2314 return ret;
2315}
2316
2317int dib7090_tuner_sleep(struct dvb_frontend *fe, int onoff)
2318{
2319 struct dib7000p_state *state = fe->demodulator_priv;
2320 u16 en_cur_state;
2321
2322 dprintk("sleep dib7090: %d", onoff);
2323
2324 en_cur_state = dib7000p_read_word(state, 1922);
2325
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002326 if (en_cur_state > 0xff)
Olivier Grenie713d54a2011-01-04 04:54:31 -03002327 state->tuner_enable = en_cur_state;
Olivier Grenie713d54a2011-01-04 04:54:31 -03002328
2329 if (onoff)
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002330 en_cur_state &= 0x00ff;
Olivier Grenie713d54a2011-01-04 04:54:31 -03002331 else {
2332 if (state->tuner_enable != 0)
2333 en_cur_state = state->tuner_enable;
2334 }
2335
2336 dib7000p_write_word(state, 1922, en_cur_state);
2337
2338 return 0;
2339}
2340EXPORT_SYMBOL(dib7090_tuner_sleep);
2341
Olivier Grenie713d54a2011-01-04 04:54:31 -03002342int dib7090_get_adc_power(struct dvb_frontend *fe)
2343{
2344 return dib7000p_get_adc_power(fe);
2345}
2346EXPORT_SYMBOL(dib7090_get_adc_power);
2347
2348int dib7090_slave_reset(struct dvb_frontend *fe)
2349{
2350 struct dib7000p_state *state = fe->demodulator_priv;
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002351 u16 reg;
Olivier Grenie713d54a2011-01-04 04:54:31 -03002352
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002353 reg = dib7000p_read_word(state, 1794);
2354 dib7000p_write_word(state, 1794, reg | (4 << 12));
Olivier Grenie713d54a2011-01-04 04:54:31 -03002355
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002356 dib7000p_write_word(state, 1032, 0xffff);
2357 return 0;
Olivier Grenie713d54a2011-01-04 04:54:31 -03002358}
2359EXPORT_SYMBOL(dib7090_slave_reset);
2360
Patrick Boettchera75763f2006-10-18 08:34:16 -03002361static struct dvb_frontend_ops dib7000p_ops;
Olivier Grenie713d54a2011-01-04 04:54:31 -03002362struct dvb_frontend *dib7000p_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr, struct dib7000p_config *cfg)
Patrick Boettchera75763f2006-10-18 08:34:16 -03002363{
2364 struct dvb_frontend *demod;
2365 struct dib7000p_state *st;
2366 st = kzalloc(sizeof(struct dib7000p_state), GFP_KERNEL);
2367 if (st == NULL)
2368 return NULL;
2369
2370 memcpy(&st->cfg, cfg, sizeof(struct dib7000p_config));
2371 st->i2c_adap = i2c_adap;
2372 st->i2c_addr = i2c_addr;
2373 st->gpio_val = cfg->gpio_val;
2374 st->gpio_dir = cfg->gpio_dir;
2375
Steven Totha38d6e32008-04-22 15:37:01 -03002376 /* Ensure the output mode remains at the previous default if it's
2377 * not specifically set by the caller.
2378 */
Olivier Grenie713d54a2011-01-04 04:54:31 -03002379 if ((st->cfg.output_mode != OUTMODE_MPEG2_SERIAL) && (st->cfg.output_mode != OUTMODE_MPEG2_PAR_GATED_CLK))
Steven Totha38d6e32008-04-22 15:37:01 -03002380 st->cfg.output_mode = OUTMODE_MPEG2_FIFO;
2381
Olivier Grenie713d54a2011-01-04 04:54:31 -03002382 demod = &st->demod;
Patrick Boettchera75763f2006-10-18 08:34:16 -03002383 demod->demodulator_priv = st;
2384 memcpy(&st->demod.ops, &dib7000p_ops, sizeof(struct dvb_frontend_ops));
Patrick Boettcher79fcce32011-08-03 12:08:21 -03002385 mutex_init(&st->i2c_buffer_lock);
Patrick Boettchera75763f2006-10-18 08:34:16 -03002386
Olivier Grenie713d54a2011-01-04 04:54:31 -03002387 dib7000p_write_word(st, 1287, 0x0003); /* sram lead in, rdy */
Olivier Grenieeac1fe12009-09-23 13:41:27 -03002388
Patrick Boettchera75763f2006-10-18 08:34:16 -03002389 if (dib7000p_identify(st) != 0)
2390 goto error;
2391
Olivier Grenie713d54a2011-01-04 04:54:31 -03002392 st->version = dib7000p_read_word(st, 897);
2393
Martin Samek7646b9d2009-09-30 22:59:09 -03002394 /* FIXME: make sure the dev.parent field is initialized, or else
Patrick Boettcher79fcce32011-08-03 12:08:21 -03002395 request_firmware() will hit an OOPS (this should be moved somewhere
2396 more common) */
2397 st->i2c_master.gated_tuner_i2c_adap.dev.parent = i2c_adap->dev.parent;
Martin Samek7646b9d2009-09-30 22:59:09 -03002398
Devin Heitmueller85ec9d72009-07-20 00:45:25 -03002399 /* FIXME: make sure the dev.parent field is initialized, or else
2400 request_firmware() will hit an OOPS (this should be moved somewhere
2401 more common) */
2402 st->i2c_master.gated_tuner_i2c_adap.dev.parent = i2c_adap->dev.parent;
2403
Patrick Boettchera75763f2006-10-18 08:34:16 -03002404 dibx000_init_i2c_master(&st->i2c_master, DIB7000P, st->i2c_adap, st->i2c_addr);
2405
Olivier Grenie713d54a2011-01-04 04:54:31 -03002406 /* init 7090 tuner adapter */
2407 strncpy(st->dib7090_tuner_adap.name, "DiB7090 tuner interface", sizeof(st->dib7090_tuner_adap.name));
2408 st->dib7090_tuner_adap.algo = &dib7090_tuner_xfer_algo;
2409 st->dib7090_tuner_adap.algo_data = NULL;
2410 st->dib7090_tuner_adap.dev.parent = st->i2c_adap->dev.parent;
2411 i2c_set_adapdata(&st->dib7090_tuner_adap, st);
2412 i2c_add_adapter(&st->dib7090_tuner_adap);
2413
Patrick Boettchera75763f2006-10-18 08:34:16 -03002414 dib7000p_demod_reset(st);
2415
Olivier Grenie713d54a2011-01-04 04:54:31 -03002416 if (st->version == SOC7090) {
2417 dib7090_set_output_mode(demod, st->cfg.output_mode);
2418 dib7090_set_diversity_in(demod, 0);
2419 }
2420
Patrick Boettchera75763f2006-10-18 08:34:16 -03002421 return demod;
2422
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002423error:
Patrick Boettchera75763f2006-10-18 08:34:16 -03002424 kfree(st);
2425 return NULL;
2426}
2427EXPORT_SYMBOL(dib7000p_attach);
2428
2429static struct dvb_frontend_ops dib7000p_ops = {
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -03002430 .delsys = { SYS_DVBT },
Patrick Boettchera75763f2006-10-18 08:34:16 -03002431 .info = {
Olivier Grenie713d54a2011-01-04 04:54:31 -03002432 .name = "DiBcom 7000PC",
Olivier Grenie713d54a2011-01-04 04:54:31 -03002433 .frequency_min = 44250000,
2434 .frequency_max = 867250000,
2435 .frequency_stepsize = 62500,
2436 .caps = FE_CAN_INVERSION_AUTO |
2437 FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
2438 FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
2439 FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO |
2440 FE_CAN_TRANSMISSION_MODE_AUTO | FE_CAN_GUARD_INTERVAL_AUTO | FE_CAN_RECOVER | FE_CAN_HIERARCHY_AUTO,
2441 },
Patrick Boettchera75763f2006-10-18 08:34:16 -03002442
Olivier Grenie713d54a2011-01-04 04:54:31 -03002443 .release = dib7000p_release,
Patrick Boettchera75763f2006-10-18 08:34:16 -03002444
Olivier Grenie713d54a2011-01-04 04:54:31 -03002445 .init = dib7000p_wakeup,
2446 .sleep = dib7000p_sleep,
Patrick Boettchera75763f2006-10-18 08:34:16 -03002447
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -03002448 .set_frontend = dib7000p_set_frontend,
Olivier Grenie713d54a2011-01-04 04:54:31 -03002449 .get_tune_settings = dib7000p_fe_get_tune_settings,
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -03002450 .get_frontend = dib7000p_get_frontend,
Patrick Boettchera75763f2006-10-18 08:34:16 -03002451
Olivier Grenie713d54a2011-01-04 04:54:31 -03002452 .read_status = dib7000p_read_status,
2453 .read_ber = dib7000p_read_ber,
Patrick Boettchera75763f2006-10-18 08:34:16 -03002454 .read_signal_strength = dib7000p_read_signal_strength,
Olivier Grenie713d54a2011-01-04 04:54:31 -03002455 .read_snr = dib7000p_read_snr,
2456 .read_ucblocks = dib7000p_read_unc_blocks,
Patrick Boettchera75763f2006-10-18 08:34:16 -03002457};
2458
Olivier Grenie713d54a2011-01-04 04:54:31 -03002459MODULE_AUTHOR("Olivier Grenie <ogrenie@dibcom.fr>");
Patrick Boettchera75763f2006-10-18 08:34:16 -03002460MODULE_AUTHOR("Patrick Boettcher <pboettcher@dibcom.fr>");
2461MODULE_DESCRIPTION("Driver for the DiBcom 7000PC COFDM demodulator");
2462MODULE_LICENSE("GPL");