blob: effb87f773b0256c9b5eab954b0811f17ea0e3b3 [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 Doran8f6956c72007-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 Doran8f6956c72007-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 Doran8f6956c72007-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
Olivier Grenie6fe10992012-12-31 09:23:26 -0300432int dib7000p_set_agc1_min(struct dvb_frontend *fe, u16 v)
433{
434 struct dib7000p_state *state = fe->demodulator_priv;
435 return dib7000p_write_word(state, 108, v);
436}
437EXPORT_SYMBOL(dib7000p_set_agc1_min);
438
Patrick Boettchera75763f2006-10-18 08:34:16 -0300439static void dib7000p_reset_pll(struct dib7000p_state *state)
440{
441 struct dibx000_bandwidth_config *bw = &state->cfg.bw[0];
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300442 u16 clk_cfg0;
Patrick Boettchera75763f2006-10-18 08:34:16 -0300443
Olivier Grenie713d54a2011-01-04 04:54:31 -0300444 if (state->version == SOC7090) {
445 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 -0300446
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300447 while (((dib7000p_read_word(state, 1856) >> 15) & 0x1) != 1)
448 ;
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300449
Olivier Grenie713d54a2011-01-04 04:54:31 -0300450 dib7000p_write_word(state, 1857, dib7000p_read_word(state, 1857) | (!bw->pll_bypass << 15));
451 } else {
452 /* force PLL bypass */
453 clk_cfg0 = (1 << 15) | ((bw->pll_ratio & 0x3f) << 9) |
454 (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 -0300455
Olivier Grenie713d54a2011-01-04 04:54:31 -0300456 dib7000p_write_word(state, 900, clk_cfg0);
457
458 /* P_pll_cfg */
459 dib7000p_write_word(state, 903, (bw->pll_prediv << 5) | (((bw->pll_ratio >> 6) & 0x3) << 3) | (bw->pll_range << 1) | bw->pll_reset);
460 clk_cfg0 = (bw->pll_bypass << 15) | (clk_cfg0 & 0x7fff);
461 dib7000p_write_word(state, 900, clk_cfg0);
462 }
463
464 dib7000p_write_word(state, 18, (u16) (((bw->internal * 1000) >> 16) & 0xffff));
465 dib7000p_write_word(state, 19, (u16) ((bw->internal * 1000) & 0xffff));
466 dib7000p_write_word(state, 21, (u16) ((bw->ifreq >> 16) & 0xffff));
467 dib7000p_write_word(state, 22, (u16) ((bw->ifreq) & 0xffff));
Patrick Boettchera75763f2006-10-18 08:34:16 -0300468
469 dib7000p_write_word(state, 72, bw->sad_cfg);
470}
471
Olivier Grenie713d54a2011-01-04 04:54:31 -0300472static u32 dib7000p_get_internal_freq(struct dib7000p_state *state)
473{
474 u32 internal = (u32) dib7000p_read_word(state, 18) << 16;
475 internal |= (u32) dib7000p_read_word(state, 19);
476 internal /= 1000;
477
478 return internal;
479}
480
481int dib7000p_update_pll(struct dvb_frontend *fe, struct dibx000_bandwidth_config *bw)
482{
483 struct dib7000p_state *state = fe->demodulator_priv;
484 u16 reg_1857, reg_1856 = dib7000p_read_word(state, 1856);
485 u8 loopdiv, prediv;
486 u32 internal, xtal;
487
488 /* get back old values */
489 prediv = reg_1856 & 0x3f;
490 loopdiv = (reg_1856 >> 6) & 0x3f;
491
492 if ((bw != NULL) && (bw->pll_prediv != prediv || bw->pll_ratio != loopdiv)) {
493 dprintk("Updating pll (prediv: old = %d new = %d ; loopdiv : old = %d new = %d)", prediv, bw->pll_prediv, loopdiv, bw->pll_ratio);
494 reg_1856 &= 0xf000;
495 reg_1857 = dib7000p_read_word(state, 1857);
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300496 dib7000p_write_word(state, 1857, reg_1857 & ~(1 << 15));
Olivier Grenie713d54a2011-01-04 04:54:31 -0300497
498 dib7000p_write_word(state, 1856, reg_1856 | ((bw->pll_ratio & 0x3f) << 6) | (bw->pll_prediv & 0x3f));
499
500 /* write new system clk into P_sec_len */
501 internal = dib7000p_get_internal_freq(state);
502 xtal = (internal / loopdiv) * prediv;
503 internal = 1000 * (xtal / bw->pll_prediv) * bw->pll_ratio; /* new internal */
504 dib7000p_write_word(state, 18, (u16) ((internal >> 16) & 0xffff));
505 dib7000p_write_word(state, 19, (u16) (internal & 0xffff));
506
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300507 dib7000p_write_word(state, 1857, reg_1857 | (1 << 15));
Olivier Grenie713d54a2011-01-04 04:54:31 -0300508
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300509 while (((dib7000p_read_word(state, 1856) >> 15) & 0x1) != 1)
Olivier Grenie713d54a2011-01-04 04:54:31 -0300510 dprintk("Waiting for PLL to lock");
Olivier Grenie713d54a2011-01-04 04:54:31 -0300511
512 return 0;
513 }
514 return -EIO;
515}
516EXPORT_SYMBOL(dib7000p_update_pll);
517
Patrick Boettchera75763f2006-10-18 08:34:16 -0300518static int dib7000p_reset_gpio(struct dib7000p_state *st)
519{
520 /* reset the GPIOs */
Olivier Grenie713d54a2011-01-04 04:54:31 -0300521 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 -0300522
523 dib7000p_write_word(st, 1029, st->gpio_dir);
524 dib7000p_write_word(st, 1030, st->gpio_val);
525
526 /* TODO 1031 is P_gpio_od */
527
528 dib7000p_write_word(st, 1032, st->cfg.gpio_pwm_pos);
529
530 dib7000p_write_word(st, 1037, st->cfg.pwm_freq_div);
531 return 0;
532}
533
Patrick Boettcher01373a52007-07-30 12:49:04 -0300534static int dib7000p_cfg_gpio(struct dib7000p_state *st, u8 num, u8 dir, u8 val)
535{
536 st->gpio_dir = dib7000p_read_word(st, 1029);
Olivier Grenie713d54a2011-01-04 04:54:31 -0300537 st->gpio_dir &= ~(1 << num); /* reset the direction bit */
538 st->gpio_dir |= (dir & 0x1) << num; /* set the new direction */
Patrick Boettcher01373a52007-07-30 12:49:04 -0300539 dib7000p_write_word(st, 1029, st->gpio_dir);
540
541 st->gpio_val = dib7000p_read_word(st, 1030);
Olivier Grenie713d54a2011-01-04 04:54:31 -0300542 st->gpio_val &= ~(1 << num); /* reset the direction bit */
543 st->gpio_val |= (val & 0x01) << num; /* set the new value */
Patrick Boettcher01373a52007-07-30 12:49:04 -0300544 dib7000p_write_word(st, 1030, st->gpio_val);
545
546 return 0;
547}
548
549int dib7000p_set_gpio(struct dvb_frontend *demod, u8 num, u8 dir, u8 val)
550{
551 struct dib7000p_state *state = demod->demodulator_priv;
552 return dib7000p_cfg_gpio(state, num, dir, val);
553}
Patrick Boettcher01373a52007-07-30 12:49:04 -0300554EXPORT_SYMBOL(dib7000p_set_gpio);
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300555
Olivier Grenie713d54a2011-01-04 04:54:31 -0300556static u16 dib7000p_defaults[] = {
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300557 // auto search configuration
558 3, 2,
Olivier Grenie713d54a2011-01-04 04:54:31 -0300559 0x0004,
Olivier Grenie2e802862011-08-05 10:39:15 -0300560 (1<<3)|(1<<11)|(1<<12)|(1<<13),
Olivier Grenie713d54a2011-01-04 04:54:31 -0300561 0x0814, /* Equal Lock */
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300562
563 12, 6,
Olivier Grenie713d54a2011-01-04 04:54:31 -0300564 0x001b,
565 0x7740,
566 0x005b,
567 0x8d80,
568 0x01c9,
569 0xc380,
570 0x0000,
571 0x0080,
572 0x0000,
573 0x0090,
574 0x0001,
575 0xd4c0,
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300576
577 1, 26,
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300578 0x6680,
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300579
580 /* set ADC level to -16 */
581 11, 79,
Olivier Grenie713d54a2011-01-04 04:54:31 -0300582 (1 << 13) - 825 - 117,
583 (1 << 13) - 837 - 117,
584 (1 << 13) - 811 - 117,
585 (1 << 13) - 766 - 117,
586 (1 << 13) - 737 - 117,
587 (1 << 13) - 693 - 117,
588 (1 << 13) - 648 - 117,
589 (1 << 13) - 619 - 117,
590 (1 << 13) - 575 - 117,
591 (1 << 13) - 531 - 117,
592 (1 << 13) - 501 - 117,
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300593
594 1, 142,
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300595 0x0410,
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300596
597 /* disable power smoothing */
598 8, 145,
Olivier Grenie713d54a2011-01-04 04:54:31 -0300599 0,
600 0,
601 0,
602 0,
603 0,
604 0,
605 0,
606 0,
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300607
608 1, 154,
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300609 1 << 13,
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300610
611 1, 168,
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300612 0x0ccd,
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300613
614 1, 183,
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300615 0x200f,
Olivier Grenie713d54a2011-01-04 04:54:31 -0300616
617 1, 212,
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300618 0x169,
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300619
620 5, 187,
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300621 0x023d,
622 0x00a4,
623 0x00a4,
624 0x7ff0,
625 0x3ccc,
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300626
627 1, 198,
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300628 0x800,
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300629
630 1, 222,
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300631 0x0010,
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300632
633 1, 235,
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300634 0x0062,
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300635
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300636 0,
637};
638
Patrick Boettchera75763f2006-10-18 08:34:16 -0300639static int dib7000p_demod_reset(struct dib7000p_state *state)
640{
641 dib7000p_set_power_mode(state, DIB7000P_POWER_ALL);
642
Olivier Grenie713d54a2011-01-04 04:54:31 -0300643 if (state->version == SOC7090)
644 dibx000_reset_i2c_master(&state->i2c_master);
645
Patrick Boettchera75763f2006-10-18 08:34:16 -0300646 dib7000p_set_adc_state(state, DIBX000_VBG_ENABLE);
647
648 /* restart all parts */
Olivier Grenie713d54a2011-01-04 04:54:31 -0300649 dib7000p_write_word(state, 770, 0xffff);
650 dib7000p_write_word(state, 771, 0xffff);
651 dib7000p_write_word(state, 772, 0x001f);
Olivier Grenie713d54a2011-01-04 04:54:31 -0300652 dib7000p_write_word(state, 1280, 0x001f - ((1 << 4) | (1 << 3)));
Patrick Boettchera75763f2006-10-18 08:34:16 -0300653
Olivier Grenie713d54a2011-01-04 04:54:31 -0300654 dib7000p_write_word(state, 770, 0);
655 dib7000p_write_word(state, 771, 0);
656 dib7000p_write_word(state, 772, 0);
Patrick Boettchera75763f2006-10-18 08:34:16 -0300657 dib7000p_write_word(state, 1280, 0);
658
Olivier Grenie2e802862011-08-05 10:39:15 -0300659 if (state->version != SOC7090) {
660 dib7000p_write_word(state, 898, 0x0003);
661 dib7000p_write_word(state, 898, 0);
662 }
663
Patrick Boettchera75763f2006-10-18 08:34:16 -0300664 /* default */
665 dib7000p_reset_pll(state);
666
667 if (dib7000p_reset_gpio(state) != 0)
Olivier Grenie713d54a2011-01-04 04:54:31 -0300668 dprintk("GPIO reset was not successful.");
Patrick Boettchera75763f2006-10-18 08:34:16 -0300669
Olivier Grenie713d54a2011-01-04 04:54:31 -0300670 if (state->version == SOC7090) {
671 dib7000p_write_word(state, 899, 0);
672
673 /* impulse noise */
674 dib7000p_write_word(state, 42, (1<<5) | 3); /* P_iqc_thsat_ipc = 1 ; P_iqc_win2 = 3 */
675 dib7000p_write_word(state, 43, 0x2d4); /*-300 fag P_iqc_dect_min = -280 */
676 dib7000p_write_word(state, 44, 300); /* 300 fag P_iqc_dect_min = +280 */
Olivier Grenie2e802862011-08-05 10:39:15 -0300677 dib7000p_write_word(state, 273, (0<<6) | 30);
Olivier Grenie713d54a2011-01-04 04:54:31 -0300678 }
Patrick Boettchera75763f2006-10-18 08:34:16 -0300679 if (dib7000p_set_output_mode(state, OUTMODE_HIGH_Z) != 0)
Olivier Grenie713d54a2011-01-04 04:54:31 -0300680 dprintk("OUTPUT_MODE could not be reset.");
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300681
682 dib7000p_set_adc_state(state, DIBX000_SLOW_ADC_ON);
683 dib7000p_sad_calib(state);
684 dib7000p_set_adc_state(state, DIBX000_SLOW_ADC_OFF);
685
Olivier Grenie713d54a2011-01-04 04:54:31 -0300686 /* unforce divstr regardless whether i2c enumeration was done or not */
687 dib7000p_write_word(state, 1285, dib7000p_read_word(state, 1285) & ~(1 << 1));
688
689 dib7000p_set_bandwidth(state, 8000);
690
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300691 if (state->version == SOC7090) {
Olivier Grenie2e802862011-08-05 10:39:15 -0300692 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 -0300693 } else {
Olivier Grenie713d54a2011-01-04 04:54:31 -0300694 if (state->cfg.tuner_is_baseband)
695 dib7000p_write_word(state, 36, 0x0755);
696 else
697 dib7000p_write_word(state, 36, 0x1f55);
698 }
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300699
700 dib7000p_write_tab(state, dib7000p_defaults);
Olivier Grenie2e802862011-08-05 10:39:15 -0300701 if (state->version != SOC7090) {
702 dib7000p_write_word(state, 901, 0x0006);
703 dib7000p_write_word(state, 902, (3 << 10) | (1 << 6));
704 dib7000p_write_word(state, 905, 0x2c8e);
705 }
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300706
Patrick Boettchera75763f2006-10-18 08:34:16 -0300707 dib7000p_set_power_mode(state, DIB7000P_POWER_INTERFACE_ONLY);
708
709 return 0;
710}
711
Patrick Boettchera75763f2006-10-18 08:34:16 -0300712static void dib7000p_pll_clk_cfg(struct dib7000p_state *state)
713{
714 u16 tmp = 0;
715 tmp = dib7000p_read_word(state, 903);
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300716 dib7000p_write_word(state, 903, (tmp | 0x1));
Patrick Boettchera75763f2006-10-18 08:34:16 -0300717 tmp = dib7000p_read_word(state, 900);
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300718 dib7000p_write_word(state, 900, (tmp & 0x7fff) | (1 << 6));
Patrick Boettchera75763f2006-10-18 08:34:16 -0300719}
720
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300721static void dib7000p_restart_agc(struct dib7000p_state *state)
Patrick Boettchera75763f2006-10-18 08:34:16 -0300722{
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300723 // P_restart_iqc & P_restart_agc
724 dib7000p_write_word(state, 770, (1 << 11) | (1 << 9));
725 dib7000p_write_word(state, 770, 0x0000);
Patrick Boettchera75763f2006-10-18 08:34:16 -0300726}
727
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300728static int dib7000p_update_lna(struct dib7000p_state *state)
Patrick Boettchera75763f2006-10-18 08:34:16 -0300729{
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300730 u16 dyn_gain;
731
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300732 if (state->cfg.update_lna) {
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300733 dyn_gain = dib7000p_read_word(state, 394);
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300734 if (state->cfg.update_lna(&state->demod, dyn_gain)) {
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300735 dib7000p_restart_agc(state);
736 return 1;
737 }
738 }
739
740 return 0;
741}
742
743static int dib7000p_set_agc_config(struct dib7000p_state *state, u8 band)
744{
745 struct dibx000_agc_config *agc = NULL;
746 int i;
747 if (state->current_band == band && state->current_agc != NULL)
748 return 0;
749 state->current_band = band;
750
751 for (i = 0; i < state->cfg.agc_config_count; i++)
752 if (state->cfg.agc[i].band_caps & band) {
753 agc = &state->cfg.agc[i];
754 break;
755 }
756
757 if (agc == NULL) {
Olivier Grenie713d54a2011-01-04 04:54:31 -0300758 dprintk("no valid AGC configuration found for band 0x%02x", band);
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300759 return -EINVAL;
760 }
761
762 state->current_agc = agc;
763
764 /* AGC */
Olivier Grenie713d54a2011-01-04 04:54:31 -0300765 dib7000p_write_word(state, 75, agc->setup);
766 dib7000p_write_word(state, 76, agc->inv_gain);
767 dib7000p_write_word(state, 77, agc->time_stabiliz);
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300768 dib7000p_write_word(state, 100, (agc->alpha_level << 12) | agc->thlock);
769
770 // Demod AGC loop configuration
771 dib7000p_write_word(state, 101, (agc->alpha_mant << 5) | agc->alpha_exp);
Olivier Grenie713d54a2011-01-04 04:54:31 -0300772 dib7000p_write_word(state, 102, (agc->beta_mant << 6) | agc->beta_exp);
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300773
774 /* AGC continued */
Olivier Grenie713d54a2011-01-04 04:54:31 -0300775 dprintk("WBD: ref: %d, sel: %d, active: %d, alpha: %d",
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300776 state->wbd_ref != 0 ? state->wbd_ref : agc->wbd_ref, agc->wbd_sel, !agc->perform_agc_softsplit, agc->wbd_sel);
777
778 if (state->wbd_ref != 0)
779 dib7000p_write_word(state, 105, (agc->wbd_inv << 12) | state->wbd_ref);
780 else
781 dib7000p_write_word(state, 105, (agc->wbd_inv << 12) | agc->wbd_ref);
782
783 dib7000p_write_word(state, 106, (agc->wbd_sel << 13) | (agc->wbd_alpha << 9) | (agc->perform_agc_softsplit << 8));
784
Olivier Grenie713d54a2011-01-04 04:54:31 -0300785 dib7000p_write_word(state, 107, agc->agc1_max);
786 dib7000p_write_word(state, 108, agc->agc1_min);
787 dib7000p_write_word(state, 109, agc->agc2_max);
788 dib7000p_write_word(state, 110, agc->agc2_min);
789 dib7000p_write_word(state, 111, (agc->agc1_pt1 << 8) | agc->agc1_pt2);
790 dib7000p_write_word(state, 112, agc->agc1_pt3);
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300791 dib7000p_write_word(state, 113, (agc->agc1_slope1 << 8) | agc->agc1_slope2);
Olivier Grenie713d54a2011-01-04 04:54:31 -0300792 dib7000p_write_word(state, 114, (agc->agc2_pt1 << 8) | agc->agc2_pt2);
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300793 dib7000p_write_word(state, 115, (agc->agc2_slope1 << 8) | agc->agc2_slope2);
794 return 0;
795}
796
Olivier Grenie713d54a2011-01-04 04:54:31 -0300797static void dib7000p_set_dds(struct dib7000p_state *state, s32 offset_khz)
798{
799 u32 internal = dib7000p_get_internal_freq(state);
800 s32 unit_khz_dds_val = 67108864 / (internal); /* 2**26 / Fsampling is the unit 1KHz offset */
801 u32 abs_offset_khz = ABS(offset_khz);
802 u32 dds = state->cfg.bw->ifreq & 0x1ffffff;
803 u8 invert = !!(state->cfg.bw->ifreq & (1 << 25));
804
805 dprintk("setting a frequency offset of %dkHz internal freq = %d invert = %d", offset_khz, internal, invert);
806
807 if (offset_khz < 0)
808 unit_khz_dds_val *= -1;
809
810 /* IF tuner */
811 if (invert)
812 dds -= (abs_offset_khz * unit_khz_dds_val); /* /100 because of /100 on the unit_khz_dds_val line calc for better accuracy */
813 else
814 dds += (abs_offset_khz * unit_khz_dds_val);
815
816 if (abs_offset_khz <= (internal / 2)) { /* Max dds offset is the half of the demod freq */
817 dib7000p_write_word(state, 21, (u16) (((dds >> 16) & 0x1ff) | (0 << 10) | (invert << 9)));
818 dib7000p_write_word(state, 22, (u16) (dds & 0xffff));
819 }
820}
821
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -0300822static int dib7000p_agc_startup(struct dvb_frontend *demod)
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300823{
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -0300824 struct dtv_frontend_properties *ch = &demod->dtv_property_cache;
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300825 struct dib7000p_state *state = demod->demodulator_priv;
826 int ret = -1;
827 u8 *agc_state = &state->agc_state;
828 u8 agc_split;
Olivier Grenie713d54a2011-01-04 04:54:31 -0300829 u16 reg;
830 u32 upd_demod_gain_period = 0x1000;
Olivier Grenie6fe10992012-12-31 09:23:26 -0300831 s32 frequency_offset = 0;
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300832
833 switch (state->agc_state) {
Olivier Grenie713d54a2011-01-04 04:54:31 -0300834 case 0:
Olivier Grenie713d54a2011-01-04 04:54:31 -0300835 dib7000p_set_power_mode(state, DIB7000P_POWER_ALL);
836 if (state->version == SOC7090) {
837 reg = dib7000p_read_word(state, 0x79b) & 0xff00;
838 dib7000p_write_word(state, 0x79a, upd_demod_gain_period & 0xFFFF); /* lsb */
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300839 dib7000p_write_word(state, 0x79b, reg | (1 << 14) | ((upd_demod_gain_period >> 16) & 0xFF));
Olivier Grenie713d54a2011-01-04 04:54:31 -0300840
841 /* enable adc i & q */
842 reg = dib7000p_read_word(state, 0x780);
843 dib7000p_write_word(state, 0x780, (reg | (0x3)) & (~(1 << 7)));
844 } else {
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300845 dib7000p_set_adc_state(state, DIBX000_ADC_ON);
846 dib7000p_pll_clk_cfg(state);
Olivier Grenie713d54a2011-01-04 04:54:31 -0300847 }
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300848
Olivier Grenie713d54a2011-01-04 04:54:31 -0300849 if (dib7000p_set_agc_config(state, BAND_OF_FREQUENCY(ch->frequency / 1000)) != 0)
850 return -1;
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300851
Olivier Grenie6fe10992012-12-31 09:23:26 -0300852 if (demod->ops.tuner_ops.get_frequency) {
853 u32 frequency_tuner;
854
855 demod->ops.tuner_ops.get_frequency(demod, &frequency_tuner);
856 frequency_offset = (s32)frequency_tuner / 1000 - ch->frequency / 1000;
857 }
858
859 dib7000p_set_dds(state, frequency_offset);
Olivier Grenie713d54a2011-01-04 04:54:31 -0300860 ret = 7;
861 (*agc_state)++;
862 break;
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300863
Olivier Grenie713d54a2011-01-04 04:54:31 -0300864 case 1:
Olivier Grenie713d54a2011-01-04 04:54:31 -0300865 if (state->cfg.agc_control)
866 state->cfg.agc_control(&state->demod, 1);
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300867
Olivier Grenie713d54a2011-01-04 04:54:31 -0300868 dib7000p_write_word(state, 78, 32768);
869 if (!state->current_agc->perform_agc_softsplit) {
870 /* we are using the wbd - so slow AGC startup */
871 /* force 0 split on WBD and restart AGC */
872 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 -0300873 (*agc_state)++;
874 ret = 5;
Olivier Grenie713d54a2011-01-04 04:54:31 -0300875 } else {
876 /* default AGC startup */
877 (*agc_state) = 4;
878 /* wait AGC rough lock time */
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300879 ret = 7;
Olivier Grenie713d54a2011-01-04 04:54:31 -0300880 }
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300881
Olivier Grenie713d54a2011-01-04 04:54:31 -0300882 dib7000p_restart_agc(state);
883 break;
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300884
Olivier Grenie713d54a2011-01-04 04:54:31 -0300885 case 2: /* fast split search path after 5sec */
886 dib7000p_write_word(state, 75, state->current_agc->setup | (1 << 4)); /* freeze AGC loop */
887 dib7000p_write_word(state, 106, (state->current_agc->wbd_sel << 13) | (2 << 9) | (0 << 8)); /* fast split search 0.25kHz */
888 (*agc_state)++;
889 ret = 14;
890 break;
891
892 case 3: /* split search ended */
893 agc_split = (u8) dib7000p_read_word(state, 396); /* store the split value for the next time */
894 dib7000p_write_word(state, 78, dib7000p_read_word(state, 394)); /* set AGC gain start value */
895
896 dib7000p_write_word(state, 75, state->current_agc->setup); /* std AGC loop */
897 dib7000p_write_word(state, 106, (state->current_agc->wbd_sel << 13) | (state->current_agc->wbd_alpha << 9) | agc_split); /* standard split search */
898
899 dib7000p_restart_agc(state);
900
901 dprintk("SPLIT %p: %hd", demod, agc_split);
902
903 (*agc_state)++;
904 ret = 5;
905 break;
906
907 case 4: /* LNA startup */
Olivier Grenie713d54a2011-01-04 04:54:31 -0300908 ret = 7;
909
910 if (dib7000p_update_lna(state))
Olivier Grenie713d54a2011-01-04 04:54:31 -0300911 ret = 5;
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300912 else
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300913 (*agc_state)++;
Olivier Grenie713d54a2011-01-04 04:54:31 -0300914 break;
915
916 case 5:
917 if (state->cfg.agc_control)
918 state->cfg.agc_control(&state->demod, 0);
919 (*agc_state)++;
920 break;
921 default:
922 break;
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300923 }
924 return ret;
925}
926
927static void dib7000p_update_timf(struct dib7000p_state *state)
928{
929 u32 timf = (dib7000p_read_word(state, 427) << 16) | dib7000p_read_word(state, 428);
930 state->timf = timf * 160 / (state->current_bandwidth / 50);
931 dib7000p_write_word(state, 23, (u16) (timf >> 16));
932 dib7000p_write_word(state, 24, (u16) (timf & 0xffff));
Olivier Grenie713d54a2011-01-04 04:54:31 -0300933 dprintk("updated timf_frequency: %d (default: %d)", state->timf, state->cfg.bw->timf);
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300934
935}
936
Olivier Grenie713d54a2011-01-04 04:54:31 -0300937u32 dib7000p_ctrl_timf(struct dvb_frontend *fe, u8 op, u32 timf)
938{
939 struct dib7000p_state *state = fe->demodulator_priv;
940 switch (op) {
941 case DEMOD_TIMF_SET:
942 state->timf = timf;
943 break;
944 case DEMOD_TIMF_UPDATE:
945 dib7000p_update_timf(state);
946 break;
947 case DEMOD_TIMF_GET:
948 break;
949 }
950 dib7000p_set_bandwidth(state, state->current_bandwidth);
951 return state->timf;
952}
953EXPORT_SYMBOL(dib7000p_ctrl_timf);
954
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -0300955static void dib7000p_set_channel(struct dib7000p_state *state,
956 struct dtv_frontend_properties *ch, u8 seq)
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300957{
958 u16 value, est[4];
959
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -0300960 dib7000p_set_bandwidth(state, BANDWIDTH_TO_KHZ(ch->bandwidth_hz));
Patrick Boettchera75763f2006-10-18 08:34:16 -0300961
962 /* nfft, guard, qam, alpha */
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300963 value = 0;
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -0300964 switch (ch->transmission_mode) {
Olivier Grenie713d54a2011-01-04 04:54:31 -0300965 case TRANSMISSION_MODE_2K:
966 value |= (0 << 7);
967 break;
Mauro Carvalho Chehab46f72962011-01-16 13:01:20 -0200968 case TRANSMISSION_MODE_4K:
Olivier Grenie713d54a2011-01-04 04:54:31 -0300969 value |= (2 << 7);
970 break;
971 default:
972 case TRANSMISSION_MODE_8K:
973 value |= (1 << 7);
974 break;
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300975 }
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -0300976 switch (ch->guard_interval) {
Olivier Grenie713d54a2011-01-04 04:54:31 -0300977 case GUARD_INTERVAL_1_32:
978 value |= (0 << 5);
979 break;
980 case GUARD_INTERVAL_1_16:
981 value |= (1 << 5);
982 break;
983 case GUARD_INTERVAL_1_4:
984 value |= (3 << 5);
985 break;
986 default:
987 case GUARD_INTERVAL_1_8:
988 value |= (2 << 5);
989 break;
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300990 }
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -0300991 switch (ch->modulation) {
Olivier Grenie713d54a2011-01-04 04:54:31 -0300992 case QPSK:
993 value |= (0 << 3);
994 break;
995 case QAM_16:
996 value |= (1 << 3);
997 break;
998 default:
999 case QAM_64:
1000 value |= (2 << 3);
1001 break;
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001002 }
1003 switch (HIERARCHY_1) {
Olivier Grenie713d54a2011-01-04 04:54:31 -03001004 case HIERARCHY_2:
1005 value |= 2;
1006 break;
1007 case HIERARCHY_4:
1008 value |= 4;
1009 break;
1010 default:
1011 case HIERARCHY_1:
1012 value |= 1;
1013 break;
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001014 }
1015 dib7000p_write_word(state, 0, value);
Olivier Grenie713d54a2011-01-04 04:54:31 -03001016 dib7000p_write_word(state, 5, (seq << 4) | 1); /* do not force tps, search list 0 */
Patrick Boettchera75763f2006-10-18 08:34:16 -03001017
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001018 /* P_dintl_native, P_dintlv_inv, P_hrch, P_code_rate, P_select_hp */
1019 value = 0;
1020 if (1 != 0)
1021 value |= (1 << 6);
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -03001022 if (ch->hierarchy == 1)
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001023 value |= (1 << 4);
1024 if (1 == 1)
1025 value |= 1;
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -03001026 switch ((ch->hierarchy == 0 || 1 == 1) ? ch->code_rate_HP : ch->code_rate_LP) {
Olivier Grenie713d54a2011-01-04 04:54:31 -03001027 case FEC_2_3:
1028 value |= (2 << 1);
1029 break;
1030 case FEC_3_4:
1031 value |= (3 << 1);
1032 break;
1033 case FEC_5_6:
1034 value |= (5 << 1);
1035 break;
1036 case FEC_7_8:
1037 value |= (7 << 1);
1038 break;
1039 default:
1040 case FEC_1_2:
1041 value |= (1 << 1);
1042 break;
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001043 }
1044 dib7000p_write_word(state, 208, value);
1045
1046 /* offset loop parameters */
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001047 dib7000p_write_word(state, 26, 0x6680);
1048 dib7000p_write_word(state, 32, 0x0003);
1049 dib7000p_write_word(state, 29, 0x1273);
1050 dib7000p_write_word(state, 33, 0x0005);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001051
1052 /* P_dvsy_sync_wait */
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -03001053 switch (ch->transmission_mode) {
Olivier Grenie713d54a2011-01-04 04:54:31 -03001054 case TRANSMISSION_MODE_8K:
1055 value = 256;
1056 break;
1057 case TRANSMISSION_MODE_4K:
1058 value = 128;
1059 break;
1060 case TRANSMISSION_MODE_2K:
1061 default:
1062 value = 64;
1063 break;
Patrick Boettchera75763f2006-10-18 08:34:16 -03001064 }
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -03001065 switch (ch->guard_interval) {
Olivier Grenie713d54a2011-01-04 04:54:31 -03001066 case GUARD_INTERVAL_1_16:
1067 value *= 2;
1068 break;
1069 case GUARD_INTERVAL_1_8:
1070 value *= 4;
1071 break;
1072 case GUARD_INTERVAL_1_4:
1073 value *= 8;
1074 break;
1075 default:
1076 case GUARD_INTERVAL_1_32:
1077 value *= 1;
1078 break;
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001079 }
Olivier Grenie970d14c2010-09-07 12:50:46 -03001080 if (state->cfg.diversity_delay == 0)
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001081 state->div_sync_wait = (value * 3) / 2 + 48;
Olivier Grenie970d14c2010-09-07 12:50:46 -03001082 else
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001083 state->div_sync_wait = (value * 3) / 2 + state->cfg.diversity_delay;
Patrick Boettchera75763f2006-10-18 08:34:16 -03001084
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001085 /* deactive the possibility of diversity reception if extended interleaver */
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -03001086 state->div_force_off = !1 && ch->transmission_mode != TRANSMISSION_MODE_8K;
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001087 dib7000p_set_diversity_in(&state->demod, state->div_state);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001088
1089 /* channel estimation fine configuration */
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -03001090 switch (ch->modulation) {
Olivier Grenie713d54a2011-01-04 04:54:31 -03001091 case QAM_64:
1092 est[0] = 0x0148; /* P_adp_regul_cnt 0.04 */
1093 est[1] = 0xfff0; /* P_adp_noise_cnt -0.002 */
1094 est[2] = 0x00a4; /* P_adp_regul_ext 0.02 */
1095 est[3] = 0xfff8; /* P_adp_noise_ext -0.001 */
1096 break;
1097 case QAM_16:
1098 est[0] = 0x023d; /* P_adp_regul_cnt 0.07 */
1099 est[1] = 0xffdf; /* P_adp_noise_cnt -0.004 */
1100 est[2] = 0x00a4; /* P_adp_regul_ext 0.02 */
1101 est[3] = 0xfff0; /* P_adp_noise_ext -0.002 */
1102 break;
1103 default:
1104 est[0] = 0x099a; /* P_adp_regul_cnt 0.3 */
1105 est[1] = 0xffae; /* P_adp_noise_cnt -0.01 */
1106 est[2] = 0x0333; /* P_adp_regul_ext 0.1 */
1107 est[3] = 0xfff8; /* P_adp_noise_ext -0.002 */
1108 break;
Patrick Boettchera75763f2006-10-18 08:34:16 -03001109 }
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001110 for (value = 0; value < 4; value++)
1111 dib7000p_write_word(state, 187 + value, est[value]);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001112}
1113
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -03001114static int dib7000p_autosearch_start(struct dvb_frontend *demod)
Patrick Boettchera75763f2006-10-18 08:34:16 -03001115{
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -03001116 struct dtv_frontend_properties *ch = &demod->dtv_property_cache;
Patrick Boettchera75763f2006-10-18 08:34:16 -03001117 struct dib7000p_state *state = demod->demodulator_priv;
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -03001118 struct dtv_frontend_properties schan;
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001119 u32 value, factor;
Olivier Grenie713d54a2011-01-04 04:54:31 -03001120 u32 internal = dib7000p_get_internal_freq(state);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001121
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001122 schan = *ch;
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -03001123 schan.modulation = QAM_64;
1124 schan.guard_interval = GUARD_INTERVAL_1_32;
1125 schan.transmission_mode = TRANSMISSION_MODE_8K;
1126 schan.code_rate_HP = FEC_2_3;
1127 schan.code_rate_LP = FEC_3_4;
1128 schan.hierarchy = 0;
Patrick Boettchera75763f2006-10-18 08:34:16 -03001129
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001130 dib7000p_set_channel(state, &schan, 7);
1131
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -03001132 factor = BANDWIDTH_TO_KHZ(ch->bandwidth_hz);
Olivier Grenie2e802862011-08-05 10:39:15 -03001133 if (factor >= 5000) {
1134 if (state->version == SOC7090)
1135 factor = 2;
1136 else
1137 factor = 1;
1138 } else
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001139 factor = 6;
Patrick Boettchera75763f2006-10-18 08:34:16 -03001140
Olivier Grenie713d54a2011-01-04 04:54:31 -03001141 value = 30 * internal * factor;
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001142 dib7000p_write_word(state, 6, (u16) ((value >> 16) & 0xffff));
1143 dib7000p_write_word(state, 7, (u16) (value & 0xffff));
Olivier Grenie713d54a2011-01-04 04:54:31 -03001144 value = 100 * internal * factor;
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001145 dib7000p_write_word(state, 8, (u16) ((value >> 16) & 0xffff));
1146 dib7000p_write_word(state, 9, (u16) (value & 0xffff));
Olivier Grenie713d54a2011-01-04 04:54:31 -03001147 value = 500 * internal * factor;
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001148 dib7000p_write_word(state, 10, (u16) ((value >> 16) & 0xffff));
1149 dib7000p_write_word(state, 11, (u16) (value & 0xffff));
Patrick Boettchera75763f2006-10-18 08:34:16 -03001150
1151 value = dib7000p_read_word(state, 0);
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001152 dib7000p_write_word(state, 0, (u16) ((1 << 9) | value));
Patrick Boettchera75763f2006-10-18 08:34:16 -03001153 dib7000p_read_word(state, 1284);
1154 dib7000p_write_word(state, 0, (u16) value);
1155
1156 return 0;
1157}
1158
1159static int dib7000p_autosearch_is_irq(struct dvb_frontend *demod)
1160{
1161 struct dib7000p_state *state = demod->demodulator_priv;
1162 u16 irq_pending = dib7000p_read_word(state, 1284);
1163
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001164 if (irq_pending & 0x1)
Patrick Boettchera75763f2006-10-18 08:34:16 -03001165 return 1;
1166
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001167 if (irq_pending & 0x2)
Patrick Boettchera75763f2006-10-18 08:34:16 -03001168 return 2;
1169
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001170 return 0;
Patrick Boettchera75763f2006-10-18 08:34:16 -03001171}
1172
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001173static void dib7000p_spur_protect(struct dib7000p_state *state, u32 rf_khz, u32 bw)
1174{
Olivier Grenie713d54a2011-01-04 04:54:31 -03001175 static s16 notch[] = { 16143, 14402, 12238, 9713, 6902, 3888, 759, -2392 };
1176 static u8 sine[] = { 0, 2, 3, 5, 6, 8, 9, 11, 13, 14, 16, 17, 19, 20, 22,
1177 24, 25, 27, 28, 30, 31, 33, 34, 36, 38, 39, 41, 42, 44, 45, 47, 48, 50, 51,
1178 53, 55, 56, 58, 59, 61, 62, 64, 65, 67, 68, 70, 71, 73, 74, 76, 77, 79, 80,
1179 82, 83, 85, 86, 88, 89, 91, 92, 94, 95, 97, 98, 99, 101, 102, 104, 105,
1180 107, 108, 109, 111, 112, 114, 115, 117, 118, 119, 121, 122, 123, 125, 126,
1181 128, 129, 130, 132, 133, 134, 136, 137, 138, 140, 141, 142, 144, 145, 146,
1182 147, 149, 150, 151, 152, 154, 155, 156, 157, 159, 160, 161, 162, 164, 165,
1183 166, 167, 168, 170, 171, 172, 173, 174, 175, 177, 178, 179, 180, 181, 182,
1184 183, 184, 185, 186, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198,
1185 199, 200, 201, 202, 203, 204, 205, 206, 207, 207, 208, 209, 210, 211, 212,
1186 213, 214, 215, 215, 216, 217, 218, 219, 220, 220, 221, 222, 223, 224, 224,
1187 225, 226, 227, 227, 228, 229, 229, 230, 231, 231, 232, 233, 233, 234, 235,
1188 235, 236, 237, 237, 238, 238, 239, 239, 240, 241, 241, 242, 242, 243, 243,
1189 244, 244, 245, 245, 245, 246, 246, 247, 247, 248, 248, 248, 249, 249, 249,
1190 250, 250, 250, 251, 251, 251, 252, 252, 252, 252, 253, 253, 253, 253, 254,
1191 254, 254, 254, 254, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
1192 255, 255, 255, 255, 255, 255
1193 };
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001194
1195 u32 xtal = state->cfg.bw->xtal_hz / 1000;
Julia Lawall75b697f2009-08-01 16:48:41 -03001196 int f_rel = DIV_ROUND_CLOSEST(rf_khz, xtal) * xtal - rf_khz;
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001197 int k;
Olivier Grenie713d54a2011-01-04 04:54:31 -03001198 int coef_re[8], coef_im[8];
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001199 int bw_khz = bw;
1200 u32 pha;
1201
Olivier Grenie713d54a2011-01-04 04:54:31 -03001202 dprintk("relative position of the Spur: %dk (RF: %dk, XTAL: %dk)", f_rel, rf_khz, xtal);
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001203
Olivier Grenie713d54a2011-01-04 04:54:31 -03001204 if (f_rel < -bw_khz / 2 || f_rel > bw_khz / 2)
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001205 return;
1206
1207 bw_khz /= 100;
1208
Olivier Grenie713d54a2011-01-04 04:54:31 -03001209 dib7000p_write_word(state, 142, 0x0610);
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001210
1211 for (k = 0; k < 8; k++) {
Olivier Grenie713d54a2011-01-04 04:54:31 -03001212 pha = ((f_rel * (k + 1) * 112 * 80 / bw_khz) / 1000) & 0x3ff;
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001213
Olivier Grenie713d54a2011-01-04 04:54:31 -03001214 if (pha == 0) {
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001215 coef_re[k] = 256;
1216 coef_im[k] = 0;
Olivier Grenie713d54a2011-01-04 04:54:31 -03001217 } else if (pha < 256) {
1218 coef_re[k] = sine[256 - (pha & 0xff)];
1219 coef_im[k] = sine[pha & 0xff];
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001220 } else if (pha == 256) {
1221 coef_re[k] = 0;
1222 coef_im[k] = 256;
1223 } else if (pha < 512) {
Olivier Grenie713d54a2011-01-04 04:54:31 -03001224 coef_re[k] = -sine[pha & 0xff];
1225 coef_im[k] = sine[256 - (pha & 0xff)];
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001226 } else if (pha == 512) {
1227 coef_re[k] = -256;
1228 coef_im[k] = 0;
1229 } else if (pha < 768) {
Olivier Grenie713d54a2011-01-04 04:54:31 -03001230 coef_re[k] = -sine[256 - (pha & 0xff)];
1231 coef_im[k] = -sine[pha & 0xff];
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001232 } else if (pha == 768) {
1233 coef_re[k] = 0;
1234 coef_im[k] = -256;
1235 } else {
Olivier Grenie713d54a2011-01-04 04:54:31 -03001236 coef_re[k] = sine[pha & 0xff];
1237 coef_im[k] = -sine[256 - (pha & 0xff)];
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001238 }
1239
1240 coef_re[k] *= notch[k];
Olivier Grenie713d54a2011-01-04 04:54:31 -03001241 coef_re[k] += (1 << 14);
1242 if (coef_re[k] >= (1 << 24))
1243 coef_re[k] = (1 << 24) - 1;
1244 coef_re[k] /= (1 << 15);
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001245
1246 coef_im[k] *= notch[k];
Olivier Grenie713d54a2011-01-04 04:54:31 -03001247 coef_im[k] += (1 << 14);
1248 if (coef_im[k] >= (1 << 24))
1249 coef_im[k] = (1 << 24) - 1;
1250 coef_im[k] /= (1 << 15);
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001251
Olivier Grenie713d54a2011-01-04 04:54:31 -03001252 dprintk("PALF COEF: %d re: %d im: %d", k, coef_re[k], coef_im[k]);
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001253
1254 dib7000p_write_word(state, 143, (0 << 14) | (k << 10) | (coef_re[k] & 0x3ff));
1255 dib7000p_write_word(state, 144, coef_im[k] & 0x3ff);
1256 dib7000p_write_word(state, 143, (1 << 14) | (k << 10) | (coef_re[k] & 0x3ff));
1257 }
Olivier Grenie713d54a2011-01-04 04:54:31 -03001258 dib7000p_write_word(state, 143, 0);
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001259}
1260
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -03001261static int dib7000p_tune(struct dvb_frontend *demod)
Patrick Boettchera75763f2006-10-18 08:34:16 -03001262{
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -03001263 struct dtv_frontend_properties *ch = &demod->dtv_property_cache;
Patrick Boettchera75763f2006-10-18 08:34:16 -03001264 struct dib7000p_state *state = demod->demodulator_priv;
1265 u16 tmp = 0;
1266
1267 if (ch != NULL)
1268 dib7000p_set_channel(state, ch, 0);
1269 else
1270 return -EINVAL;
1271
1272 // restart demod
1273 dib7000p_write_word(state, 770, 0x4000);
1274 dib7000p_write_word(state, 770, 0x0000);
1275 msleep(45);
1276
1277 /* 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 Doran8f6956c72007-07-31 07:09:30 -03001278 tmp = (0 << 14) | (4 << 10) | (0 << 9) | (3 << 5) | (1 << 4) | (0x3);
1279 if (state->sfn_workaround_active) {
Olivier Grenie713d54a2011-01-04 04:54:31 -03001280 dprintk("SFN workaround is active");
Matt Doran8f6956c72007-07-31 07:09:30 -03001281 tmp |= (1 << 9);
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001282 dib7000p_write_word(state, 166, 0x4000);
Matt Doran8f6956c72007-07-31 07:09:30 -03001283 } else {
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001284 dib7000p_write_word(state, 166, 0x0000);
Matt Doran8f6956c72007-07-31 07:09:30 -03001285 }
1286 dib7000p_write_word(state, 29, tmp);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001287
1288 // never achieved a lock with that bandwidth so far - wait for osc-freq to update
1289 if (state->timf == 0)
1290 msleep(200);
1291
1292 /* offset loop parameters */
1293
1294 /* P_timf_alpha, P_corm_alpha=6, P_corm_thres=0x80 */
1295 tmp = (6 << 8) | 0x80;
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -03001296 switch (ch->transmission_mode) {
Olivier Grenie713d54a2011-01-04 04:54:31 -03001297 case TRANSMISSION_MODE_2K:
1298 tmp |= (2 << 12);
1299 break;
Mauro Carvalho Chehab46f72962011-01-16 13:01:20 -02001300 case TRANSMISSION_MODE_4K:
Olivier Grenie713d54a2011-01-04 04:54:31 -03001301 tmp |= (3 << 12);
1302 break;
1303 default:
1304 case TRANSMISSION_MODE_8K:
1305 tmp |= (4 << 12);
1306 break;
Patrick Boettchera75763f2006-10-18 08:34:16 -03001307 }
Olivier Grenie713d54a2011-01-04 04:54:31 -03001308 dib7000p_write_word(state, 26, tmp); /* timf_a(6xxx) */
Patrick Boettchera75763f2006-10-18 08:34:16 -03001309
1310 /* P_ctrl_freeze_pha_shift=0, P_ctrl_pha_off_max */
1311 tmp = (0 << 4);
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -03001312 switch (ch->transmission_mode) {
Olivier Grenie713d54a2011-01-04 04:54:31 -03001313 case TRANSMISSION_MODE_2K:
1314 tmp |= 0x6;
1315 break;
Mauro Carvalho Chehab46f72962011-01-16 13:01:20 -02001316 case TRANSMISSION_MODE_4K:
Olivier Grenie713d54a2011-01-04 04:54:31 -03001317 tmp |= 0x7;
1318 break;
1319 default:
1320 case TRANSMISSION_MODE_8K:
1321 tmp |= 0x8;
1322 break;
Patrick Boettchera75763f2006-10-18 08:34:16 -03001323 }
Olivier Grenie713d54a2011-01-04 04:54:31 -03001324 dib7000p_write_word(state, 32, tmp);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001325
1326 /* P_ctrl_sfreq_inh=0, P_ctrl_sfreq_step */
1327 tmp = (0 << 4);
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -03001328 switch (ch->transmission_mode) {
Olivier Grenie713d54a2011-01-04 04:54:31 -03001329 case TRANSMISSION_MODE_2K:
1330 tmp |= 0x6;
1331 break;
1332 case TRANSMISSION_MODE_4K:
1333 tmp |= 0x7;
1334 break;
1335 default:
1336 case TRANSMISSION_MODE_8K:
1337 tmp |= 0x8;
1338 break;
Patrick Boettchera75763f2006-10-18 08:34:16 -03001339 }
Olivier Grenie713d54a2011-01-04 04:54:31 -03001340 dib7000p_write_word(state, 33, tmp);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001341
Olivier Grenie713d54a2011-01-04 04:54:31 -03001342 tmp = dib7000p_read_word(state, 509);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001343 if (!((tmp >> 6) & 0x1)) {
1344 /* restart the fec */
Olivier Grenie713d54a2011-01-04 04:54:31 -03001345 tmp = dib7000p_read_word(state, 771);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001346 dib7000p_write_word(state, 771, tmp | (1 << 1));
1347 dib7000p_write_word(state, 771, tmp);
Olivier Grenie713d54a2011-01-04 04:54:31 -03001348 msleep(40);
1349 tmp = dib7000p_read_word(state, 509);
1350 }
1351 // we achieved a lock - it's time to update the osc freq
1352 if ((tmp >> 6) & 0x1) {
1353 dib7000p_update_timf(state);
1354 /* P_timf_alpha += 2 */
1355 tmp = dib7000p_read_word(state, 26);
1356 dib7000p_write_word(state, 26, (tmp & ~(0xf << 12)) | ((((tmp >> 12) & 0xf) + 5) << 12));
Patrick Boettchera75763f2006-10-18 08:34:16 -03001357 }
1358
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001359 if (state->cfg.spur_protect)
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -03001360 dib7000p_spur_protect(state, ch->frequency / 1000, BANDWIDTH_TO_KHZ(ch->bandwidth_hz));
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001361
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -03001362 dib7000p_set_bandwidth(state, BANDWIDTH_TO_KHZ(ch->bandwidth_hz));
Patrick Boettchera75763f2006-10-18 08:34:16 -03001363 return 0;
1364}
1365
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001366static int dib7000p_wakeup(struct dvb_frontend *demod)
Patrick Boettchera75763f2006-10-18 08:34:16 -03001367{
Patrick Boettchera75763f2006-10-18 08:34:16 -03001368 struct dib7000p_state *state = demod->demodulator_priv;
Patrick Boettchera75763f2006-10-18 08:34:16 -03001369 dib7000p_set_power_mode(state, DIB7000P_POWER_ALL);
1370 dib7000p_set_adc_state(state, DIBX000_SLOW_ADC_ON);
Olivier Grenie713d54a2011-01-04 04:54:31 -03001371 if (state->version == SOC7090)
1372 dib7000p_sad_calib(state);
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001373 return 0;
Patrick Boettchera75763f2006-10-18 08:34:16 -03001374}
1375
1376static int dib7000p_sleep(struct dvb_frontend *demod)
1377{
1378 struct dib7000p_state *state = demod->demodulator_priv;
Olivier Grenie713d54a2011-01-04 04:54:31 -03001379 if (state->version == SOC7090)
Olivier Grenie2e802862011-08-05 10:39:15 -03001380 return dib7000p_set_power_mode(state, DIB7000P_POWER_INTERFACE_ONLY);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001381 return dib7000p_set_output_mode(state, OUTMODE_HIGH_Z) | dib7000p_set_power_mode(state, DIB7000P_POWER_INTERFACE_ONLY);
1382}
1383
1384static int dib7000p_identify(struct dib7000p_state *st)
1385{
1386 u16 value;
Olivier Grenie713d54a2011-01-04 04:54:31 -03001387 dprintk("checking demod on I2C address: %d (%x)", st->i2c_addr, st->i2c_addr);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001388
1389 if ((value = dib7000p_read_word(st, 768)) != 0x01b3) {
Olivier Grenie713d54a2011-01-04 04:54:31 -03001390 dprintk("wrong Vendor ID (read=0x%x)", value);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001391 return -EREMOTEIO;
1392 }
1393
1394 if ((value = dib7000p_read_word(st, 769)) != 0x4000) {
Olivier Grenie713d54a2011-01-04 04:54:31 -03001395 dprintk("wrong Device ID (%x)", value);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001396 return -EREMOTEIO;
1397 }
1398
1399 return 0;
1400}
1401
Mauro Carvalho Chehab7c61d802011-12-30 11:30:21 -03001402static int dib7000p_get_frontend(struct dvb_frontend *fe)
Patrick Boettchera75763f2006-10-18 08:34:16 -03001403{
Mauro Carvalho Chehab7c61d802011-12-30 11:30:21 -03001404 struct dtv_frontend_properties *fep = &fe->dtv_property_cache;
Patrick Boettchera75763f2006-10-18 08:34:16 -03001405 struct dib7000p_state *state = fe->demodulator_priv;
Olivier Grenie713d54a2011-01-04 04:54:31 -03001406 u16 tps = dib7000p_read_word(state, 463);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001407
1408 fep->inversion = INVERSION_AUTO;
1409
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -03001410 fep->bandwidth_hz = BANDWIDTH_TO_HZ(state->current_bandwidth);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001411
1412 switch ((tps >> 8) & 0x3) {
Olivier Grenie713d54a2011-01-04 04:54:31 -03001413 case 0:
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -03001414 fep->transmission_mode = TRANSMISSION_MODE_2K;
Olivier Grenie713d54a2011-01-04 04:54:31 -03001415 break;
1416 case 1:
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -03001417 fep->transmission_mode = TRANSMISSION_MODE_8K;
Olivier Grenie713d54a2011-01-04 04:54:31 -03001418 break;
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -03001419 /* case 2: fep->transmission_mode = TRANSMISSION_MODE_4K; break; */
Patrick Boettchera75763f2006-10-18 08:34:16 -03001420 }
1421
1422 switch (tps & 0x3) {
Olivier Grenie713d54a2011-01-04 04:54:31 -03001423 case 0:
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -03001424 fep->guard_interval = GUARD_INTERVAL_1_32;
Olivier Grenie713d54a2011-01-04 04:54:31 -03001425 break;
1426 case 1:
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -03001427 fep->guard_interval = GUARD_INTERVAL_1_16;
Olivier Grenie713d54a2011-01-04 04:54:31 -03001428 break;
1429 case 2:
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -03001430 fep->guard_interval = GUARD_INTERVAL_1_8;
Olivier Grenie713d54a2011-01-04 04:54:31 -03001431 break;
1432 case 3:
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -03001433 fep->guard_interval = GUARD_INTERVAL_1_4;
Olivier Grenie713d54a2011-01-04 04:54:31 -03001434 break;
Patrick Boettchera75763f2006-10-18 08:34:16 -03001435 }
1436
1437 switch ((tps >> 14) & 0x3) {
Olivier Grenie713d54a2011-01-04 04:54:31 -03001438 case 0:
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -03001439 fep->modulation = QPSK;
Olivier Grenie713d54a2011-01-04 04:54:31 -03001440 break;
1441 case 1:
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -03001442 fep->modulation = QAM_16;
Olivier Grenie713d54a2011-01-04 04:54:31 -03001443 break;
1444 case 2:
1445 default:
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -03001446 fep->modulation = QAM_64;
Olivier Grenie713d54a2011-01-04 04:54:31 -03001447 break;
Patrick Boettchera75763f2006-10-18 08:34:16 -03001448 }
1449
1450 /* as long as the frontend_param structure is fixed for hierarchical transmission I refuse to use it */
1451 /* (tps >> 13) & 0x1 == hrch is used, (tps >> 10) & 0x7 == alpha */
1452
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -03001453 fep->hierarchy = HIERARCHY_NONE;
Patrick Boettchera75763f2006-10-18 08:34:16 -03001454 switch ((tps >> 5) & 0x7) {
Olivier Grenie713d54a2011-01-04 04:54:31 -03001455 case 1:
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -03001456 fep->code_rate_HP = FEC_1_2;
Olivier Grenie713d54a2011-01-04 04:54:31 -03001457 break;
1458 case 2:
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -03001459 fep->code_rate_HP = FEC_2_3;
Olivier Grenie713d54a2011-01-04 04:54:31 -03001460 break;
1461 case 3:
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -03001462 fep->code_rate_HP = FEC_3_4;
Olivier Grenie713d54a2011-01-04 04:54:31 -03001463 break;
1464 case 5:
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -03001465 fep->code_rate_HP = FEC_5_6;
Olivier Grenie713d54a2011-01-04 04:54:31 -03001466 break;
1467 case 7:
1468 default:
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -03001469 fep->code_rate_HP = FEC_7_8;
Olivier Grenie713d54a2011-01-04 04:54:31 -03001470 break;
Patrick Boettchera75763f2006-10-18 08:34:16 -03001471
1472 }
1473
1474 switch ((tps >> 2) & 0x7) {
Olivier Grenie713d54a2011-01-04 04:54:31 -03001475 case 1:
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -03001476 fep->code_rate_LP = FEC_1_2;
Olivier Grenie713d54a2011-01-04 04:54:31 -03001477 break;
1478 case 2:
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -03001479 fep->code_rate_LP = FEC_2_3;
Olivier Grenie713d54a2011-01-04 04:54:31 -03001480 break;
1481 case 3:
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -03001482 fep->code_rate_LP = FEC_3_4;
Olivier Grenie713d54a2011-01-04 04:54:31 -03001483 break;
1484 case 5:
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -03001485 fep->code_rate_LP = FEC_5_6;
Olivier Grenie713d54a2011-01-04 04:54:31 -03001486 break;
1487 case 7:
1488 default:
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -03001489 fep->code_rate_LP = FEC_7_8;
Olivier Grenie713d54a2011-01-04 04:54:31 -03001490 break;
Patrick Boettchera75763f2006-10-18 08:34:16 -03001491 }
1492
1493 /* native interleaver: (dib7000p_read_word(state, 464) >> 5) & 0x1 */
1494
1495 return 0;
1496}
1497
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -03001498static int dib7000p_set_frontend(struct dvb_frontend *fe)
Patrick Boettchera75763f2006-10-18 08:34:16 -03001499{
Mauro Carvalho Chehab7c61d802011-12-30 11:30:21 -03001500 struct dtv_frontend_properties *fep = &fe->dtv_property_cache;
Patrick Boettchera75763f2006-10-18 08:34:16 -03001501 struct dib7000p_state *state = fe->demodulator_priv;
Soeren Moch853ea132008-01-25 06:27:06 -03001502 int time, ret;
Patrick Boettchera75763f2006-10-18 08:34:16 -03001503
Olivier Grenie2e802862011-08-05 10:39:15 -03001504 if (state->version == SOC7090)
Olivier Grenie713d54a2011-01-04 04:54:31 -03001505 dib7090_set_diversity_in(fe, 0);
Olivier Grenie2e802862011-08-05 10:39:15 -03001506 else
Olivier Grenie713d54a2011-01-04 04:54:31 -03001507 dib7000p_set_output_mode(state, OUTMODE_HIGH_Z);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001508
Olivier Grenie713d54a2011-01-04 04:54:31 -03001509 /* maybe the parameter has been changed */
Matt Doran8f6956c72007-07-31 07:09:30 -03001510 state->sfn_workaround_active = buggy_sfn_workaround;
1511
Patrick Boettchera75763f2006-10-18 08:34:16 -03001512 if (fe->ops.tuner_ops.set_params)
Mauro Carvalho Chehab14d24d12011-12-24 12:24:33 -03001513 fe->ops.tuner_ops.set_params(fe);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001514
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001515 /* start up the AGC */
1516 state->agc_state = 0;
1517 do {
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -03001518 time = dib7000p_agc_startup(fe);
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001519 if (time != -1)
1520 msleep(time);
1521 } while (time != -1);
1522
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -03001523 if (fep->transmission_mode == TRANSMISSION_MODE_AUTO ||
1524 fep->guard_interval == GUARD_INTERVAL_AUTO || fep->modulation == QAM_AUTO || fep->code_rate_HP == FEC_AUTO) {
Patrick Boettchera75763f2006-10-18 08:34:16 -03001525 int i = 800, found;
1526
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -03001527 dib7000p_autosearch_start(fe);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001528 do {
1529 msleep(1);
1530 found = dib7000p_autosearch_is_irq(fe);
1531 } while (found == 0 && i--);
1532
Olivier Grenie713d54a2011-01-04 04:54:31 -03001533 dprintk("autosearch returns: %d", found);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001534 if (found == 0 || found == 1)
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001535 return 0;
Patrick Boettchera75763f2006-10-18 08:34:16 -03001536
Mauro Carvalho Chehab7c61d802011-12-30 11:30:21 -03001537 dib7000p_get_frontend(fe);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001538 }
1539
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -03001540 ret = dib7000p_tune(fe);
Soeren Moch853ea132008-01-25 06:27:06 -03001541
Patrick Boettchera75763f2006-10-18 08:34:16 -03001542 /* make this a config parameter */
Olivier Grenie2e802862011-08-05 10:39:15 -03001543 if (state->version == SOC7090) {
Olivier Grenie713d54a2011-01-04 04:54:31 -03001544 dib7090_set_output_mode(fe, state->cfg.output_mode);
Olivier Grenie2e802862011-08-05 10:39:15 -03001545 if (state->cfg.enMpegOutput == 0) {
1546 dib7090_setDibTxMux(state, MPEG_ON_DIBTX);
1547 dib7090_setHostBusMux(state, DIBTX_ON_HOSTBUS);
1548 }
1549 } else
Olivier Grenie713d54a2011-01-04 04:54:31 -03001550 dib7000p_set_output_mode(state, state->cfg.output_mode);
1551
1552 return ret;
Patrick Boettchera75763f2006-10-18 08:34:16 -03001553}
1554
Olivier Grenie713d54a2011-01-04 04:54:31 -03001555static int dib7000p_read_status(struct dvb_frontend *fe, fe_status_t * stat)
Patrick Boettchera75763f2006-10-18 08:34:16 -03001556{
1557 struct dib7000p_state *state = fe->demodulator_priv;
1558 u16 lock = dib7000p_read_word(state, 509);
1559
1560 *stat = 0;
1561
1562 if (lock & 0x8000)
1563 *stat |= FE_HAS_SIGNAL;
1564 if (lock & 0x3000)
1565 *stat |= FE_HAS_CARRIER;
1566 if (lock & 0x0100)
1567 *stat |= FE_HAS_VITERBI;
1568 if (lock & 0x0010)
1569 *stat |= FE_HAS_SYNC;
Olivier Grenie713d54a2011-01-04 04:54:31 -03001570 if ((lock & 0x0038) == 0x38)
Patrick Boettchera75763f2006-10-18 08:34:16 -03001571 *stat |= FE_HAS_LOCK;
1572
1573 return 0;
1574}
1575
Olivier Grenie713d54a2011-01-04 04:54:31 -03001576static int dib7000p_read_ber(struct dvb_frontend *fe, u32 * ber)
Patrick Boettchera75763f2006-10-18 08:34:16 -03001577{
1578 struct dib7000p_state *state = fe->demodulator_priv;
1579 *ber = (dib7000p_read_word(state, 500) << 16) | dib7000p_read_word(state, 501);
1580 return 0;
1581}
1582
Olivier Grenie713d54a2011-01-04 04:54:31 -03001583static int dib7000p_read_unc_blocks(struct dvb_frontend *fe, u32 * unc)
Patrick Boettchera75763f2006-10-18 08:34:16 -03001584{
1585 struct dib7000p_state *state = fe->demodulator_priv;
1586 *unc = dib7000p_read_word(state, 506);
1587 return 0;
1588}
1589
Olivier Grenie713d54a2011-01-04 04:54:31 -03001590static int dib7000p_read_signal_strength(struct dvb_frontend *fe, u16 * strength)
Patrick Boettchera75763f2006-10-18 08:34:16 -03001591{
1592 struct dib7000p_state *state = fe->demodulator_priv;
1593 u16 val = dib7000p_read_word(state, 394);
1594 *strength = 65535 - val;
1595 return 0;
1596}
1597
Olivier Grenie713d54a2011-01-04 04:54:31 -03001598static int dib7000p_read_snr(struct dvb_frontend *fe, u16 * snr)
Patrick Boettchera75763f2006-10-18 08:34:16 -03001599{
Olivier Grenieef801962009-09-15 06:46:52 -03001600 struct dib7000p_state *state = fe->demodulator_priv;
1601 u16 val;
1602 s32 signal_mant, signal_exp, noise_mant, noise_exp;
1603 u32 result = 0;
1604
1605 val = dib7000p_read_word(state, 479);
1606 noise_mant = (val >> 4) & 0xff;
1607 noise_exp = ((val & 0xf) << 2);
1608 val = dib7000p_read_word(state, 480);
1609 noise_exp += ((val >> 14) & 0x3);
1610 if ((noise_exp & 0x20) != 0)
1611 noise_exp -= 0x40;
1612
1613 signal_mant = (val >> 6) & 0xFF;
Olivier Grenie713d54a2011-01-04 04:54:31 -03001614 signal_exp = (val & 0x3F);
Olivier Grenieef801962009-09-15 06:46:52 -03001615 if ((signal_exp & 0x20) != 0)
1616 signal_exp -= 0x40;
1617
1618 if (signal_mant != 0)
Olivier Grenie713d54a2011-01-04 04:54:31 -03001619 result = intlog10(2) * 10 * signal_exp + 10 * intlog10(signal_mant);
Olivier Grenieef801962009-09-15 06:46:52 -03001620 else
1621 result = intlog10(2) * 10 * signal_exp - 100;
1622
1623 if (noise_mant != 0)
Olivier Grenie713d54a2011-01-04 04:54:31 -03001624 result -= intlog10(2) * 10 * noise_exp + 10 * intlog10(noise_mant);
Olivier Grenieef801962009-09-15 06:46:52 -03001625 else
1626 result -= intlog10(2) * 10 * noise_exp - 100;
1627
1628 *snr = result / ((1 << 24) / 10);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001629 return 0;
1630}
1631
Olivier Grenie713d54a2011-01-04 04:54:31 -03001632static int dib7000p_fe_get_tune_settings(struct dvb_frontend *fe, struct dvb_frontend_tune_settings *tune)
Patrick Boettchera75763f2006-10-18 08:34:16 -03001633{
1634 tune->min_delay_ms = 1000;
1635 return 0;
1636}
1637
1638static void dib7000p_release(struct dvb_frontend *demod)
1639{
1640 struct dib7000p_state *st = demod->demodulator_priv;
1641 dibx000_exit_i2c_master(&st->i2c_master);
Olivier Grenie713d54a2011-01-04 04:54:31 -03001642 i2c_del_adapter(&st->dib7090_tuner_adap);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001643 kfree(st);
1644}
1645
1646int dib7000pc_detection(struct i2c_adapter *i2c_adap)
1647{
Olivier Grenie5a0deee2011-05-03 12:27:33 -03001648 u8 *tx, *rx;
Patrick Boettchera75763f2006-10-18 08:34:16 -03001649 struct i2c_msg msg[2] = {
Olivier Grenie5a0deee2011-05-03 12:27:33 -03001650 {.addr = 18 >> 1, .flags = 0, .len = 2},
1651 {.addr = 18 >> 1, .flags = I2C_M_RD, .len = 2},
Patrick Boettchera75763f2006-10-18 08:34:16 -03001652 };
Olivier Grenie5a0deee2011-05-03 12:27:33 -03001653 int ret = 0;
1654
1655 tx = kzalloc(2*sizeof(u8), GFP_KERNEL);
1656 if (!tx)
1657 return -ENOMEM;
1658 rx = kzalloc(2*sizeof(u8), GFP_KERNEL);
1659 if (!rx) {
Olivier Grenie5a0deee2011-05-03 12:27:33 -03001660 ret = -ENOMEM;
Dan Carpenter0c61cc3b2011-08-06 05:00:34 -03001661 goto rx_memory_error;
Olivier Grenie5a0deee2011-05-03 12:27:33 -03001662 }
1663
1664 msg[0].buf = tx;
1665 msg[1].buf = rx;
Patrick Boettchera75763f2006-10-18 08:34:16 -03001666
1667 tx[0] = 0x03;
1668 tx[1] = 0x00;
1669
1670 if (i2c_transfer(i2c_adap, msg, 2) == 2)
1671 if (rx[0] == 0x01 && rx[1] == 0xb3) {
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001672 dprintk("-D- DiB7000PC detected");
Patrick Boettchera75763f2006-10-18 08:34:16 -03001673 return 1;
1674 }
1675
1676 msg[0].addr = msg[1].addr = 0x40;
1677
1678 if (i2c_transfer(i2c_adap, msg, 2) == 2)
1679 if (rx[0] == 0x01 && rx[1] == 0xb3) {
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001680 dprintk("-D- DiB7000PC detected");
Patrick Boettchera75763f2006-10-18 08:34:16 -03001681 return 1;
1682 }
1683
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001684 dprintk("-D- DiB7000PC not detected");
Olivier Grenie5a0deee2011-05-03 12:27:33 -03001685
1686 kfree(rx);
1687rx_memory_error:
1688 kfree(tx);
1689 return ret;
Patrick Boettchera75763f2006-10-18 08:34:16 -03001690}
1691EXPORT_SYMBOL(dib7000pc_detection);
1692
Olivier Grenie713d54a2011-01-04 04:54:31 -03001693struct i2c_adapter *dib7000p_get_i2c_master(struct dvb_frontend *demod, enum dibx000_i2c_interface intf, int gating)
Patrick Boettchera75763f2006-10-18 08:34:16 -03001694{
1695 struct dib7000p_state *st = demod->demodulator_priv;
1696 return dibx000_get_i2c_adapter(&st->i2c_master, intf, gating);
1697}
1698EXPORT_SYMBOL(dib7000p_get_i2c_master);
1699
Olivier Grenief8731f42009-09-18 04:08:43 -03001700int dib7000p_pid_filter_ctrl(struct dvb_frontend *fe, u8 onoff)
1701{
Olivier Grenie713d54a2011-01-04 04:54:31 -03001702 struct dib7000p_state *state = fe->demodulator_priv;
1703 u16 val = dib7000p_read_word(state, 235) & 0xffef;
1704 val |= (onoff & 0x1) << 4;
1705 dprintk("PID filter enabled %d", onoff);
1706 return dib7000p_write_word(state, 235, val);
Olivier Grenief8731f42009-09-18 04:08:43 -03001707}
1708EXPORT_SYMBOL(dib7000p_pid_filter_ctrl);
1709
1710int dib7000p_pid_filter(struct dvb_frontend *fe, u8 id, u16 pid, u8 onoff)
1711{
Olivier Grenie713d54a2011-01-04 04:54:31 -03001712 struct dib7000p_state *state = fe->demodulator_priv;
1713 dprintk("PID filter: index %x, PID %d, OnOff %d", id, pid, onoff);
1714 return dib7000p_write_word(state, 241 + id, onoff ? (1 << 13) | pid : 0);
Olivier Grenief8731f42009-09-18 04:08:43 -03001715}
1716EXPORT_SYMBOL(dib7000p_pid_filter);
1717
Patrick Boettchera75763f2006-10-18 08:34:16 -03001718int dib7000p_i2c_enumeration(struct i2c_adapter *i2c, int no_of_demods, u8 default_addr, struct dib7000p_config cfg[])
1719{
Randy Dunlap30d81bb2010-02-08 20:30:44 -03001720 struct dib7000p_state *dpst;
Patrick Boettchera75763f2006-10-18 08:34:16 -03001721 int k = 0;
1722 u8 new_addr = 0;
1723
Randy Dunlap30d81bb2010-02-08 20:30:44 -03001724 dpst = kzalloc(sizeof(struct dib7000p_state), GFP_KERNEL);
1725 if (!dpst)
Andrew Morton0b427602010-04-27 19:09:45 -03001726 return -ENOMEM;
Randy Dunlap30d81bb2010-02-08 20:30:44 -03001727
1728 dpst->i2c_adap = i2c;
Patrick Boettcher79fcce32011-08-03 12:08:21 -03001729 mutex_init(&dpst->i2c_buffer_lock);
Randy Dunlap30d81bb2010-02-08 20:30:44 -03001730
Olivier Grenie713d54a2011-01-04 04:54:31 -03001731 for (k = no_of_demods - 1; k >= 0; k--) {
Randy Dunlap30d81bb2010-02-08 20:30:44 -03001732 dpst->cfg = cfg[k];
Patrick Boettchera75763f2006-10-18 08:34:16 -03001733
1734 /* designated i2c address */
Olivier Grenie713d54a2011-01-04 04:54:31 -03001735 if (cfg[k].default_i2c_addr != 0)
1736 new_addr = cfg[k].default_i2c_addr + (k << 1);
1737 else
1738 new_addr = (0x40 + k) << 1;
Randy Dunlap30d81bb2010-02-08 20:30:44 -03001739 dpst->i2c_addr = new_addr;
Olivier Grenie713d54a2011-01-04 04:54:31 -03001740 dib7000p_write_word(dpst, 1287, 0x0003); /* sram lead in, rdy */
Randy Dunlap30d81bb2010-02-08 20:30:44 -03001741 if (dib7000p_identify(dpst) != 0) {
1742 dpst->i2c_addr = default_addr;
Olivier Grenie713d54a2011-01-04 04:54:31 -03001743 dib7000p_write_word(dpst, 1287, 0x0003); /* sram lead in, rdy */
Randy Dunlap30d81bb2010-02-08 20:30:44 -03001744 if (dib7000p_identify(dpst) != 0) {
Patrick Boettchera75763f2006-10-18 08:34:16 -03001745 dprintk("DiB7000P #%d: not identified\n", k);
Randy Dunlap30d81bb2010-02-08 20:30:44 -03001746 kfree(dpst);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001747 return -EIO;
1748 }
1749 }
1750
1751 /* start diversity to pull_down div_str - just for i2c-enumeration */
Randy Dunlap30d81bb2010-02-08 20:30:44 -03001752 dib7000p_set_output_mode(dpst, OUTMODE_DIVERSITY);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001753
1754 /* set new i2c address and force divstart */
Randy Dunlap30d81bb2010-02-08 20:30:44 -03001755 dib7000p_write_word(dpst, 1285, (new_addr << 2) | 0x2);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001756
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001757 dprintk("IC %d initialized (to i2c_address 0x%x)", k, new_addr);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001758 }
1759
1760 for (k = 0; k < no_of_demods; k++) {
Randy Dunlap30d81bb2010-02-08 20:30:44 -03001761 dpst->cfg = cfg[k];
Olivier Grenie713d54a2011-01-04 04:54:31 -03001762 if (cfg[k].default_i2c_addr != 0)
1763 dpst->i2c_addr = (cfg[k].default_i2c_addr + k) << 1;
1764 else
1765 dpst->i2c_addr = (0x40 + k) << 1;
Patrick Boettchera75763f2006-10-18 08:34:16 -03001766
1767 // unforce divstr
Randy Dunlap30d81bb2010-02-08 20:30:44 -03001768 dib7000p_write_word(dpst, 1285, dpst->i2c_addr << 2);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001769
1770 /* deactivate div - it was just for i2c-enumeration */
Randy Dunlap30d81bb2010-02-08 20:30:44 -03001771 dib7000p_set_output_mode(dpst, OUTMODE_HIGH_Z);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001772 }
1773
Randy Dunlap30d81bb2010-02-08 20:30:44 -03001774 kfree(dpst);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001775 return 0;
1776}
1777EXPORT_SYMBOL(dib7000p_i2c_enumeration);
1778
Olivier Grenie713d54a2011-01-04 04:54:31 -03001779static const s32 lut_1000ln_mant[] = {
1780 6908, 6956, 7003, 7047, 7090, 7131, 7170, 7208, 7244, 7279, 7313, 7346, 7377, 7408, 7438, 7467, 7495, 7523, 7549, 7575, 7600
1781};
1782
1783static s32 dib7000p_get_adc_power(struct dvb_frontend *fe)
1784{
1785 struct dib7000p_state *state = fe->demodulator_priv;
1786 u32 tmp_val = 0, exp = 0, mant = 0;
1787 s32 pow_i;
1788 u16 buf[2];
1789 u8 ix = 0;
1790
1791 buf[0] = dib7000p_read_word(state, 0x184);
1792 buf[1] = dib7000p_read_word(state, 0x185);
1793 pow_i = (buf[0] << 16) | buf[1];
1794 dprintk("raw pow_i = %d", pow_i);
1795
1796 tmp_val = pow_i;
1797 while (tmp_val >>= 1)
1798 exp++;
1799
1800 mant = (pow_i * 1000 / (1 << exp));
1801 dprintk(" mant = %d exp = %d", mant / 1000, exp);
1802
1803 ix = (u8) ((mant - 1000) / 100); /* index of the LUT */
1804 dprintk(" ix = %d", ix);
1805
1806 pow_i = (lut_1000ln_mant[ix] + 693 * (exp - 20) - 6908);
1807 pow_i = (pow_i << 8) / 1000;
1808 dprintk(" pow_i = %d", pow_i);
1809
1810 return pow_i;
1811}
1812
1813static int map_addr_to_serpar_number(struct i2c_msg *msg)
1814{
1815 if ((msg->buf[0] <= 15))
1816 msg->buf[0] -= 1;
1817 else if (msg->buf[0] == 17)
1818 msg->buf[0] = 15;
1819 else if (msg->buf[0] == 16)
1820 msg->buf[0] = 17;
1821 else if (msg->buf[0] == 19)
1822 msg->buf[0] = 16;
1823 else if (msg->buf[0] >= 21 && msg->buf[0] <= 25)
1824 msg->buf[0] -= 3;
1825 else if (msg->buf[0] == 28)
1826 msg->buf[0] = 23;
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001827 else
Olivier Grenie713d54a2011-01-04 04:54:31 -03001828 return -EINVAL;
Olivier Grenie713d54a2011-01-04 04:54:31 -03001829 return 0;
1830}
1831
1832static int w7090p_tuner_write_serpar(struct i2c_adapter *i2c_adap, struct i2c_msg msg[], int num)
1833{
1834 struct dib7000p_state *state = i2c_get_adapdata(i2c_adap);
1835 u8 n_overflow = 1;
1836 u16 i = 1000;
1837 u16 serpar_num = msg[0].buf[0];
1838
1839 while (n_overflow == 1 && i) {
1840 n_overflow = (dib7000p_read_word(state, 1984) >> 1) & 0x1;
1841 i--;
1842 if (i == 0)
1843 dprintk("Tuner ITF: write busy (overflow)");
1844 }
1845 dib7000p_write_word(state, 1985, (1 << 6) | (serpar_num & 0x3f));
1846 dib7000p_write_word(state, 1986, (msg[0].buf[1] << 8) | msg[0].buf[2]);
1847
1848 return num;
1849}
1850
1851static int w7090p_tuner_read_serpar(struct i2c_adapter *i2c_adap, struct i2c_msg msg[], int num)
1852{
1853 struct dib7000p_state *state = i2c_get_adapdata(i2c_adap);
1854 u8 n_overflow = 1, n_empty = 1;
1855 u16 i = 1000;
1856 u16 serpar_num = msg[0].buf[0];
1857 u16 read_word;
1858
1859 while (n_overflow == 1 && i) {
1860 n_overflow = (dib7000p_read_word(state, 1984) >> 1) & 0x1;
1861 i--;
1862 if (i == 0)
1863 dprintk("TunerITF: read busy (overflow)");
1864 }
1865 dib7000p_write_word(state, 1985, (0 << 6) | (serpar_num & 0x3f));
1866
1867 i = 1000;
1868 while (n_empty == 1 && i) {
1869 n_empty = dib7000p_read_word(state, 1984) & 0x1;
1870 i--;
1871 if (i == 0)
1872 dprintk("TunerITF: read busy (empty)");
1873 }
1874 read_word = dib7000p_read_word(state, 1987);
1875 msg[1].buf[0] = (read_word >> 8) & 0xff;
1876 msg[1].buf[1] = (read_word) & 0xff;
1877
1878 return num;
1879}
1880
1881static int w7090p_tuner_rw_serpar(struct i2c_adapter *i2c_adap, struct i2c_msg msg[], int num)
1882{
1883 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... */
1884 if (num == 1) { /* write */
1885 return w7090p_tuner_write_serpar(i2c_adap, msg, 1);
1886 } else { /* read */
1887 return w7090p_tuner_read_serpar(i2c_adap, msg, 2);
1888 }
1889 }
1890 return num;
1891}
1892
Olivier Greniea685dbb2011-08-05 14:10:40 -03001893static int dib7090p_rw_on_apb(struct i2c_adapter *i2c_adap,
1894 struct i2c_msg msg[], int num, u16 apb_address)
Olivier Grenie713d54a2011-01-04 04:54:31 -03001895{
1896 struct dib7000p_state *state = i2c_get_adapdata(i2c_adap);
1897 u16 word;
1898
1899 if (num == 1) { /* write */
1900 dib7000p_write_word(state, apb_address, ((msg[0].buf[1] << 8) | (msg[0].buf[2])));
1901 } else {
1902 word = dib7000p_read_word(state, apb_address);
1903 msg[1].buf[0] = (word >> 8) & 0xff;
1904 msg[1].buf[1] = (word) & 0xff;
1905 }
1906
1907 return num;
1908}
1909
1910static int dib7090_tuner_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg msg[], int num)
1911{
1912 struct dib7000p_state *state = i2c_get_adapdata(i2c_adap);
1913
1914 u16 apb_address = 0, word;
1915 int i = 0;
1916 switch (msg[0].buf[0]) {
1917 case 0x12:
1918 apb_address = 1920;
1919 break;
1920 case 0x14:
1921 apb_address = 1921;
1922 break;
1923 case 0x24:
1924 apb_address = 1922;
1925 break;
1926 case 0x1a:
1927 apb_address = 1923;
1928 break;
1929 case 0x22:
1930 apb_address = 1924;
1931 break;
1932 case 0x33:
1933 apb_address = 1926;
1934 break;
1935 case 0x34:
1936 apb_address = 1927;
1937 break;
1938 case 0x35:
1939 apb_address = 1928;
1940 break;
1941 case 0x36:
1942 apb_address = 1929;
1943 break;
1944 case 0x37:
1945 apb_address = 1930;
1946 break;
1947 case 0x38:
1948 apb_address = 1931;
1949 break;
1950 case 0x39:
1951 apb_address = 1932;
1952 break;
1953 case 0x2a:
1954 apb_address = 1935;
1955 break;
1956 case 0x2b:
1957 apb_address = 1936;
1958 break;
1959 case 0x2c:
1960 apb_address = 1937;
1961 break;
1962 case 0x2d:
1963 apb_address = 1938;
1964 break;
1965 case 0x2e:
1966 apb_address = 1939;
1967 break;
1968 case 0x2f:
1969 apb_address = 1940;
1970 break;
1971 case 0x30:
1972 apb_address = 1941;
1973 break;
1974 case 0x31:
1975 apb_address = 1942;
1976 break;
1977 case 0x32:
1978 apb_address = 1943;
1979 break;
1980 case 0x3e:
1981 apb_address = 1944;
1982 break;
1983 case 0x3f:
1984 apb_address = 1945;
1985 break;
1986 case 0x40:
1987 apb_address = 1948;
1988 break;
1989 case 0x25:
1990 apb_address = 914;
1991 break;
1992 case 0x26:
1993 apb_address = 915;
1994 break;
1995 case 0x27:
Olivier Grenie2e802862011-08-05 10:39:15 -03001996 apb_address = 917;
Olivier Grenie713d54a2011-01-04 04:54:31 -03001997 break;
1998 case 0x28:
Olivier Grenie2e802862011-08-05 10:39:15 -03001999 apb_address = 916;
Olivier Grenie713d54a2011-01-04 04:54:31 -03002000 break;
2001 case 0x1d:
2002 i = ((dib7000p_read_word(state, 72) >> 12) & 0x3);
2003 word = dib7000p_read_word(state, 384 + i);
2004 msg[1].buf[0] = (word >> 8) & 0xff;
2005 msg[1].buf[1] = (word) & 0xff;
2006 return num;
2007 case 0x1f:
2008 if (num == 1) { /* write */
2009 word = (u16) ((msg[0].buf[1] << 8) | msg[0].buf[2]);
2010 word &= 0x3;
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002011 word = (dib7000p_read_word(state, 72) & ~(3 << 12)) | (word << 12);
Olivier Grenie713d54a2011-01-04 04:54:31 -03002012 dib7000p_write_word(state, 72, word); /* Set the proper input */
2013 return num;
2014 }
2015 }
2016
2017 if (apb_address != 0) /* R/W acces via APB */
2018 return dib7090p_rw_on_apb(i2c_adap, msg, num, apb_address);
2019 else /* R/W access via SERPAR */
2020 return w7090p_tuner_rw_serpar(i2c_adap, msg, num);
2021
2022 return 0;
2023}
2024
2025static u32 dib7000p_i2c_func(struct i2c_adapter *adapter)
2026{
2027 return I2C_FUNC_I2C;
2028}
2029
2030static struct i2c_algorithm dib7090_tuner_xfer_algo = {
2031 .master_xfer = dib7090_tuner_xfer,
2032 .functionality = dib7000p_i2c_func,
2033};
2034
2035struct i2c_adapter *dib7090_get_i2c_tuner(struct dvb_frontend *fe)
2036{
2037 struct dib7000p_state *st = fe->demodulator_priv;
2038 return &st->dib7090_tuner_adap;
2039}
2040EXPORT_SYMBOL(dib7090_get_i2c_tuner);
2041
2042static int dib7090_host_bus_drive(struct dib7000p_state *state, u8 drive)
2043{
2044 u16 reg;
2045
2046 /* drive host bus 2, 3, 4 */
2047 reg = dib7000p_read_word(state, 1798) & ~((0x7) | (0x7 << 6) | (0x7 << 12));
2048 reg |= (drive << 12) | (drive << 6) | drive;
2049 dib7000p_write_word(state, 1798, reg);
2050
2051 /* drive host bus 5,6 */
2052 reg = dib7000p_read_word(state, 1799) & ~((0x7 << 2) | (0x7 << 8));
2053 reg |= (drive << 8) | (drive << 2);
2054 dib7000p_write_word(state, 1799, reg);
2055
2056 /* drive host bus 7, 8, 9 */
2057 reg = dib7000p_read_word(state, 1800) & ~((0x7) | (0x7 << 6) | (0x7 << 12));
2058 reg |= (drive << 12) | (drive << 6) | drive;
2059 dib7000p_write_word(state, 1800, reg);
2060
2061 /* drive host bus 10, 11 */
2062 reg = dib7000p_read_word(state, 1801) & ~((0x7 << 2) | (0x7 << 8));
2063 reg |= (drive << 8) | (drive << 2);
2064 dib7000p_write_word(state, 1801, reg);
2065
2066 /* drive host bus 12, 13, 14 */
2067 reg = dib7000p_read_word(state, 1802) & ~((0x7) | (0x7 << 6) | (0x7 << 12));
2068 reg |= (drive << 12) | (drive << 6) | drive;
2069 dib7000p_write_word(state, 1802, reg);
2070
2071 return 0;
2072}
2073
2074static u32 dib7090_calcSyncFreq(u32 P_Kin, u32 P_Kout, u32 insertExtSynchro, u32 syncSize)
2075{
2076 u32 quantif = 3;
2077 u32 nom = (insertExtSynchro * P_Kin + syncSize);
2078 u32 denom = P_Kout;
2079 u32 syncFreq = ((nom << quantif) / denom);
2080
2081 if ((syncFreq & ((1 << quantif) - 1)) != 0)
2082 syncFreq = (syncFreq >> quantif) + 1;
2083 else
2084 syncFreq = (syncFreq >> quantif);
2085
2086 if (syncFreq != 0)
2087 syncFreq = syncFreq - 1;
2088
2089 return syncFreq;
2090}
2091
2092static int dib7090_cfg_DibTx(struct dib7000p_state *state, u32 P_Kin, u32 P_Kout, u32 insertExtSynchro, u32 synchroMode, u32 syncWord, u32 syncSize)
2093{
Olivier Grenie713d54a2011-01-04 04:54:31 -03002094 dprintk("Configure DibStream Tx");
Olivier Grenie713d54a2011-01-04 04:54:31 -03002095
2096 dib7000p_write_word(state, 1615, 1);
2097 dib7000p_write_word(state, 1603, P_Kin);
2098 dib7000p_write_word(state, 1605, P_Kout);
2099 dib7000p_write_word(state, 1606, insertExtSynchro);
2100 dib7000p_write_word(state, 1608, synchroMode);
2101 dib7000p_write_word(state, 1609, (syncWord >> 16) & 0xffff);
2102 dib7000p_write_word(state, 1610, syncWord & 0xffff);
2103 dib7000p_write_word(state, 1612, syncSize);
2104 dib7000p_write_word(state, 1615, 0);
2105
Olivier Grenie713d54a2011-01-04 04:54:31 -03002106 return 0;
2107}
2108
2109static int dib7090_cfg_DibRx(struct dib7000p_state *state, u32 P_Kin, u32 P_Kout, u32 synchroMode, u32 insertExtSynchro, u32 syncWord, u32 syncSize,
2110 u32 dataOutRate)
2111{
2112 u32 syncFreq;
2113
2114 dprintk("Configure DibStream Rx");
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002115 if ((P_Kin != 0) && (P_Kout != 0)) {
Olivier Grenie713d54a2011-01-04 04:54:31 -03002116 syncFreq = dib7090_calcSyncFreq(P_Kin, P_Kout, insertExtSynchro, syncSize);
2117 dib7000p_write_word(state, 1542, syncFreq);
2118 }
2119 dib7000p_write_word(state, 1554, 1);
2120 dib7000p_write_word(state, 1536, P_Kin);
2121 dib7000p_write_word(state, 1537, P_Kout);
2122 dib7000p_write_word(state, 1539, synchroMode);
2123 dib7000p_write_word(state, 1540, (syncWord >> 16) & 0xffff);
2124 dib7000p_write_word(state, 1541, syncWord & 0xffff);
2125 dib7000p_write_word(state, 1543, syncSize);
2126 dib7000p_write_word(state, 1544, dataOutRate);
2127 dib7000p_write_word(state, 1554, 0);
2128
2129 return 0;
2130}
2131
Olivier Grenie2e802862011-08-05 10:39:15 -03002132static void dib7090_enMpegMux(struct dib7000p_state *state, int onoff)
Olivier Grenie713d54a2011-01-04 04:54:31 -03002133{
Olivier Grenie2e802862011-08-05 10:39:15 -03002134 u16 reg_1287 = dib7000p_read_word(state, 1287);
Olivier Grenie713d54a2011-01-04 04:54:31 -03002135
Olivier Grenie2e802862011-08-05 10:39:15 -03002136 switch (onoff) {
2137 case 1:
2138 reg_1287 &= ~(1<<7);
2139 break;
2140 case 0:
2141 reg_1287 |= (1<<7);
2142 break;
2143 }
Olivier Grenie713d54a2011-01-04 04:54:31 -03002144
Olivier Grenie2e802862011-08-05 10:39:15 -03002145 dib7000p_write_word(state, 1287, reg_1287);
Olivier Grenie713d54a2011-01-04 04:54:31 -03002146}
2147
Olivier Grenie2e802862011-08-05 10:39:15 -03002148static void dib7090_configMpegMux(struct dib7000p_state *state,
2149 u16 pulseWidth, u16 enSerialMode, u16 enSerialClkDiv2)
Olivier Grenie713d54a2011-01-04 04:54:31 -03002150{
Olivier Grenie713d54a2011-01-04 04:54:31 -03002151 dprintk("Enable Mpeg mux");
Olivier Grenie713d54a2011-01-04 04:54:31 -03002152
Olivier Grenie2e802862011-08-05 10:39:15 -03002153 dib7090_enMpegMux(state, 0);
Olivier Grenie713d54a2011-01-04 04:54:31 -03002154
Olivier Grenie2e802862011-08-05 10:39:15 -03002155 /* If the input mode is MPEG do not divide the serial clock */
2156 if ((enSerialMode == 1) && (state->input_mode_mpeg == 1))
2157 enSerialClkDiv2 = 0;
Olivier Grenie713d54a2011-01-04 04:54:31 -03002158
Olivier Grenie2e802862011-08-05 10:39:15 -03002159 dib7000p_write_word(state, 1287, ((pulseWidth & 0x1f) << 2)
2160 | ((enSerialMode & 0x1) << 1)
2161 | (enSerialClkDiv2 & 0x1));
2162
2163 dib7090_enMpegMux(state, 1);
Olivier Grenie713d54a2011-01-04 04:54:31 -03002164}
2165
Olivier Grenie2e802862011-08-05 10:39:15 -03002166static void dib7090_setDibTxMux(struct dib7000p_state *state, int mode)
Olivier Grenie713d54a2011-01-04 04:54:31 -03002167{
Olivier Grenie2e802862011-08-05 10:39:15 -03002168 u16 reg_1288 = dib7000p_read_word(state, 1288) & ~(0x7 << 7);
Olivier Grenie713d54a2011-01-04 04:54:31 -03002169
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002170 switch (mode) {
Olivier Grenie2e802862011-08-05 10:39:15 -03002171 case MPEG_ON_DIBTX:
2172 dprintk("SET MPEG ON DIBSTREAM TX");
2173 dib7090_cfg_DibTx(state, 8, 5, 0, 0, 0, 0);
2174 reg_1288 |= (1<<9);
Olivier Grenie713d54a2011-01-04 04:54:31 -03002175 break;
Olivier Grenie2e802862011-08-05 10:39:15 -03002176 case DIV_ON_DIBTX:
2177 dprintk("SET DIV_OUT ON DIBSTREAM TX");
2178 dib7090_cfg_DibTx(state, 5, 5, 0, 0, 0, 0);
2179 reg_1288 |= (1<<8);
Olivier Grenie713d54a2011-01-04 04:54:31 -03002180 break;
Olivier Grenie2e802862011-08-05 10:39:15 -03002181 case ADC_ON_DIBTX:
2182 dprintk("SET ADC_OUT ON DIBSTREAM TX");
2183 dib7090_cfg_DibTx(state, 20, 5, 10, 0, 0, 0);
2184 reg_1288 |= (1<<7);
2185 break;
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002186 default:
Olivier Grenie713d54a2011-01-04 04:54:31 -03002187 break;
2188 }
Olivier Grenie2e802862011-08-05 10:39:15 -03002189 dib7000p_write_word(state, 1288, reg_1288);
Olivier Grenie713d54a2011-01-04 04:54:31 -03002190}
2191
Olivier Grenie2e802862011-08-05 10:39:15 -03002192static void dib7090_setHostBusMux(struct dib7000p_state *state, int mode)
Olivier Grenie713d54a2011-01-04 04:54:31 -03002193{
Olivier Grenie2e802862011-08-05 10:39:15 -03002194 u16 reg_1288 = dib7000p_read_word(state, 1288) & ~(0x7 << 4);
2195
2196 switch (mode) {
2197 case DEMOUT_ON_HOSTBUS:
2198 dprintk("SET DEM OUT OLD INTERF ON HOST BUS");
2199 dib7090_enMpegMux(state, 0);
2200 reg_1288 |= (1<<6);
2201 break;
2202 case DIBTX_ON_HOSTBUS:
2203 dprintk("SET DIBSTREAM TX ON HOST BUS");
2204 dib7090_enMpegMux(state, 0);
2205 reg_1288 |= (1<<5);
2206 break;
2207 case MPEG_ON_HOSTBUS:
2208 dprintk("SET MPEG MUX ON HOST BUS");
2209 reg_1288 |= (1<<4);
2210 break;
2211 default:
2212 break;
2213 }
2214 dib7000p_write_word(state, 1288, reg_1288);
2215}
2216
2217int dib7090_set_diversity_in(struct dvb_frontend *fe, int onoff)
2218{
2219 struct dib7000p_state *state = fe->demodulator_priv;
2220 u16 reg_1287;
2221
Olivier Grenie713d54a2011-01-04 04:54:31 -03002222 switch (onoff) {
Olivier Grenie2e802862011-08-05 10:39:15 -03002223 case 0: /* only use the internal way - not the diversity input */
2224 dprintk("%s mode OFF : by default Enable Mpeg INPUT", __func__);
2225 dib7090_cfg_DibRx(state, 8, 5, 0, 0, 0, 8, 0);
2226
2227 /* Do not divide the serial clock of MPEG MUX */
2228 /* in SERIAL MODE in case input mode MPEG is used */
2229 reg_1287 = dib7000p_read_word(state, 1287);
2230 /* enSerialClkDiv2 == 1 ? */
2231 if ((reg_1287 & 0x1) == 1) {
2232 /* force enSerialClkDiv2 = 0 */
2233 reg_1287 &= ~0x1;
2234 dib7000p_write_word(state, 1287, reg_1287);
2235 }
2236 state->input_mode_mpeg = 1;
2237 break;
2238 case 1: /* both ways */
2239 case 2: /* only the diversity input */
2240 dprintk("%s ON : Enable diversity INPUT", __func__);
2241 dib7090_cfg_DibRx(state, 5, 5, 0, 0, 0, 0, 0);
2242 state->input_mode_mpeg = 0;
2243 break;
Olivier Grenie713d54a2011-01-04 04:54:31 -03002244 }
2245
Olivier Grenie2e802862011-08-05 10:39:15 -03002246 dib7000p_set_diversity_in(&state->demod, onoff);
Olivier Grenie713d54a2011-01-04 04:54:31 -03002247 return 0;
2248}
2249
2250static int dib7090_set_output_mode(struct dvb_frontend *fe, int mode)
2251{
2252 struct dib7000p_state *state = fe->demodulator_priv;
2253
2254 u16 outreg, smo_mode, fifo_threshold;
2255 u8 prefer_mpeg_mux_use = 1;
2256 int ret = 0;
2257
2258 dib7090_host_bus_drive(state, 1);
2259
2260 fifo_threshold = 1792;
2261 smo_mode = (dib7000p_read_word(state, 235) & 0x0050) | (1 << 1);
2262 outreg = dib7000p_read_word(state, 1286) & ~((1 << 10) | (0x7 << 6) | (1 << 1));
2263
2264 switch (mode) {
2265 case OUTMODE_HIGH_Z:
2266 outreg = 0;
2267 break;
2268
2269 case OUTMODE_MPEG2_SERIAL:
2270 if (prefer_mpeg_mux_use) {
Olivier Grenie2e802862011-08-05 10:39:15 -03002271 dprintk("setting output mode TS_SERIAL using Mpeg Mux");
2272 dib7090_configMpegMux(state, 3, 1, 1);
2273 dib7090_setHostBusMux(state, MPEG_ON_HOSTBUS);
2274 } else {/* Use Smooth block */
2275 dprintk("setting output mode TS_SERIAL using Smooth bloc");
2276 dib7090_setHostBusMux(state, DEMOUT_ON_HOSTBUS);
2277 outreg |= (2<<6) | (0 << 1);
Olivier Grenie713d54a2011-01-04 04:54:31 -03002278 }
2279 break;
2280
2281 case OUTMODE_MPEG2_PAR_GATED_CLK:
2282 if (prefer_mpeg_mux_use) {
Olivier Grenie2e802862011-08-05 10:39:15 -03002283 dprintk("setting output mode TS_PARALLEL_GATED using Mpeg Mux");
2284 dib7090_configMpegMux(state, 2, 0, 0);
2285 dib7090_setHostBusMux(state, MPEG_ON_HOSTBUS);
2286 } else { /* Use Smooth block */
2287 dprintk("setting output mode TS_PARALLEL_GATED using Smooth block");
2288 dib7090_setHostBusMux(state, DEMOUT_ON_HOSTBUS);
2289 outreg |= (0<<6);
Olivier Grenie713d54a2011-01-04 04:54:31 -03002290 }
2291 break;
2292
2293 case OUTMODE_MPEG2_PAR_CONT_CLK: /* Using Smooth block only */
Olivier Grenie2e802862011-08-05 10:39:15 -03002294 dprintk("setting output mode TS_PARALLEL_CONT using Smooth block");
2295 dib7090_setHostBusMux(state, DEMOUT_ON_HOSTBUS);
2296 outreg |= (1<<6);
Olivier Grenie713d54a2011-01-04 04:54:31 -03002297 break;
2298
2299 case OUTMODE_MPEG2_FIFO: /* Using Smooth block because not supported by new Mpeg Mux bloc */
Olivier Grenie2e802862011-08-05 10:39:15 -03002300 dprintk("setting output mode TS_FIFO using Smooth block");
2301 dib7090_setHostBusMux(state, DEMOUT_ON_HOSTBUS);
2302 outreg |= (5<<6);
Olivier Grenie713d54a2011-01-04 04:54:31 -03002303 smo_mode |= (3 << 1);
2304 fifo_threshold = 512;
2305 break;
2306
2307 case OUTMODE_DIVERSITY:
Olivier Grenie2e802862011-08-05 10:39:15 -03002308 dprintk("setting output mode MODE_DIVERSITY");
2309 dib7090_setDibTxMux(state, DIV_ON_DIBTX);
2310 dib7090_setHostBusMux(state, DIBTX_ON_HOSTBUS);
Olivier Grenie713d54a2011-01-04 04:54:31 -03002311 break;
2312
2313 case OUTMODE_ANALOG_ADC:
Olivier Grenie2e802862011-08-05 10:39:15 -03002314 dprintk("setting output mode MODE_ANALOG_ADC");
2315 dib7090_setDibTxMux(state, ADC_ON_DIBTX);
2316 dib7090_setHostBusMux(state, DIBTX_ON_HOSTBUS);
Olivier Grenie713d54a2011-01-04 04:54:31 -03002317 break;
2318 }
Olivier Grenie2e802862011-08-05 10:39:15 -03002319 if (mode != OUTMODE_HIGH_Z)
2320 outreg |= (1 << 10);
Olivier Grenie713d54a2011-01-04 04:54:31 -03002321
2322 if (state->cfg.output_mpeg2_in_188_bytes)
2323 smo_mode |= (1 << 5);
2324
2325 ret |= dib7000p_write_word(state, 235, smo_mode);
2326 ret |= dib7000p_write_word(state, 236, fifo_threshold); /* synchronous fread */
Olivier Grenie2e802862011-08-05 10:39:15 -03002327 ret |= dib7000p_write_word(state, 1286, outreg);
Olivier Grenie713d54a2011-01-04 04:54:31 -03002328
2329 return ret;
2330}
2331
2332int dib7090_tuner_sleep(struct dvb_frontend *fe, int onoff)
2333{
2334 struct dib7000p_state *state = fe->demodulator_priv;
2335 u16 en_cur_state;
2336
2337 dprintk("sleep dib7090: %d", onoff);
2338
2339 en_cur_state = dib7000p_read_word(state, 1922);
2340
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002341 if (en_cur_state > 0xff)
Olivier Grenie713d54a2011-01-04 04:54:31 -03002342 state->tuner_enable = en_cur_state;
Olivier Grenie713d54a2011-01-04 04:54:31 -03002343
2344 if (onoff)
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002345 en_cur_state &= 0x00ff;
Olivier Grenie713d54a2011-01-04 04:54:31 -03002346 else {
2347 if (state->tuner_enable != 0)
2348 en_cur_state = state->tuner_enable;
2349 }
2350
2351 dib7000p_write_word(state, 1922, en_cur_state);
2352
2353 return 0;
2354}
2355EXPORT_SYMBOL(dib7090_tuner_sleep);
2356
Olivier Grenie713d54a2011-01-04 04:54:31 -03002357int dib7090_get_adc_power(struct dvb_frontend *fe)
2358{
2359 return dib7000p_get_adc_power(fe);
2360}
2361EXPORT_SYMBOL(dib7090_get_adc_power);
2362
2363int dib7090_slave_reset(struct dvb_frontend *fe)
2364{
2365 struct dib7000p_state *state = fe->demodulator_priv;
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002366 u16 reg;
Olivier Grenie713d54a2011-01-04 04:54:31 -03002367
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002368 reg = dib7000p_read_word(state, 1794);
2369 dib7000p_write_word(state, 1794, reg | (4 << 12));
Olivier Grenie713d54a2011-01-04 04:54:31 -03002370
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002371 dib7000p_write_word(state, 1032, 0xffff);
2372 return 0;
Olivier Grenie713d54a2011-01-04 04:54:31 -03002373}
2374EXPORT_SYMBOL(dib7090_slave_reset);
2375
Patrick Boettchera75763f2006-10-18 08:34:16 -03002376static struct dvb_frontend_ops dib7000p_ops;
Olivier Grenie713d54a2011-01-04 04:54:31 -03002377struct dvb_frontend *dib7000p_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr, struct dib7000p_config *cfg)
Patrick Boettchera75763f2006-10-18 08:34:16 -03002378{
2379 struct dvb_frontend *demod;
2380 struct dib7000p_state *st;
2381 st = kzalloc(sizeof(struct dib7000p_state), GFP_KERNEL);
2382 if (st == NULL)
2383 return NULL;
2384
2385 memcpy(&st->cfg, cfg, sizeof(struct dib7000p_config));
2386 st->i2c_adap = i2c_adap;
2387 st->i2c_addr = i2c_addr;
2388 st->gpio_val = cfg->gpio_val;
2389 st->gpio_dir = cfg->gpio_dir;
2390
Steven Totha38d6e32008-04-22 15:37:01 -03002391 /* Ensure the output mode remains at the previous default if it's
2392 * not specifically set by the caller.
2393 */
Olivier Grenie713d54a2011-01-04 04:54:31 -03002394 if ((st->cfg.output_mode != OUTMODE_MPEG2_SERIAL) && (st->cfg.output_mode != OUTMODE_MPEG2_PAR_GATED_CLK))
Steven Totha38d6e32008-04-22 15:37:01 -03002395 st->cfg.output_mode = OUTMODE_MPEG2_FIFO;
2396
Olivier Grenie713d54a2011-01-04 04:54:31 -03002397 demod = &st->demod;
Patrick Boettchera75763f2006-10-18 08:34:16 -03002398 demod->demodulator_priv = st;
2399 memcpy(&st->demod.ops, &dib7000p_ops, sizeof(struct dvb_frontend_ops));
Patrick Boettcher79fcce32011-08-03 12:08:21 -03002400 mutex_init(&st->i2c_buffer_lock);
Patrick Boettchera75763f2006-10-18 08:34:16 -03002401
Olivier Grenie713d54a2011-01-04 04:54:31 -03002402 dib7000p_write_word(st, 1287, 0x0003); /* sram lead in, rdy */
Olivier Grenieeac1fe12009-09-23 13:41:27 -03002403
Patrick Boettchera75763f2006-10-18 08:34:16 -03002404 if (dib7000p_identify(st) != 0)
2405 goto error;
2406
Olivier Grenie713d54a2011-01-04 04:54:31 -03002407 st->version = dib7000p_read_word(st, 897);
2408
Martin Samek7646b9d2009-09-30 22:59:09 -03002409 /* FIXME: make sure the dev.parent field is initialized, or else
Patrick Boettcher79fcce32011-08-03 12:08:21 -03002410 request_firmware() will hit an OOPS (this should be moved somewhere
2411 more common) */
2412 st->i2c_master.gated_tuner_i2c_adap.dev.parent = i2c_adap->dev.parent;
Martin Samek7646b9d2009-09-30 22:59:09 -03002413
Patrick Boettchera75763f2006-10-18 08:34:16 -03002414 dibx000_init_i2c_master(&st->i2c_master, DIB7000P, st->i2c_adap, st->i2c_addr);
2415
Olivier Grenie713d54a2011-01-04 04:54:31 -03002416 /* init 7090 tuner adapter */
2417 strncpy(st->dib7090_tuner_adap.name, "DiB7090 tuner interface", sizeof(st->dib7090_tuner_adap.name));
2418 st->dib7090_tuner_adap.algo = &dib7090_tuner_xfer_algo;
2419 st->dib7090_tuner_adap.algo_data = NULL;
2420 st->dib7090_tuner_adap.dev.parent = st->i2c_adap->dev.parent;
2421 i2c_set_adapdata(&st->dib7090_tuner_adap, st);
2422 i2c_add_adapter(&st->dib7090_tuner_adap);
2423
Patrick Boettchera75763f2006-10-18 08:34:16 -03002424 dib7000p_demod_reset(st);
2425
Olivier Grenie713d54a2011-01-04 04:54:31 -03002426 if (st->version == SOC7090) {
2427 dib7090_set_output_mode(demod, st->cfg.output_mode);
2428 dib7090_set_diversity_in(demod, 0);
2429 }
2430
Patrick Boettchera75763f2006-10-18 08:34:16 -03002431 return demod;
2432
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002433error:
Patrick Boettchera75763f2006-10-18 08:34:16 -03002434 kfree(st);
2435 return NULL;
2436}
2437EXPORT_SYMBOL(dib7000p_attach);
2438
2439static struct dvb_frontend_ops dib7000p_ops = {
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -03002440 .delsys = { SYS_DVBT },
Patrick Boettchera75763f2006-10-18 08:34:16 -03002441 .info = {
Olivier Grenie713d54a2011-01-04 04:54:31 -03002442 .name = "DiBcom 7000PC",
Olivier Grenie713d54a2011-01-04 04:54:31 -03002443 .frequency_min = 44250000,
2444 .frequency_max = 867250000,
2445 .frequency_stepsize = 62500,
2446 .caps = FE_CAN_INVERSION_AUTO |
2447 FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
2448 FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
2449 FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO |
2450 FE_CAN_TRANSMISSION_MODE_AUTO | FE_CAN_GUARD_INTERVAL_AUTO | FE_CAN_RECOVER | FE_CAN_HIERARCHY_AUTO,
2451 },
Patrick Boettchera75763f2006-10-18 08:34:16 -03002452
Olivier Grenie713d54a2011-01-04 04:54:31 -03002453 .release = dib7000p_release,
Patrick Boettchera75763f2006-10-18 08:34:16 -03002454
Olivier Grenie713d54a2011-01-04 04:54:31 -03002455 .init = dib7000p_wakeup,
2456 .sleep = dib7000p_sleep,
Patrick Boettchera75763f2006-10-18 08:34:16 -03002457
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -03002458 .set_frontend = dib7000p_set_frontend,
Olivier Grenie713d54a2011-01-04 04:54:31 -03002459 .get_tune_settings = dib7000p_fe_get_tune_settings,
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -03002460 .get_frontend = dib7000p_get_frontend,
Patrick Boettchera75763f2006-10-18 08:34:16 -03002461
Olivier Grenie713d54a2011-01-04 04:54:31 -03002462 .read_status = dib7000p_read_status,
2463 .read_ber = dib7000p_read_ber,
Patrick Boettchera75763f2006-10-18 08:34:16 -03002464 .read_signal_strength = dib7000p_read_signal_strength,
Olivier Grenie713d54a2011-01-04 04:54:31 -03002465 .read_snr = dib7000p_read_snr,
2466 .read_ucblocks = dib7000p_read_unc_blocks,
Patrick Boettchera75763f2006-10-18 08:34:16 -03002467};
2468
Olivier Grenie713d54a2011-01-04 04:54:31 -03002469MODULE_AUTHOR("Olivier Grenie <ogrenie@dibcom.fr>");
Patrick Boettchera75763f2006-10-18 08:34:16 -03002470MODULE_AUTHOR("Patrick Boettcher <pboettcher@dibcom.fr>");
2471MODULE_DESCRIPTION("Driver for the DiBcom 7000PC COFDM demodulator");
2472MODULE_LICENSE("GPL");