blob: 589134e951758c1ab984be32e1becf88d3631ea5 [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>
Mauro Carvalho Chehab041ad442014-05-29 14:44:56 -030014#include <asm/div64.h>
Patrick Boettchera75763f2006-10-18 08:34:16 -030015
Olivier Grenieef801962009-09-15 06:46:52 -030016#include "dvb_math.h"
Patrick Boettchera75763f2006-10-18 08:34:16 -030017#include "dvb_frontend.h"
18
19#include "dib7000p.h"
20
21static int debug;
22module_param(debug, int, 0644);
23MODULE_PARM_DESC(debug, "turn on debugging (default: 0)");
24
Matt Doran8f6956c2007-07-31 07:09:30 -030025static int buggy_sfn_workaround;
26module_param(buggy_sfn_workaround, int, 0644);
Patrick Boettcher8d999962007-07-31 10:36:06 -030027MODULE_PARM_DESC(buggy_sfn_workaround, "Enable work-around for buggy SFNs (default: 0)");
Matt Doran8f6956c2007-07-31 07:09:30 -030028
Patrick Boettcherb6884a12007-07-27 10:08:51 -030029#define dprintk(args...) do { if (debug) { printk(KERN_DEBUG "DiB7000P: "); printk(args); printk("\n"); } } while (0)
Patrick Boettchera75763f2006-10-18 08:34:16 -030030
Olivier Grenie713d54a2011-01-04 04:54:31 -030031struct i2c_device {
32 struct i2c_adapter *i2c_adap;
33 u8 i2c_addr;
34};
35
Patrick Boettchera75763f2006-10-18 08:34:16 -030036struct dib7000p_state {
37 struct dvb_frontend demod;
Olivier Grenie713d54a2011-01-04 04:54:31 -030038 struct dib7000p_config cfg;
Patrick Boettchera75763f2006-10-18 08:34:16 -030039
40 u8 i2c_addr;
Olivier Grenie713d54a2011-01-04 04:54:31 -030041 struct i2c_adapter *i2c_adap;
Patrick Boettchera75763f2006-10-18 08:34:16 -030042
43 struct dibx000_i2c_master i2c_master;
44
45 u16 wbd_ref;
46
Olivier Grenie713d54a2011-01-04 04:54:31 -030047 u8 current_band;
Patrick Boettcher904a82e2008-01-25 07:31:58 -030048 u32 current_bandwidth;
Patrick Boettchera75763f2006-10-18 08:34:16 -030049 struct dibx000_agc_config *current_agc;
50 u32 timf;
51
Olivier Grenie713d54a2011-01-04 04:54:31 -030052 u8 div_force_off:1;
53 u8 div_state:1;
Patrick Boettcher01373a52007-07-30 12:49:04 -030054 u16 div_sync_wait;
Patrick Boettcherb6884a12007-07-27 10:08:51 -030055
56 u8 agc_state;
57
Patrick Boettchera75763f2006-10-18 08:34:16 -030058 u16 gpio_dir;
59 u16 gpio_val;
Matt Doran8f6956c2007-07-31 07:09:30 -030060
Olivier Grenie713d54a2011-01-04 04:54:31 -030061 u8 sfn_workaround_active:1;
62
63#define SOC7090 0x7090
64 u16 version;
65
66 u16 tuner_enable;
67 struct i2c_adapter dib7090_tuner_adap;
Olivier Grenie5a0deee2011-05-03 12:27:33 -030068
69 /* for the I2C transfer */
70 struct i2c_msg msg[2];
71 u8 i2c_write_buffer[4];
72 u8 i2c_read_buffer[2];
Patrick Boettcher79fcce32011-08-03 12:08:21 -030073 struct mutex i2c_buffer_lock;
Olivier Grenie2e802862011-08-05 10:39:15 -030074
75 u8 input_mode_mpeg;
Mauro Carvalho Chehab041ad442014-05-29 14:44:56 -030076
77 /* for DVBv5 stats */
78 s64 old_ucb;
79 unsigned long per_jiffies_stats;
80 unsigned long ber_jiffies_stats;
81 unsigned long get_stats_time;
Patrick Boettchera75763f2006-10-18 08:34:16 -030082};
83
84enum dib7000p_power_mode {
85 DIB7000P_POWER_ALL = 0,
Patrick Boettcherb6884a12007-07-27 10:08:51 -030086 DIB7000P_POWER_ANALOG_ADC,
Patrick Boettchera75763f2006-10-18 08:34:16 -030087 DIB7000P_POWER_INTERFACE_ONLY,
88};
89
Olivier Grenie2e802862011-08-05 10:39:15 -030090/* dib7090 specific fonctions */
Olivier Grenie713d54a2011-01-04 04:54:31 -030091static int dib7090_set_output_mode(struct dvb_frontend *fe, int mode);
92static int dib7090_set_diversity_in(struct dvb_frontend *fe, int onoff);
Olivier Grenie2e802862011-08-05 10:39:15 -030093static void dib7090_setDibTxMux(struct dib7000p_state *state, int mode);
94static void dib7090_setHostBusMux(struct dib7000p_state *state, int mode);
Olivier Grenie713d54a2011-01-04 04:54:31 -030095
Patrick Boettchera75763f2006-10-18 08:34:16 -030096static u16 dib7000p_read_word(struct dib7000p_state *state, u16 reg)
97{
Patrick Boettcher79fcce32011-08-03 12:08:21 -030098 u16 ret;
99
100 if (mutex_lock_interruptible(&state->i2c_buffer_lock) < 0) {
101 dprintk("could not acquire lock");
102 return 0;
103 }
104
Olivier Grenie5a0deee2011-05-03 12:27:33 -0300105 state->i2c_write_buffer[0] = reg >> 8;
106 state->i2c_write_buffer[1] = reg & 0xff;
Patrick Boettchera75763f2006-10-18 08:34:16 -0300107
Olivier Grenie5a0deee2011-05-03 12:27:33 -0300108 memset(state->msg, 0, 2 * sizeof(struct i2c_msg));
109 state->msg[0].addr = state->i2c_addr >> 1;
110 state->msg[0].flags = 0;
111 state->msg[0].buf = state->i2c_write_buffer;
112 state->msg[0].len = 2;
113 state->msg[1].addr = state->i2c_addr >> 1;
114 state->msg[1].flags = I2C_M_RD;
115 state->msg[1].buf = state->i2c_read_buffer;
116 state->msg[1].len = 2;
117
118 if (i2c_transfer(state->i2c_adap, state->msg, 2) != 2)
Olivier Grenie713d54a2011-01-04 04:54:31 -0300119 dprintk("i2c read error on %d", reg);
Patrick Boettchera75763f2006-10-18 08:34:16 -0300120
Patrick Boettcher79fcce32011-08-03 12:08:21 -0300121 ret = (state->i2c_read_buffer[0] << 8) | state->i2c_read_buffer[1];
122 mutex_unlock(&state->i2c_buffer_lock);
123 return ret;
Patrick Boettchera75763f2006-10-18 08:34:16 -0300124}
125
126static int dib7000p_write_word(struct dib7000p_state *state, u16 reg, u16 val)
127{
Patrick Boettcher79fcce32011-08-03 12:08:21 -0300128 int ret;
129
130 if (mutex_lock_interruptible(&state->i2c_buffer_lock) < 0) {
131 dprintk("could not acquire lock");
132 return -EINVAL;
133 }
134
Olivier Grenie5a0deee2011-05-03 12:27:33 -0300135 state->i2c_write_buffer[0] = (reg >> 8) & 0xff;
136 state->i2c_write_buffer[1] = reg & 0xff;
137 state->i2c_write_buffer[2] = (val >> 8) & 0xff;
138 state->i2c_write_buffer[3] = val & 0xff;
139
140 memset(&state->msg[0], 0, sizeof(struct i2c_msg));
141 state->msg[0].addr = state->i2c_addr >> 1;
142 state->msg[0].flags = 0;
143 state->msg[0].buf = state->i2c_write_buffer;
144 state->msg[0].len = 4;
145
Patrick Boettcher79fcce32011-08-03 12:08:21 -0300146 ret = (i2c_transfer(state->i2c_adap, state->msg, 1) != 1 ?
147 -EREMOTEIO : 0);
148 mutex_unlock(&state->i2c_buffer_lock);
149 return ret;
Patrick Boettchera75763f2006-10-18 08:34:16 -0300150}
Olivier Grenie713d54a2011-01-04 04:54:31 -0300151
152static void dib7000p_write_tab(struct dib7000p_state *state, u16 * buf)
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300153{
154 u16 l = 0, r, *n;
155 n = buf;
156 l = *n++;
157 while (l) {
158 r = *n++;
159
160 do {
161 dib7000p_write_word(state, r, *n++);
162 r++;
163 } while (--l);
164 l = *n++;
165 }
166}
167
Patrick Boettchera75763f2006-10-18 08:34:16 -0300168static int dib7000p_set_output_mode(struct dib7000p_state *state, int mode)
169{
Olivier Grenie713d54a2011-01-04 04:54:31 -0300170 int ret = 0;
Patrick Boettchera75763f2006-10-18 08:34:16 -0300171 u16 outreg, fifo_threshold, smo_mode;
172
173 outreg = 0;
174 fifo_threshold = 1792;
Olivier Grenieeac1fe12009-09-23 13:41:27 -0300175 smo_mode = (dib7000p_read_word(state, 235) & 0x0050) | (1 << 1);
Patrick Boettchera75763f2006-10-18 08:34:16 -0300176
Olivier Grenie713d54a2011-01-04 04:54:31 -0300177 dprintk("setting output mode for demod %p to %d", &state->demod, mode);
Patrick Boettchera75763f2006-10-18 08:34:16 -0300178
179 switch (mode) {
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300180 case OUTMODE_MPEG2_PAR_GATED_CLK:
Olivier Grenie713d54a2011-01-04 04:54:31 -0300181 outreg = (1 << 10); /* 0x0400 */
182 break;
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300183 case OUTMODE_MPEG2_PAR_CONT_CLK:
Olivier Grenie713d54a2011-01-04 04:54:31 -0300184 outreg = (1 << 10) | (1 << 6); /* 0x0440 */
185 break;
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300186 case OUTMODE_MPEG2_SERIAL:
Olivier Grenie713d54a2011-01-04 04:54:31 -0300187 outreg = (1 << 10) | (2 << 6) | (0 << 1); /* 0x0480 */
188 break;
189 case OUTMODE_DIVERSITY:
190 if (state->cfg.hostbus_diversity)
191 outreg = (1 << 10) | (4 << 6); /* 0x0500 */
192 else
193 outreg = (1 << 11);
194 break;
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300195 case OUTMODE_MPEG2_FIFO:
Olivier Grenie713d54a2011-01-04 04:54:31 -0300196 smo_mode |= (3 << 1);
197 fifo_threshold = 512;
198 outreg = (1 << 10) | (5 << 6);
199 break;
200 case OUTMODE_ANALOG_ADC:
201 outreg = (1 << 10) | (3 << 6);
202 break;
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300203 case OUTMODE_HIGH_Z:
Olivier Grenie713d54a2011-01-04 04:54:31 -0300204 outreg = 0;
205 break;
206 default:
207 dprintk("Unhandled output_mode passed to be set for demod %p", &state->demod);
208 break;
Patrick Boettchera75763f2006-10-18 08:34:16 -0300209 }
210
211 if (state->cfg.output_mpeg2_in_188_bytes)
Olivier Grenie713d54a2011-01-04 04:54:31 -0300212 smo_mode |= (1 << 5);
Patrick Boettchera75763f2006-10-18 08:34:16 -0300213
Olivier Grenie713d54a2011-01-04 04:54:31 -0300214 ret |= dib7000p_write_word(state, 235, smo_mode);
215 ret |= dib7000p_write_word(state, 236, fifo_threshold); /* synchronous fread */
216 if (state->version != SOC7090)
217 ret |= dib7000p_write_word(state, 1286, outreg); /* P_Div_active */
Patrick Boettchera75763f2006-10-18 08:34:16 -0300218
219 return ret;
220}
221
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300222static int dib7000p_set_diversity_in(struct dvb_frontend *demod, int onoff)
223{
224 struct dib7000p_state *state = demod->demodulator_priv;
225
226 if (state->div_force_off) {
Olivier Grenie713d54a2011-01-04 04:54:31 -0300227 dprintk("diversity combination deactivated - forced by COFDM parameters");
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300228 onoff = 0;
Olivier Grenieeac1fe12009-09-23 13:41:27 -0300229 dib7000p_write_word(state, 207, 0);
230 } else
231 dib7000p_write_word(state, 207, (state->div_sync_wait << 4) | (1 << 2) | (2 << 0));
232
Olivier Grenie713d54a2011-01-04 04:54:31 -0300233 state->div_state = (u8) onoff;
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300234
235 if (onoff) {
236 dib7000p_write_word(state, 204, 6);
237 dib7000p_write_word(state, 205, 16);
238 /* P_dvsy_sync_mode = 0, P_dvsy_sync_enable=1, P_dvcb_comb_mode=2 */
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300239 } else {
240 dib7000p_write_word(state, 204, 1);
241 dib7000p_write_word(state, 205, 0);
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300242 }
243
244 return 0;
245}
246
Patrick Boettchera75763f2006-10-18 08:34:16 -0300247static int dib7000p_set_power_mode(struct dib7000p_state *state, enum dib7000p_power_mode mode)
248{
249 /* by default everything is powered off */
Olivier Grenie713d54a2011-01-04 04:54:31 -0300250 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 -0300251
252 /* now, depending on the requested mode, we power on */
253 switch (mode) {
254 /* power up everything in the demod */
Olivier Grenie713d54a2011-01-04 04:54:31 -0300255 case DIB7000P_POWER_ALL:
256 reg_774 = 0x0000;
257 reg_775 = 0x0000;
258 reg_776 = 0x0;
259 reg_899 = 0x0;
260 if (state->version == SOC7090)
261 reg_1280 &= 0x001f;
262 else
263 reg_1280 &= 0x01ff;
264 break;
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300265
Olivier Grenie713d54a2011-01-04 04:54:31 -0300266 case DIB7000P_POWER_ANALOG_ADC:
267 /* dem, cfg, iqc, sad, agc */
268 reg_774 &= ~((1 << 15) | (1 << 14) | (1 << 11) | (1 << 10) | (1 << 9));
269 /* nud */
270 reg_776 &= ~((1 << 0));
271 /* Dout */
272 if (state->version != SOC7090)
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300273 reg_1280 &= ~((1 << 11));
Olivier Grenie713d54a2011-01-04 04:54:31 -0300274 reg_1280 &= ~(1 << 6);
275 /* fall through wanted to enable the interfaces */
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300276
Patrick Boettchera75763f2006-10-18 08:34:16 -0300277 /* just leave power on the control-interfaces: GPIO and (I2C or SDIO) */
Olivier Grenie713d54a2011-01-04 04:54:31 -0300278 case DIB7000P_POWER_INTERFACE_ONLY: /* TODO power up either SDIO or I2C */
279 if (state->version == SOC7090)
280 reg_1280 &= ~((1 << 7) | (1 << 5));
281 else
Patrick Boettchera75763f2006-10-18 08:34:16 -0300282 reg_1280 &= ~((1 << 14) | (1 << 13) | (1 << 12) | (1 << 10));
Olivier Grenie713d54a2011-01-04 04:54:31 -0300283 break;
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300284
Patrick Boettchera75763f2006-10-18 08:34:16 -0300285/* TODO following stuff is just converted from the dib7000-driver - check when is used what */
286 }
287
Olivier Grenie713d54a2011-01-04 04:54:31 -0300288 dib7000p_write_word(state, 774, reg_774);
289 dib7000p_write_word(state, 775, reg_775);
290 dib7000p_write_word(state, 776, reg_776);
Patrick Boettchera75763f2006-10-18 08:34:16 -0300291 dib7000p_write_word(state, 1280, reg_1280);
Olivier Grenie2e802862011-08-05 10:39:15 -0300292 if (state->version != SOC7090)
293 dib7000p_write_word(state, 899, reg_899);
Patrick Boettchera75763f2006-10-18 08:34:16 -0300294
295 return 0;
296}
297
298static void dib7000p_set_adc_state(struct dib7000p_state *state, enum dibx000_adc_states no)
299{
Olivier Grenie2e802862011-08-05 10:39:15 -0300300 u16 reg_908 = 0, reg_909 = 0;
Olivier Grenie713d54a2011-01-04 04:54:31 -0300301 u16 reg;
Patrick Boettchera75763f2006-10-18 08:34:16 -0300302
Olivier Grenie2e802862011-08-05 10:39:15 -0300303 if (state->version != SOC7090) {
304 reg_908 = dib7000p_read_word(state, 908);
305 reg_909 = dib7000p_read_word(state, 909);
306 }
307
Patrick Boettchera75763f2006-10-18 08:34:16 -0300308 switch (no) {
Olivier Grenie713d54a2011-01-04 04:54:31 -0300309 case DIBX000_SLOW_ADC_ON:
310 if (state->version == SOC7090) {
311 reg = dib7000p_read_word(state, 1925);
312
313 dib7000p_write_word(state, 1925, reg | (1 << 4) | (1 << 2)); /* en_slowAdc = 1 & reset_sladc = 1 */
314
315 reg = dib7000p_read_word(state, 1925); /* read acces to make it works... strange ... */
316 msleep(200);
317 dib7000p_write_word(state, 1925, reg & ~(1 << 4)); /* en_slowAdc = 1 & reset_sladc = 0 */
318
319 reg = dib7000p_read_word(state, 72) & ~((0x3 << 14) | (0x3 << 12));
320 dib7000p_write_word(state, 72, reg | (1 << 14) | (3 << 12) | 524); /* ref = Vin1 => Vbg ; sel = Vin0 or Vin3 ; (Vin2 = Vcm) */
321 } else {
Patrick Boettchera75763f2006-10-18 08:34:16 -0300322 reg_909 |= (1 << 1) | (1 << 0);
323 dib7000p_write_word(state, 909, reg_909);
324 reg_909 &= ~(1 << 1);
Olivier Grenie713d54a2011-01-04 04:54:31 -0300325 }
326 break;
Patrick Boettchera75763f2006-10-18 08:34:16 -0300327
Olivier Grenie713d54a2011-01-04 04:54:31 -0300328 case DIBX000_SLOW_ADC_OFF:
329 if (state->version == SOC7090) {
330 reg = dib7000p_read_word(state, 1925);
331 dib7000p_write_word(state, 1925, (reg & ~(1 << 2)) | (1 << 4)); /* reset_sladc = 1 en_slowAdc = 0 */
332 } else
333 reg_909 |= (1 << 1) | (1 << 0);
334 break;
Patrick Boettchera75763f2006-10-18 08:34:16 -0300335
Olivier Grenie713d54a2011-01-04 04:54:31 -0300336 case DIBX000_ADC_ON:
337 reg_908 &= 0x0fff;
338 reg_909 &= 0x0003;
339 break;
Patrick Boettchera75763f2006-10-18 08:34:16 -0300340
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300341 case DIBX000_ADC_OFF:
Olivier Grenie713d54a2011-01-04 04:54:31 -0300342 reg_908 |= (1 << 14) | (1 << 13) | (1 << 12);
343 reg_909 |= (1 << 5) | (1 << 4) | (1 << 3) | (1 << 2);
344 break;
Patrick Boettchera75763f2006-10-18 08:34:16 -0300345
Olivier Grenie713d54a2011-01-04 04:54:31 -0300346 case DIBX000_VBG_ENABLE:
347 reg_908 &= ~(1 << 15);
348 break;
Patrick Boettchera75763f2006-10-18 08:34:16 -0300349
Olivier Grenie713d54a2011-01-04 04:54:31 -0300350 case DIBX000_VBG_DISABLE:
351 reg_908 |= (1 << 15);
352 break;
Patrick Boettchera75763f2006-10-18 08:34:16 -0300353
Olivier Grenie713d54a2011-01-04 04:54:31 -0300354 default:
355 break;
Patrick Boettchera75763f2006-10-18 08:34:16 -0300356 }
357
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300358// dprintk( "908: %x, 909: %x\n", reg_908, reg_909);
Patrick Boettchera75763f2006-10-18 08:34:16 -0300359
Olivier Grenie970d14c2010-09-07 12:50:46 -0300360 reg_909 |= (state->cfg.disable_sample_and_hold & 1) << 4;
Olivier Grenie90e12ce2010-09-07 12:50:45 -0300361 reg_908 |= (state->cfg.enable_current_mirror & 1) << 7;
362
Olivier Grenie2e802862011-08-05 10:39:15 -0300363 if (state->version != SOC7090) {
364 dib7000p_write_word(state, 908, reg_908);
365 dib7000p_write_word(state, 909, reg_909);
366 }
Patrick Boettchera75763f2006-10-18 08:34:16 -0300367}
368
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300369static int dib7000p_set_bandwidth(struct dib7000p_state *state, u32 bw)
Patrick Boettchera75763f2006-10-18 08:34:16 -0300370{
Patrick Boettchera75763f2006-10-18 08:34:16 -0300371 u32 timf;
372
373 // store the current bandwidth for later use
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300374 state->current_bandwidth = bw;
Patrick Boettchera75763f2006-10-18 08:34:16 -0300375
376 if (state->timf == 0) {
Olivier Grenie713d54a2011-01-04 04:54:31 -0300377 dprintk("using default timf");
Patrick Boettchera75763f2006-10-18 08:34:16 -0300378 timf = state->cfg.bw->timf;
379 } else {
Olivier Grenie713d54a2011-01-04 04:54:31 -0300380 dprintk("using updated timf");
Patrick Boettchera75763f2006-10-18 08:34:16 -0300381 timf = state->timf;
382 }
383
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300384 timf = timf * (bw / 50) / 160;
Patrick Boettchera75763f2006-10-18 08:34:16 -0300385
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300386 dib7000p_write_word(state, 23, (u16) ((timf >> 16) & 0xffff));
Olivier Grenie713d54a2011-01-04 04:54:31 -0300387 dib7000p_write_word(state, 24, (u16) ((timf) & 0xffff));
Patrick Boettchera75763f2006-10-18 08:34:16 -0300388
389 return 0;
390}
391
392static int dib7000p_sad_calib(struct dib7000p_state *state)
393{
394/* internal */
Patrick Boettchera75763f2006-10-18 08:34:16 -0300395 dib7000p_write_word(state, 73, (0 << 1) | (0 << 0));
Olivier Grenie713d54a2011-01-04 04:54:31 -0300396
397 if (state->version == SOC7090)
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300398 dib7000p_write_word(state, 74, 2048);
Olivier Grenie713d54a2011-01-04 04:54:31 -0300399 else
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300400 dib7000p_write_word(state, 74, 776);
Patrick Boettchera75763f2006-10-18 08:34:16 -0300401
402 /* do the calibration */
403 dib7000p_write_word(state, 73, (1 << 0));
404 dib7000p_write_word(state, 73, (0 << 0));
405
406 msleep(1);
407
408 return 0;
409}
410
Mauro Carvalho Chehab8abe4a02014-05-29 09:20:15 -0300411static int dib7000p_set_wbd_ref(struct dvb_frontend *demod, u16 value)
Patrick Boettcher01373a52007-07-30 12:49:04 -0300412{
413 struct dib7000p_state *state = demod->demodulator_priv;
414 if (value > 4095)
415 value = 4095;
416 state->wbd_ref = value;
417 return dib7000p_write_word(state, 105, (dib7000p_read_word(state, 105) & 0xf000) | value);
418}
Olivier Grenie713d54a2011-01-04 04:54:31 -0300419
Mauro Carvalho Chehab8abe4a02014-05-29 09:20:15 -0300420static int dib7000p_get_agc_values(struct dvb_frontend *fe,
Olivier Grenie6724a2f2011-08-05 13:49:33 -0300421 u16 *agc_global, u16 *agc1, u16 *agc2, u16 *wbd)
422{
423 struct dib7000p_state *state = fe->demodulator_priv;
424
425 if (agc_global != NULL)
426 *agc_global = dib7000p_read_word(state, 394);
427 if (agc1 != NULL)
428 *agc1 = dib7000p_read_word(state, 392);
429 if (agc2 != NULL)
430 *agc2 = dib7000p_read_word(state, 393);
431 if (wbd != NULL)
432 *wbd = dib7000p_read_word(state, 397);
433
434 return 0;
435}
Olivier Grenie6724a2f2011-08-05 13:49:33 -0300436
Mauro Carvalho Chehab8abe4a02014-05-29 09:20:15 -0300437static int dib7000p_set_agc1_min(struct dvb_frontend *fe, u16 v)
Olivier Grenie6fe10992012-12-31 09:23:26 -0300438{
439 struct dib7000p_state *state = fe->demodulator_priv;
440 return dib7000p_write_word(state, 108, v);
441}
Olivier Grenie6fe10992012-12-31 09:23:26 -0300442
Patrick Boettchera75763f2006-10-18 08:34:16 -0300443static void dib7000p_reset_pll(struct dib7000p_state *state)
444{
445 struct dibx000_bandwidth_config *bw = &state->cfg.bw[0];
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300446 u16 clk_cfg0;
Patrick Boettchera75763f2006-10-18 08:34:16 -0300447
Olivier Grenie713d54a2011-01-04 04:54:31 -0300448 if (state->version == SOC7090) {
449 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 -0300450
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300451 while (((dib7000p_read_word(state, 1856) >> 15) & 0x1) != 1)
452 ;
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300453
Olivier Grenie713d54a2011-01-04 04:54:31 -0300454 dib7000p_write_word(state, 1857, dib7000p_read_word(state, 1857) | (!bw->pll_bypass << 15));
455 } else {
456 /* force PLL bypass */
457 clk_cfg0 = (1 << 15) | ((bw->pll_ratio & 0x3f) << 9) |
458 (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 -0300459
Olivier Grenie713d54a2011-01-04 04:54:31 -0300460 dib7000p_write_word(state, 900, clk_cfg0);
461
462 /* P_pll_cfg */
463 dib7000p_write_word(state, 903, (bw->pll_prediv << 5) | (((bw->pll_ratio >> 6) & 0x3) << 3) | (bw->pll_range << 1) | bw->pll_reset);
464 clk_cfg0 = (bw->pll_bypass << 15) | (clk_cfg0 & 0x7fff);
465 dib7000p_write_word(state, 900, clk_cfg0);
466 }
467
468 dib7000p_write_word(state, 18, (u16) (((bw->internal * 1000) >> 16) & 0xffff));
469 dib7000p_write_word(state, 19, (u16) ((bw->internal * 1000) & 0xffff));
470 dib7000p_write_word(state, 21, (u16) ((bw->ifreq >> 16) & 0xffff));
471 dib7000p_write_word(state, 22, (u16) ((bw->ifreq) & 0xffff));
Patrick Boettchera75763f2006-10-18 08:34:16 -0300472
473 dib7000p_write_word(state, 72, bw->sad_cfg);
474}
475
Olivier Grenie713d54a2011-01-04 04:54:31 -0300476static u32 dib7000p_get_internal_freq(struct dib7000p_state *state)
477{
478 u32 internal = (u32) dib7000p_read_word(state, 18) << 16;
479 internal |= (u32) dib7000p_read_word(state, 19);
480 internal /= 1000;
481
482 return internal;
483}
484
Mauro Carvalho Chehab8abe4a02014-05-29 09:20:15 -0300485static int dib7000p_update_pll(struct dvb_frontend *fe, struct dibx000_bandwidth_config *bw)
Olivier Grenie713d54a2011-01-04 04:54:31 -0300486{
487 struct dib7000p_state *state = fe->demodulator_priv;
488 u16 reg_1857, reg_1856 = dib7000p_read_word(state, 1856);
489 u8 loopdiv, prediv;
490 u32 internal, xtal;
491
492 /* get back old values */
493 prediv = reg_1856 & 0x3f;
494 loopdiv = (reg_1856 >> 6) & 0x3f;
495
496 if ((bw != NULL) && (bw->pll_prediv != prediv || bw->pll_ratio != loopdiv)) {
497 dprintk("Updating pll (prediv: old = %d new = %d ; loopdiv : old = %d new = %d)", prediv, bw->pll_prediv, loopdiv, bw->pll_ratio);
498 reg_1856 &= 0xf000;
499 reg_1857 = dib7000p_read_word(state, 1857);
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300500 dib7000p_write_word(state, 1857, reg_1857 & ~(1 << 15));
Olivier Grenie713d54a2011-01-04 04:54:31 -0300501
502 dib7000p_write_word(state, 1856, reg_1856 | ((bw->pll_ratio & 0x3f) << 6) | (bw->pll_prediv & 0x3f));
503
504 /* write new system clk into P_sec_len */
505 internal = dib7000p_get_internal_freq(state);
506 xtal = (internal / loopdiv) * prediv;
507 internal = 1000 * (xtal / bw->pll_prediv) * bw->pll_ratio; /* new internal */
508 dib7000p_write_word(state, 18, (u16) ((internal >> 16) & 0xffff));
509 dib7000p_write_word(state, 19, (u16) (internal & 0xffff));
510
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300511 dib7000p_write_word(state, 1857, reg_1857 | (1 << 15));
Olivier Grenie713d54a2011-01-04 04:54:31 -0300512
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300513 while (((dib7000p_read_word(state, 1856) >> 15) & 0x1) != 1)
Olivier Grenie713d54a2011-01-04 04:54:31 -0300514 dprintk("Waiting for PLL to lock");
Olivier Grenie713d54a2011-01-04 04:54:31 -0300515
516 return 0;
517 }
518 return -EIO;
519}
Olivier Grenie713d54a2011-01-04 04:54:31 -0300520
Patrick Boettchera75763f2006-10-18 08:34:16 -0300521static int dib7000p_reset_gpio(struct dib7000p_state *st)
522{
523 /* reset the GPIOs */
Olivier Grenie713d54a2011-01-04 04:54:31 -0300524 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 -0300525
526 dib7000p_write_word(st, 1029, st->gpio_dir);
527 dib7000p_write_word(st, 1030, st->gpio_val);
528
529 /* TODO 1031 is P_gpio_od */
530
531 dib7000p_write_word(st, 1032, st->cfg.gpio_pwm_pos);
532
533 dib7000p_write_word(st, 1037, st->cfg.pwm_freq_div);
534 return 0;
535}
536
Patrick Boettcher01373a52007-07-30 12:49:04 -0300537static int dib7000p_cfg_gpio(struct dib7000p_state *st, u8 num, u8 dir, u8 val)
538{
539 st->gpio_dir = dib7000p_read_word(st, 1029);
Olivier Grenie713d54a2011-01-04 04:54:31 -0300540 st->gpio_dir &= ~(1 << num); /* reset the direction bit */
541 st->gpio_dir |= (dir & 0x1) << num; /* set the new direction */
Patrick Boettcher01373a52007-07-30 12:49:04 -0300542 dib7000p_write_word(st, 1029, st->gpio_dir);
543
544 st->gpio_val = dib7000p_read_word(st, 1030);
Olivier Grenie713d54a2011-01-04 04:54:31 -0300545 st->gpio_val &= ~(1 << num); /* reset the direction bit */
546 st->gpio_val |= (val & 0x01) << num; /* set the new value */
Patrick Boettcher01373a52007-07-30 12:49:04 -0300547 dib7000p_write_word(st, 1030, st->gpio_val);
548
549 return 0;
550}
551
Mauro Carvalho Chehab8abe4a02014-05-29 09:20:15 -0300552static int dib7000p_set_gpio(struct dvb_frontend *demod, u8 num, u8 dir, u8 val)
Patrick Boettcher01373a52007-07-30 12:49:04 -0300553{
554 struct dib7000p_state *state = demod->demodulator_priv;
555 return dib7000p_cfg_gpio(state, num, dir, val);
556}
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300557
Olivier Grenie713d54a2011-01-04 04:54:31 -0300558static u16 dib7000p_defaults[] = {
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300559 // auto search configuration
560 3, 2,
Olivier Grenie713d54a2011-01-04 04:54:31 -0300561 0x0004,
Olivier Grenie2e802862011-08-05 10:39:15 -0300562 (1<<3)|(1<<11)|(1<<12)|(1<<13),
Olivier Grenie713d54a2011-01-04 04:54:31 -0300563 0x0814, /* Equal Lock */
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300564
565 12, 6,
Olivier Grenie713d54a2011-01-04 04:54:31 -0300566 0x001b,
567 0x7740,
568 0x005b,
569 0x8d80,
570 0x01c9,
571 0xc380,
572 0x0000,
573 0x0080,
574 0x0000,
575 0x0090,
576 0x0001,
577 0xd4c0,
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300578
579 1, 26,
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300580 0x6680,
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300581
582 /* set ADC level to -16 */
583 11, 79,
Olivier Grenie713d54a2011-01-04 04:54:31 -0300584 (1 << 13) - 825 - 117,
585 (1 << 13) - 837 - 117,
586 (1 << 13) - 811 - 117,
587 (1 << 13) - 766 - 117,
588 (1 << 13) - 737 - 117,
589 (1 << 13) - 693 - 117,
590 (1 << 13) - 648 - 117,
591 (1 << 13) - 619 - 117,
592 (1 << 13) - 575 - 117,
593 (1 << 13) - 531 - 117,
594 (1 << 13) - 501 - 117,
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300595
596 1, 142,
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300597 0x0410,
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300598
599 /* disable power smoothing */
600 8, 145,
Olivier Grenie713d54a2011-01-04 04:54:31 -0300601 0,
602 0,
603 0,
604 0,
605 0,
606 0,
607 0,
608 0,
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300609
610 1, 154,
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300611 1 << 13,
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300612
613 1, 168,
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300614 0x0ccd,
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300615
616 1, 183,
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300617 0x200f,
Olivier Grenie713d54a2011-01-04 04:54:31 -0300618
619 1, 212,
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300620 0x169,
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300621
622 5, 187,
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300623 0x023d,
624 0x00a4,
625 0x00a4,
626 0x7ff0,
627 0x3ccc,
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300628
629 1, 198,
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300630 0x800,
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300631
632 1, 222,
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300633 0x0010,
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300634
635 1, 235,
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300636 0x0062,
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300637
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300638 0,
639};
640
Mauro Carvalho Chehab041ad442014-05-29 14:44:56 -0300641static void dib7000p_reset_stats(struct dvb_frontend *fe);
642
Patrick Boettchera75763f2006-10-18 08:34:16 -0300643static int dib7000p_demod_reset(struct dib7000p_state *state)
644{
645 dib7000p_set_power_mode(state, DIB7000P_POWER_ALL);
646
Olivier Grenie713d54a2011-01-04 04:54:31 -0300647 if (state->version == SOC7090)
648 dibx000_reset_i2c_master(&state->i2c_master);
649
Patrick Boettchera75763f2006-10-18 08:34:16 -0300650 dib7000p_set_adc_state(state, DIBX000_VBG_ENABLE);
651
652 /* restart all parts */
Olivier Grenie713d54a2011-01-04 04:54:31 -0300653 dib7000p_write_word(state, 770, 0xffff);
654 dib7000p_write_word(state, 771, 0xffff);
655 dib7000p_write_word(state, 772, 0x001f);
Olivier Grenie713d54a2011-01-04 04:54:31 -0300656 dib7000p_write_word(state, 1280, 0x001f - ((1 << 4) | (1 << 3)));
Patrick Boettchera75763f2006-10-18 08:34:16 -0300657
Olivier Grenie713d54a2011-01-04 04:54:31 -0300658 dib7000p_write_word(state, 770, 0);
659 dib7000p_write_word(state, 771, 0);
660 dib7000p_write_word(state, 772, 0);
Patrick Boettchera75763f2006-10-18 08:34:16 -0300661 dib7000p_write_word(state, 1280, 0);
662
Olivier Grenie2e802862011-08-05 10:39:15 -0300663 if (state->version != SOC7090) {
664 dib7000p_write_word(state, 898, 0x0003);
665 dib7000p_write_word(state, 898, 0);
666 }
667
Patrick Boettchera75763f2006-10-18 08:34:16 -0300668 /* default */
669 dib7000p_reset_pll(state);
670
671 if (dib7000p_reset_gpio(state) != 0)
Olivier Grenie713d54a2011-01-04 04:54:31 -0300672 dprintk("GPIO reset was not successful.");
Patrick Boettchera75763f2006-10-18 08:34:16 -0300673
Olivier Grenie713d54a2011-01-04 04:54:31 -0300674 if (state->version == SOC7090) {
675 dib7000p_write_word(state, 899, 0);
676
677 /* impulse noise */
678 dib7000p_write_word(state, 42, (1<<5) | 3); /* P_iqc_thsat_ipc = 1 ; P_iqc_win2 = 3 */
679 dib7000p_write_word(state, 43, 0x2d4); /*-300 fag P_iqc_dect_min = -280 */
680 dib7000p_write_word(state, 44, 300); /* 300 fag P_iqc_dect_min = +280 */
Olivier Grenie2e802862011-08-05 10:39:15 -0300681 dib7000p_write_word(state, 273, (0<<6) | 30);
Olivier Grenie713d54a2011-01-04 04:54:31 -0300682 }
Patrick Boettchera75763f2006-10-18 08:34:16 -0300683 if (dib7000p_set_output_mode(state, OUTMODE_HIGH_Z) != 0)
Olivier Grenie713d54a2011-01-04 04:54:31 -0300684 dprintk("OUTPUT_MODE could not be reset.");
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300685
686 dib7000p_set_adc_state(state, DIBX000_SLOW_ADC_ON);
687 dib7000p_sad_calib(state);
688 dib7000p_set_adc_state(state, DIBX000_SLOW_ADC_OFF);
689
Olivier Grenie713d54a2011-01-04 04:54:31 -0300690 /* unforce divstr regardless whether i2c enumeration was done or not */
691 dib7000p_write_word(state, 1285, dib7000p_read_word(state, 1285) & ~(1 << 1));
692
693 dib7000p_set_bandwidth(state, 8000);
694
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300695 if (state->version == SOC7090) {
Olivier Grenie2e802862011-08-05 10:39:15 -0300696 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 -0300697 } else {
Olivier Grenie713d54a2011-01-04 04:54:31 -0300698 if (state->cfg.tuner_is_baseband)
699 dib7000p_write_word(state, 36, 0x0755);
700 else
701 dib7000p_write_word(state, 36, 0x1f55);
702 }
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300703
704 dib7000p_write_tab(state, dib7000p_defaults);
Olivier Grenie2e802862011-08-05 10:39:15 -0300705 if (state->version != SOC7090) {
706 dib7000p_write_word(state, 901, 0x0006);
707 dib7000p_write_word(state, 902, (3 << 10) | (1 << 6));
708 dib7000p_write_word(state, 905, 0x2c8e);
709 }
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300710
Patrick Boettchera75763f2006-10-18 08:34:16 -0300711 dib7000p_set_power_mode(state, DIB7000P_POWER_INTERFACE_ONLY);
712
713 return 0;
714}
715
Patrick Boettchera75763f2006-10-18 08:34:16 -0300716static void dib7000p_pll_clk_cfg(struct dib7000p_state *state)
717{
718 u16 tmp = 0;
719 tmp = dib7000p_read_word(state, 903);
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300720 dib7000p_write_word(state, 903, (tmp | 0x1));
Patrick Boettchera75763f2006-10-18 08:34:16 -0300721 tmp = dib7000p_read_word(state, 900);
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300722 dib7000p_write_word(state, 900, (tmp & 0x7fff) | (1 << 6));
Patrick Boettchera75763f2006-10-18 08:34:16 -0300723}
724
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300725static void dib7000p_restart_agc(struct dib7000p_state *state)
Patrick Boettchera75763f2006-10-18 08:34:16 -0300726{
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300727 // P_restart_iqc & P_restart_agc
728 dib7000p_write_word(state, 770, (1 << 11) | (1 << 9));
729 dib7000p_write_word(state, 770, 0x0000);
Patrick Boettchera75763f2006-10-18 08:34:16 -0300730}
731
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300732static int dib7000p_update_lna(struct dib7000p_state *state)
Patrick Boettchera75763f2006-10-18 08:34:16 -0300733{
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300734 u16 dyn_gain;
735
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300736 if (state->cfg.update_lna) {
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300737 dyn_gain = dib7000p_read_word(state, 394);
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300738 if (state->cfg.update_lna(&state->demod, dyn_gain)) {
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300739 dib7000p_restart_agc(state);
740 return 1;
741 }
742 }
743
744 return 0;
745}
746
747static int dib7000p_set_agc_config(struct dib7000p_state *state, u8 band)
748{
749 struct dibx000_agc_config *agc = NULL;
750 int i;
751 if (state->current_band == band && state->current_agc != NULL)
752 return 0;
753 state->current_band = band;
754
755 for (i = 0; i < state->cfg.agc_config_count; i++)
756 if (state->cfg.agc[i].band_caps & band) {
757 agc = &state->cfg.agc[i];
758 break;
759 }
760
761 if (agc == NULL) {
Olivier Grenie713d54a2011-01-04 04:54:31 -0300762 dprintk("no valid AGC configuration found for band 0x%02x", band);
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300763 return -EINVAL;
764 }
765
766 state->current_agc = agc;
767
768 /* AGC */
Olivier Grenie713d54a2011-01-04 04:54:31 -0300769 dib7000p_write_word(state, 75, agc->setup);
770 dib7000p_write_word(state, 76, agc->inv_gain);
771 dib7000p_write_word(state, 77, agc->time_stabiliz);
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300772 dib7000p_write_word(state, 100, (agc->alpha_level << 12) | agc->thlock);
773
774 // Demod AGC loop configuration
775 dib7000p_write_word(state, 101, (agc->alpha_mant << 5) | agc->alpha_exp);
Olivier Grenie713d54a2011-01-04 04:54:31 -0300776 dib7000p_write_word(state, 102, (agc->beta_mant << 6) | agc->beta_exp);
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300777
778 /* AGC continued */
Olivier Grenie713d54a2011-01-04 04:54:31 -0300779 dprintk("WBD: ref: %d, sel: %d, active: %d, alpha: %d",
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300780 state->wbd_ref != 0 ? state->wbd_ref : agc->wbd_ref, agc->wbd_sel, !agc->perform_agc_softsplit, agc->wbd_sel);
781
782 if (state->wbd_ref != 0)
783 dib7000p_write_word(state, 105, (agc->wbd_inv << 12) | state->wbd_ref);
784 else
785 dib7000p_write_word(state, 105, (agc->wbd_inv << 12) | agc->wbd_ref);
786
787 dib7000p_write_word(state, 106, (agc->wbd_sel << 13) | (agc->wbd_alpha << 9) | (agc->perform_agc_softsplit << 8));
788
Olivier Grenie713d54a2011-01-04 04:54:31 -0300789 dib7000p_write_word(state, 107, agc->agc1_max);
790 dib7000p_write_word(state, 108, agc->agc1_min);
791 dib7000p_write_word(state, 109, agc->agc2_max);
792 dib7000p_write_word(state, 110, agc->agc2_min);
793 dib7000p_write_word(state, 111, (agc->agc1_pt1 << 8) | agc->agc1_pt2);
794 dib7000p_write_word(state, 112, agc->agc1_pt3);
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300795 dib7000p_write_word(state, 113, (agc->agc1_slope1 << 8) | agc->agc1_slope2);
Olivier Grenie713d54a2011-01-04 04:54:31 -0300796 dib7000p_write_word(state, 114, (agc->agc2_pt1 << 8) | agc->agc2_pt2);
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300797 dib7000p_write_word(state, 115, (agc->agc2_slope1 << 8) | agc->agc2_slope2);
798 return 0;
799}
800
Olivier Grenie713d54a2011-01-04 04:54:31 -0300801static void dib7000p_set_dds(struct dib7000p_state *state, s32 offset_khz)
802{
803 u32 internal = dib7000p_get_internal_freq(state);
804 s32 unit_khz_dds_val = 67108864 / (internal); /* 2**26 / Fsampling is the unit 1KHz offset */
805 u32 abs_offset_khz = ABS(offset_khz);
806 u32 dds = state->cfg.bw->ifreq & 0x1ffffff;
807 u8 invert = !!(state->cfg.bw->ifreq & (1 << 25));
808
809 dprintk("setting a frequency offset of %dkHz internal freq = %d invert = %d", offset_khz, internal, invert);
810
811 if (offset_khz < 0)
812 unit_khz_dds_val *= -1;
813
814 /* IF tuner */
815 if (invert)
816 dds -= (abs_offset_khz * unit_khz_dds_val); /* /100 because of /100 on the unit_khz_dds_val line calc for better accuracy */
817 else
818 dds += (abs_offset_khz * unit_khz_dds_val);
819
820 if (abs_offset_khz <= (internal / 2)) { /* Max dds offset is the half of the demod freq */
821 dib7000p_write_word(state, 21, (u16) (((dds >> 16) & 0x1ff) | (0 << 10) | (invert << 9)));
822 dib7000p_write_word(state, 22, (u16) (dds & 0xffff));
823 }
824}
825
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -0300826static int dib7000p_agc_startup(struct dvb_frontend *demod)
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300827{
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -0300828 struct dtv_frontend_properties *ch = &demod->dtv_property_cache;
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300829 struct dib7000p_state *state = demod->demodulator_priv;
830 int ret = -1;
831 u8 *agc_state = &state->agc_state;
832 u8 agc_split;
Olivier Grenie713d54a2011-01-04 04:54:31 -0300833 u16 reg;
834 u32 upd_demod_gain_period = 0x1000;
Olivier Grenie6fe10992012-12-31 09:23:26 -0300835 s32 frequency_offset = 0;
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300836
837 switch (state->agc_state) {
Olivier Grenie713d54a2011-01-04 04:54:31 -0300838 case 0:
Olivier Grenie713d54a2011-01-04 04:54:31 -0300839 dib7000p_set_power_mode(state, DIB7000P_POWER_ALL);
840 if (state->version == SOC7090) {
841 reg = dib7000p_read_word(state, 0x79b) & 0xff00;
842 dib7000p_write_word(state, 0x79a, upd_demod_gain_period & 0xFFFF); /* lsb */
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300843 dib7000p_write_word(state, 0x79b, reg | (1 << 14) | ((upd_demod_gain_period >> 16) & 0xFF));
Olivier Grenie713d54a2011-01-04 04:54:31 -0300844
845 /* enable adc i & q */
846 reg = dib7000p_read_word(state, 0x780);
847 dib7000p_write_word(state, 0x780, (reg | (0x3)) & (~(1 << 7)));
848 } else {
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300849 dib7000p_set_adc_state(state, DIBX000_ADC_ON);
850 dib7000p_pll_clk_cfg(state);
Olivier Grenie713d54a2011-01-04 04:54:31 -0300851 }
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300852
Olivier Grenie713d54a2011-01-04 04:54:31 -0300853 if (dib7000p_set_agc_config(state, BAND_OF_FREQUENCY(ch->frequency / 1000)) != 0)
854 return -1;
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300855
Olivier Grenie6fe10992012-12-31 09:23:26 -0300856 if (demod->ops.tuner_ops.get_frequency) {
857 u32 frequency_tuner;
858
859 demod->ops.tuner_ops.get_frequency(demod, &frequency_tuner);
860 frequency_offset = (s32)frequency_tuner / 1000 - ch->frequency / 1000;
861 }
862
863 dib7000p_set_dds(state, frequency_offset);
Olivier Grenie713d54a2011-01-04 04:54:31 -0300864 ret = 7;
865 (*agc_state)++;
866 break;
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300867
Olivier Grenie713d54a2011-01-04 04:54:31 -0300868 case 1:
Olivier Grenie713d54a2011-01-04 04:54:31 -0300869 if (state->cfg.agc_control)
870 state->cfg.agc_control(&state->demod, 1);
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300871
Olivier Grenie713d54a2011-01-04 04:54:31 -0300872 dib7000p_write_word(state, 78, 32768);
873 if (!state->current_agc->perform_agc_softsplit) {
874 /* we are using the wbd - so slow AGC startup */
875 /* force 0 split on WBD and restart AGC */
876 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 -0300877 (*agc_state)++;
878 ret = 5;
Olivier Grenie713d54a2011-01-04 04:54:31 -0300879 } else {
880 /* default AGC startup */
881 (*agc_state) = 4;
882 /* wait AGC rough lock time */
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300883 ret = 7;
Olivier Grenie713d54a2011-01-04 04:54:31 -0300884 }
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300885
Olivier Grenie713d54a2011-01-04 04:54:31 -0300886 dib7000p_restart_agc(state);
887 break;
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300888
Olivier Grenie713d54a2011-01-04 04:54:31 -0300889 case 2: /* fast split search path after 5sec */
890 dib7000p_write_word(state, 75, state->current_agc->setup | (1 << 4)); /* freeze AGC loop */
891 dib7000p_write_word(state, 106, (state->current_agc->wbd_sel << 13) | (2 << 9) | (0 << 8)); /* fast split search 0.25kHz */
892 (*agc_state)++;
893 ret = 14;
894 break;
895
896 case 3: /* split search ended */
897 agc_split = (u8) dib7000p_read_word(state, 396); /* store the split value for the next time */
898 dib7000p_write_word(state, 78, dib7000p_read_word(state, 394)); /* set AGC gain start value */
899
900 dib7000p_write_word(state, 75, state->current_agc->setup); /* std AGC loop */
901 dib7000p_write_word(state, 106, (state->current_agc->wbd_sel << 13) | (state->current_agc->wbd_alpha << 9) | agc_split); /* standard split search */
902
903 dib7000p_restart_agc(state);
904
905 dprintk("SPLIT %p: %hd", demod, agc_split);
906
907 (*agc_state)++;
908 ret = 5;
909 break;
910
911 case 4: /* LNA startup */
Olivier Grenie713d54a2011-01-04 04:54:31 -0300912 ret = 7;
913
914 if (dib7000p_update_lna(state))
Olivier Grenie713d54a2011-01-04 04:54:31 -0300915 ret = 5;
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300916 else
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300917 (*agc_state)++;
Olivier Grenie713d54a2011-01-04 04:54:31 -0300918 break;
919
920 case 5:
921 if (state->cfg.agc_control)
922 state->cfg.agc_control(&state->demod, 0);
923 (*agc_state)++;
924 break;
925 default:
926 break;
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300927 }
928 return ret;
929}
930
931static void dib7000p_update_timf(struct dib7000p_state *state)
932{
933 u32 timf = (dib7000p_read_word(state, 427) << 16) | dib7000p_read_word(state, 428);
934 state->timf = timf * 160 / (state->current_bandwidth / 50);
935 dib7000p_write_word(state, 23, (u16) (timf >> 16));
936 dib7000p_write_word(state, 24, (u16) (timf & 0xffff));
Olivier Grenie713d54a2011-01-04 04:54:31 -0300937 dprintk("updated timf_frequency: %d (default: %d)", state->timf, state->cfg.bw->timf);
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300938
939}
940
Mauro Carvalho Chehab8abe4a02014-05-29 09:20:15 -0300941static u32 dib7000p_ctrl_timf(struct dvb_frontend *fe, u8 op, u32 timf)
Olivier Grenie713d54a2011-01-04 04:54:31 -0300942{
943 struct dib7000p_state *state = fe->demodulator_priv;
944 switch (op) {
945 case DEMOD_TIMF_SET:
946 state->timf = timf;
947 break;
948 case DEMOD_TIMF_UPDATE:
949 dib7000p_update_timf(state);
950 break;
951 case DEMOD_TIMF_GET:
952 break;
953 }
954 dib7000p_set_bandwidth(state, state->current_bandwidth);
955 return state->timf;
956}
Olivier Grenie713d54a2011-01-04 04:54:31 -0300957
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -0300958static void dib7000p_set_channel(struct dib7000p_state *state,
959 struct dtv_frontend_properties *ch, u8 seq)
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300960{
961 u16 value, est[4];
962
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -0300963 dib7000p_set_bandwidth(state, BANDWIDTH_TO_KHZ(ch->bandwidth_hz));
Patrick Boettchera75763f2006-10-18 08:34:16 -0300964
965 /* nfft, guard, qam, alpha */
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300966 value = 0;
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -0300967 switch (ch->transmission_mode) {
Olivier Grenie713d54a2011-01-04 04:54:31 -0300968 case TRANSMISSION_MODE_2K:
969 value |= (0 << 7);
970 break;
Mauro Carvalho Chehab46f72962011-01-16 13:01:20 -0200971 case TRANSMISSION_MODE_4K:
Olivier Grenie713d54a2011-01-04 04:54:31 -0300972 value |= (2 << 7);
973 break;
974 default:
975 case TRANSMISSION_MODE_8K:
976 value |= (1 << 7);
977 break;
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300978 }
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -0300979 switch (ch->guard_interval) {
Olivier Grenie713d54a2011-01-04 04:54:31 -0300980 case GUARD_INTERVAL_1_32:
981 value |= (0 << 5);
982 break;
983 case GUARD_INTERVAL_1_16:
984 value |= (1 << 5);
985 break;
986 case GUARD_INTERVAL_1_4:
987 value |= (3 << 5);
988 break;
989 default:
990 case GUARD_INTERVAL_1_8:
991 value |= (2 << 5);
992 break;
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300993 }
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -0300994 switch (ch->modulation) {
Olivier Grenie713d54a2011-01-04 04:54:31 -0300995 case QPSK:
996 value |= (0 << 3);
997 break;
998 case QAM_16:
999 value |= (1 << 3);
1000 break;
1001 default:
1002 case QAM_64:
1003 value |= (2 << 3);
1004 break;
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001005 }
1006 switch (HIERARCHY_1) {
Olivier Grenie713d54a2011-01-04 04:54:31 -03001007 case HIERARCHY_2:
1008 value |= 2;
1009 break;
1010 case HIERARCHY_4:
1011 value |= 4;
1012 break;
1013 default:
1014 case HIERARCHY_1:
1015 value |= 1;
1016 break;
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001017 }
1018 dib7000p_write_word(state, 0, value);
Olivier Grenie713d54a2011-01-04 04:54:31 -03001019 dib7000p_write_word(state, 5, (seq << 4) | 1); /* do not force tps, search list 0 */
Patrick Boettchera75763f2006-10-18 08:34:16 -03001020
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001021 /* P_dintl_native, P_dintlv_inv, P_hrch, P_code_rate, P_select_hp */
1022 value = 0;
1023 if (1 != 0)
1024 value |= (1 << 6);
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -03001025 if (ch->hierarchy == 1)
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001026 value |= (1 << 4);
1027 if (1 == 1)
1028 value |= 1;
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -03001029 switch ((ch->hierarchy == 0 || 1 == 1) ? ch->code_rate_HP : ch->code_rate_LP) {
Olivier Grenie713d54a2011-01-04 04:54:31 -03001030 case FEC_2_3:
1031 value |= (2 << 1);
1032 break;
1033 case FEC_3_4:
1034 value |= (3 << 1);
1035 break;
1036 case FEC_5_6:
1037 value |= (5 << 1);
1038 break;
1039 case FEC_7_8:
1040 value |= (7 << 1);
1041 break;
1042 default:
1043 case FEC_1_2:
1044 value |= (1 << 1);
1045 break;
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001046 }
1047 dib7000p_write_word(state, 208, value);
1048
1049 /* offset loop parameters */
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001050 dib7000p_write_word(state, 26, 0x6680);
1051 dib7000p_write_word(state, 32, 0x0003);
1052 dib7000p_write_word(state, 29, 0x1273);
1053 dib7000p_write_word(state, 33, 0x0005);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001054
1055 /* P_dvsy_sync_wait */
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -03001056 switch (ch->transmission_mode) {
Olivier Grenie713d54a2011-01-04 04:54:31 -03001057 case TRANSMISSION_MODE_8K:
1058 value = 256;
1059 break;
1060 case TRANSMISSION_MODE_4K:
1061 value = 128;
1062 break;
1063 case TRANSMISSION_MODE_2K:
1064 default:
1065 value = 64;
1066 break;
Patrick Boettchera75763f2006-10-18 08:34:16 -03001067 }
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -03001068 switch (ch->guard_interval) {
Olivier Grenie713d54a2011-01-04 04:54:31 -03001069 case GUARD_INTERVAL_1_16:
1070 value *= 2;
1071 break;
1072 case GUARD_INTERVAL_1_8:
1073 value *= 4;
1074 break;
1075 case GUARD_INTERVAL_1_4:
1076 value *= 8;
1077 break;
1078 default:
1079 case GUARD_INTERVAL_1_32:
1080 value *= 1;
1081 break;
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001082 }
Olivier Grenie970d14c2010-09-07 12:50:46 -03001083 if (state->cfg.diversity_delay == 0)
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001084 state->div_sync_wait = (value * 3) / 2 + 48;
Olivier Grenie970d14c2010-09-07 12:50:46 -03001085 else
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001086 state->div_sync_wait = (value * 3) / 2 + state->cfg.diversity_delay;
Patrick Boettchera75763f2006-10-18 08:34:16 -03001087
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001088 /* deactive the possibility of diversity reception if extended interleaver */
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -03001089 state->div_force_off = !1 && ch->transmission_mode != TRANSMISSION_MODE_8K;
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001090 dib7000p_set_diversity_in(&state->demod, state->div_state);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001091
1092 /* channel estimation fine configuration */
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -03001093 switch (ch->modulation) {
Olivier Grenie713d54a2011-01-04 04:54:31 -03001094 case QAM_64:
1095 est[0] = 0x0148; /* P_adp_regul_cnt 0.04 */
1096 est[1] = 0xfff0; /* P_adp_noise_cnt -0.002 */
1097 est[2] = 0x00a4; /* P_adp_regul_ext 0.02 */
1098 est[3] = 0xfff8; /* P_adp_noise_ext -0.001 */
1099 break;
1100 case QAM_16:
1101 est[0] = 0x023d; /* P_adp_regul_cnt 0.07 */
1102 est[1] = 0xffdf; /* P_adp_noise_cnt -0.004 */
1103 est[2] = 0x00a4; /* P_adp_regul_ext 0.02 */
1104 est[3] = 0xfff0; /* P_adp_noise_ext -0.002 */
1105 break;
1106 default:
1107 est[0] = 0x099a; /* P_adp_regul_cnt 0.3 */
1108 est[1] = 0xffae; /* P_adp_noise_cnt -0.01 */
1109 est[2] = 0x0333; /* P_adp_regul_ext 0.1 */
1110 est[3] = 0xfff8; /* P_adp_noise_ext -0.002 */
1111 break;
Patrick Boettchera75763f2006-10-18 08:34:16 -03001112 }
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001113 for (value = 0; value < 4; value++)
1114 dib7000p_write_word(state, 187 + value, est[value]);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001115}
1116
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -03001117static int dib7000p_autosearch_start(struct dvb_frontend *demod)
Patrick Boettchera75763f2006-10-18 08:34:16 -03001118{
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -03001119 struct dtv_frontend_properties *ch = &demod->dtv_property_cache;
Patrick Boettchera75763f2006-10-18 08:34:16 -03001120 struct dib7000p_state *state = demod->demodulator_priv;
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -03001121 struct dtv_frontend_properties schan;
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001122 u32 value, factor;
Olivier Grenie713d54a2011-01-04 04:54:31 -03001123 u32 internal = dib7000p_get_internal_freq(state);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001124
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001125 schan = *ch;
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -03001126 schan.modulation = QAM_64;
1127 schan.guard_interval = GUARD_INTERVAL_1_32;
1128 schan.transmission_mode = TRANSMISSION_MODE_8K;
1129 schan.code_rate_HP = FEC_2_3;
1130 schan.code_rate_LP = FEC_3_4;
1131 schan.hierarchy = 0;
Patrick Boettchera75763f2006-10-18 08:34:16 -03001132
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001133 dib7000p_set_channel(state, &schan, 7);
1134
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -03001135 factor = BANDWIDTH_TO_KHZ(ch->bandwidth_hz);
Olivier Grenie2e802862011-08-05 10:39:15 -03001136 if (factor >= 5000) {
1137 if (state->version == SOC7090)
1138 factor = 2;
1139 else
1140 factor = 1;
1141 } else
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001142 factor = 6;
Patrick Boettchera75763f2006-10-18 08:34:16 -03001143
Olivier Grenie713d54a2011-01-04 04:54:31 -03001144 value = 30 * internal * factor;
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001145 dib7000p_write_word(state, 6, (u16) ((value >> 16) & 0xffff));
1146 dib7000p_write_word(state, 7, (u16) (value & 0xffff));
Olivier Grenie713d54a2011-01-04 04:54:31 -03001147 value = 100 * internal * factor;
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001148 dib7000p_write_word(state, 8, (u16) ((value >> 16) & 0xffff));
1149 dib7000p_write_word(state, 9, (u16) (value & 0xffff));
Olivier Grenie713d54a2011-01-04 04:54:31 -03001150 value = 500 * internal * factor;
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001151 dib7000p_write_word(state, 10, (u16) ((value >> 16) & 0xffff));
1152 dib7000p_write_word(state, 11, (u16) (value & 0xffff));
Patrick Boettchera75763f2006-10-18 08:34:16 -03001153
1154 value = dib7000p_read_word(state, 0);
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001155 dib7000p_write_word(state, 0, (u16) ((1 << 9) | value));
Patrick Boettchera75763f2006-10-18 08:34:16 -03001156 dib7000p_read_word(state, 1284);
1157 dib7000p_write_word(state, 0, (u16) value);
1158
1159 return 0;
1160}
1161
1162static int dib7000p_autosearch_is_irq(struct dvb_frontend *demod)
1163{
1164 struct dib7000p_state *state = demod->demodulator_priv;
1165 u16 irq_pending = dib7000p_read_word(state, 1284);
1166
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001167 if (irq_pending & 0x1)
Patrick Boettchera75763f2006-10-18 08:34:16 -03001168 return 1;
1169
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001170 if (irq_pending & 0x2)
Patrick Boettchera75763f2006-10-18 08:34:16 -03001171 return 2;
1172
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001173 return 0;
Patrick Boettchera75763f2006-10-18 08:34:16 -03001174}
1175
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001176static void dib7000p_spur_protect(struct dib7000p_state *state, u32 rf_khz, u32 bw)
1177{
Olivier Grenie713d54a2011-01-04 04:54:31 -03001178 static s16 notch[] = { 16143, 14402, 12238, 9713, 6902, 3888, 759, -2392 };
1179 static u8 sine[] = { 0, 2, 3, 5, 6, 8, 9, 11, 13, 14, 16, 17, 19, 20, 22,
1180 24, 25, 27, 28, 30, 31, 33, 34, 36, 38, 39, 41, 42, 44, 45, 47, 48, 50, 51,
1181 53, 55, 56, 58, 59, 61, 62, 64, 65, 67, 68, 70, 71, 73, 74, 76, 77, 79, 80,
1182 82, 83, 85, 86, 88, 89, 91, 92, 94, 95, 97, 98, 99, 101, 102, 104, 105,
1183 107, 108, 109, 111, 112, 114, 115, 117, 118, 119, 121, 122, 123, 125, 126,
1184 128, 129, 130, 132, 133, 134, 136, 137, 138, 140, 141, 142, 144, 145, 146,
1185 147, 149, 150, 151, 152, 154, 155, 156, 157, 159, 160, 161, 162, 164, 165,
1186 166, 167, 168, 170, 171, 172, 173, 174, 175, 177, 178, 179, 180, 181, 182,
1187 183, 184, 185, 186, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198,
1188 199, 200, 201, 202, 203, 204, 205, 206, 207, 207, 208, 209, 210, 211, 212,
1189 213, 214, 215, 215, 216, 217, 218, 219, 220, 220, 221, 222, 223, 224, 224,
1190 225, 226, 227, 227, 228, 229, 229, 230, 231, 231, 232, 233, 233, 234, 235,
1191 235, 236, 237, 237, 238, 238, 239, 239, 240, 241, 241, 242, 242, 243, 243,
1192 244, 244, 245, 245, 245, 246, 246, 247, 247, 248, 248, 248, 249, 249, 249,
1193 250, 250, 250, 251, 251, 251, 252, 252, 252, 252, 253, 253, 253, 253, 254,
1194 254, 254, 254, 254, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
1195 255, 255, 255, 255, 255, 255
1196 };
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001197
1198 u32 xtal = state->cfg.bw->xtal_hz / 1000;
Julia Lawall75b697f2009-08-01 16:48:41 -03001199 int f_rel = DIV_ROUND_CLOSEST(rf_khz, xtal) * xtal - rf_khz;
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001200 int k;
Olivier Grenie713d54a2011-01-04 04:54:31 -03001201 int coef_re[8], coef_im[8];
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001202 int bw_khz = bw;
1203 u32 pha;
1204
Olivier Grenie713d54a2011-01-04 04:54:31 -03001205 dprintk("relative position of the Spur: %dk (RF: %dk, XTAL: %dk)", f_rel, rf_khz, xtal);
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001206
Olivier Grenie713d54a2011-01-04 04:54:31 -03001207 if (f_rel < -bw_khz / 2 || f_rel > bw_khz / 2)
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001208 return;
1209
1210 bw_khz /= 100;
1211
Olivier Grenie713d54a2011-01-04 04:54:31 -03001212 dib7000p_write_word(state, 142, 0x0610);
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001213
1214 for (k = 0; k < 8; k++) {
Olivier Grenie713d54a2011-01-04 04:54:31 -03001215 pha = ((f_rel * (k + 1) * 112 * 80 / bw_khz) / 1000) & 0x3ff;
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001216
Olivier Grenie713d54a2011-01-04 04:54:31 -03001217 if (pha == 0) {
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001218 coef_re[k] = 256;
1219 coef_im[k] = 0;
Olivier Grenie713d54a2011-01-04 04:54:31 -03001220 } else if (pha < 256) {
1221 coef_re[k] = sine[256 - (pha & 0xff)];
1222 coef_im[k] = sine[pha & 0xff];
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001223 } else if (pha == 256) {
1224 coef_re[k] = 0;
1225 coef_im[k] = 256;
1226 } else if (pha < 512) {
Olivier Grenie713d54a2011-01-04 04:54:31 -03001227 coef_re[k] = -sine[pha & 0xff];
1228 coef_im[k] = sine[256 - (pha & 0xff)];
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001229 } else if (pha == 512) {
1230 coef_re[k] = -256;
1231 coef_im[k] = 0;
1232 } else if (pha < 768) {
Olivier Grenie713d54a2011-01-04 04:54:31 -03001233 coef_re[k] = -sine[256 - (pha & 0xff)];
1234 coef_im[k] = -sine[pha & 0xff];
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001235 } else if (pha == 768) {
1236 coef_re[k] = 0;
1237 coef_im[k] = -256;
1238 } else {
Olivier Grenie713d54a2011-01-04 04:54:31 -03001239 coef_re[k] = sine[pha & 0xff];
1240 coef_im[k] = -sine[256 - (pha & 0xff)];
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001241 }
1242
1243 coef_re[k] *= notch[k];
Olivier Grenie713d54a2011-01-04 04:54:31 -03001244 coef_re[k] += (1 << 14);
1245 if (coef_re[k] >= (1 << 24))
1246 coef_re[k] = (1 << 24) - 1;
1247 coef_re[k] /= (1 << 15);
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001248
1249 coef_im[k] *= notch[k];
Olivier Grenie713d54a2011-01-04 04:54:31 -03001250 coef_im[k] += (1 << 14);
1251 if (coef_im[k] >= (1 << 24))
1252 coef_im[k] = (1 << 24) - 1;
1253 coef_im[k] /= (1 << 15);
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001254
Olivier Grenie713d54a2011-01-04 04:54:31 -03001255 dprintk("PALF COEF: %d re: %d im: %d", k, coef_re[k], coef_im[k]);
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001256
1257 dib7000p_write_word(state, 143, (0 << 14) | (k << 10) | (coef_re[k] & 0x3ff));
1258 dib7000p_write_word(state, 144, coef_im[k] & 0x3ff);
1259 dib7000p_write_word(state, 143, (1 << 14) | (k << 10) | (coef_re[k] & 0x3ff));
1260 }
Olivier Grenie713d54a2011-01-04 04:54:31 -03001261 dib7000p_write_word(state, 143, 0);
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001262}
1263
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -03001264static int dib7000p_tune(struct dvb_frontend *demod)
Patrick Boettchera75763f2006-10-18 08:34:16 -03001265{
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -03001266 struct dtv_frontend_properties *ch = &demod->dtv_property_cache;
Patrick Boettchera75763f2006-10-18 08:34:16 -03001267 struct dib7000p_state *state = demod->demodulator_priv;
1268 u16 tmp = 0;
1269
1270 if (ch != NULL)
1271 dib7000p_set_channel(state, ch, 0);
1272 else
1273 return -EINVAL;
1274
1275 // restart demod
1276 dib7000p_write_word(state, 770, 0x4000);
1277 dib7000p_write_word(state, 770, 0x0000);
1278 msleep(45);
1279
1280 /* P_ctrl_inh_cor=0, P_ctrl_alpha_cor=4, P_ctrl_inh_isi=0, P_ctrl_alpha_isi=3, P_ctrl_inh_cor4=1, P_ctrl_alpha_cor4=3 */
Matt Doran8f6956c2007-07-31 07:09:30 -03001281 tmp = (0 << 14) | (4 << 10) | (0 << 9) | (3 << 5) | (1 << 4) | (0x3);
1282 if (state->sfn_workaround_active) {
Olivier Grenie713d54a2011-01-04 04:54:31 -03001283 dprintk("SFN workaround is active");
Matt Doran8f6956c2007-07-31 07:09:30 -03001284 tmp |= (1 << 9);
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001285 dib7000p_write_word(state, 166, 0x4000);
Matt Doran8f6956c2007-07-31 07:09:30 -03001286 } else {
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001287 dib7000p_write_word(state, 166, 0x0000);
Matt Doran8f6956c2007-07-31 07:09:30 -03001288 }
1289 dib7000p_write_word(state, 29, tmp);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001290
1291 // never achieved a lock with that bandwidth so far - wait for osc-freq to update
1292 if (state->timf == 0)
1293 msleep(200);
1294
1295 /* offset loop parameters */
1296
1297 /* P_timf_alpha, P_corm_alpha=6, P_corm_thres=0x80 */
1298 tmp = (6 << 8) | 0x80;
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -03001299 switch (ch->transmission_mode) {
Olivier Grenie713d54a2011-01-04 04:54:31 -03001300 case TRANSMISSION_MODE_2K:
1301 tmp |= (2 << 12);
1302 break;
Mauro Carvalho Chehab46f72962011-01-16 13:01:20 -02001303 case TRANSMISSION_MODE_4K:
Olivier Grenie713d54a2011-01-04 04:54:31 -03001304 tmp |= (3 << 12);
1305 break;
1306 default:
1307 case TRANSMISSION_MODE_8K:
1308 tmp |= (4 << 12);
1309 break;
Patrick Boettchera75763f2006-10-18 08:34:16 -03001310 }
Olivier Grenie713d54a2011-01-04 04:54:31 -03001311 dib7000p_write_word(state, 26, tmp); /* timf_a(6xxx) */
Patrick Boettchera75763f2006-10-18 08:34:16 -03001312
1313 /* P_ctrl_freeze_pha_shift=0, P_ctrl_pha_off_max */
1314 tmp = (0 << 4);
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -03001315 switch (ch->transmission_mode) {
Olivier Grenie713d54a2011-01-04 04:54:31 -03001316 case TRANSMISSION_MODE_2K:
1317 tmp |= 0x6;
1318 break;
Mauro Carvalho Chehab46f72962011-01-16 13:01:20 -02001319 case TRANSMISSION_MODE_4K:
Olivier Grenie713d54a2011-01-04 04:54:31 -03001320 tmp |= 0x7;
1321 break;
1322 default:
1323 case TRANSMISSION_MODE_8K:
1324 tmp |= 0x8;
1325 break;
Patrick Boettchera75763f2006-10-18 08:34:16 -03001326 }
Olivier Grenie713d54a2011-01-04 04:54:31 -03001327 dib7000p_write_word(state, 32, tmp);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001328
1329 /* P_ctrl_sfreq_inh=0, P_ctrl_sfreq_step */
1330 tmp = (0 << 4);
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -03001331 switch (ch->transmission_mode) {
Olivier Grenie713d54a2011-01-04 04:54:31 -03001332 case TRANSMISSION_MODE_2K:
1333 tmp |= 0x6;
1334 break;
1335 case TRANSMISSION_MODE_4K:
1336 tmp |= 0x7;
1337 break;
1338 default:
1339 case TRANSMISSION_MODE_8K:
1340 tmp |= 0x8;
1341 break;
Patrick Boettchera75763f2006-10-18 08:34:16 -03001342 }
Olivier Grenie713d54a2011-01-04 04:54:31 -03001343 dib7000p_write_word(state, 33, tmp);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001344
Olivier Grenie713d54a2011-01-04 04:54:31 -03001345 tmp = dib7000p_read_word(state, 509);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001346 if (!((tmp >> 6) & 0x1)) {
1347 /* restart the fec */
Olivier Grenie713d54a2011-01-04 04:54:31 -03001348 tmp = dib7000p_read_word(state, 771);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001349 dib7000p_write_word(state, 771, tmp | (1 << 1));
1350 dib7000p_write_word(state, 771, tmp);
Olivier Grenie713d54a2011-01-04 04:54:31 -03001351 msleep(40);
1352 tmp = dib7000p_read_word(state, 509);
1353 }
1354 // we achieved a lock - it's time to update the osc freq
1355 if ((tmp >> 6) & 0x1) {
1356 dib7000p_update_timf(state);
1357 /* P_timf_alpha += 2 */
1358 tmp = dib7000p_read_word(state, 26);
1359 dib7000p_write_word(state, 26, (tmp & ~(0xf << 12)) | ((((tmp >> 12) & 0xf) + 5) << 12));
Patrick Boettchera75763f2006-10-18 08:34:16 -03001360 }
1361
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001362 if (state->cfg.spur_protect)
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -03001363 dib7000p_spur_protect(state, ch->frequency / 1000, BANDWIDTH_TO_KHZ(ch->bandwidth_hz));
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001364
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -03001365 dib7000p_set_bandwidth(state, BANDWIDTH_TO_KHZ(ch->bandwidth_hz));
Mauro Carvalho Chehab041ad442014-05-29 14:44:56 -03001366
1367 dib7000p_reset_stats(demod);
1368
Patrick Boettchera75763f2006-10-18 08:34:16 -03001369 return 0;
1370}
1371
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001372static int dib7000p_wakeup(struct dvb_frontend *demod)
Patrick Boettchera75763f2006-10-18 08:34:16 -03001373{
Patrick Boettchera75763f2006-10-18 08:34:16 -03001374 struct dib7000p_state *state = demod->demodulator_priv;
Patrick Boettchera75763f2006-10-18 08:34:16 -03001375 dib7000p_set_power_mode(state, DIB7000P_POWER_ALL);
1376 dib7000p_set_adc_state(state, DIBX000_SLOW_ADC_ON);
Olivier Grenie713d54a2011-01-04 04:54:31 -03001377 if (state->version == SOC7090)
1378 dib7000p_sad_calib(state);
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001379 return 0;
Patrick Boettchera75763f2006-10-18 08:34:16 -03001380}
1381
1382static int dib7000p_sleep(struct dvb_frontend *demod)
1383{
1384 struct dib7000p_state *state = demod->demodulator_priv;
Olivier Grenie713d54a2011-01-04 04:54:31 -03001385 if (state->version == SOC7090)
Olivier Grenie2e802862011-08-05 10:39:15 -03001386 return dib7000p_set_power_mode(state, DIB7000P_POWER_INTERFACE_ONLY);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001387 return dib7000p_set_output_mode(state, OUTMODE_HIGH_Z) | dib7000p_set_power_mode(state, DIB7000P_POWER_INTERFACE_ONLY);
1388}
1389
1390static int dib7000p_identify(struct dib7000p_state *st)
1391{
1392 u16 value;
Olivier Grenie713d54a2011-01-04 04:54:31 -03001393 dprintk("checking demod on I2C address: %d (%x)", st->i2c_addr, st->i2c_addr);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001394
1395 if ((value = dib7000p_read_word(st, 768)) != 0x01b3) {
Olivier Grenie713d54a2011-01-04 04:54:31 -03001396 dprintk("wrong Vendor ID (read=0x%x)", value);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001397 return -EREMOTEIO;
1398 }
1399
1400 if ((value = dib7000p_read_word(st, 769)) != 0x4000) {
Olivier Grenie713d54a2011-01-04 04:54:31 -03001401 dprintk("wrong Device ID (%x)", value);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001402 return -EREMOTEIO;
1403 }
1404
1405 return 0;
1406}
1407
Mauro Carvalho Chehab7c61d802011-12-30 11:30:21 -03001408static int dib7000p_get_frontend(struct dvb_frontend *fe)
Patrick Boettchera75763f2006-10-18 08:34:16 -03001409{
Mauro Carvalho Chehab7c61d802011-12-30 11:30:21 -03001410 struct dtv_frontend_properties *fep = &fe->dtv_property_cache;
Patrick Boettchera75763f2006-10-18 08:34:16 -03001411 struct dib7000p_state *state = fe->demodulator_priv;
Olivier Grenie713d54a2011-01-04 04:54:31 -03001412 u16 tps = dib7000p_read_word(state, 463);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001413
1414 fep->inversion = INVERSION_AUTO;
1415
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -03001416 fep->bandwidth_hz = BANDWIDTH_TO_HZ(state->current_bandwidth);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001417
1418 switch ((tps >> 8) & 0x3) {
Olivier Grenie713d54a2011-01-04 04:54:31 -03001419 case 0:
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -03001420 fep->transmission_mode = TRANSMISSION_MODE_2K;
Olivier Grenie713d54a2011-01-04 04:54:31 -03001421 break;
1422 case 1:
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -03001423 fep->transmission_mode = TRANSMISSION_MODE_8K;
Olivier Grenie713d54a2011-01-04 04:54:31 -03001424 break;
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -03001425 /* case 2: fep->transmission_mode = TRANSMISSION_MODE_4K; break; */
Patrick Boettchera75763f2006-10-18 08:34:16 -03001426 }
1427
1428 switch (tps & 0x3) {
Olivier Grenie713d54a2011-01-04 04:54:31 -03001429 case 0:
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -03001430 fep->guard_interval = GUARD_INTERVAL_1_32;
Olivier Grenie713d54a2011-01-04 04:54:31 -03001431 break;
1432 case 1:
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -03001433 fep->guard_interval = GUARD_INTERVAL_1_16;
Olivier Grenie713d54a2011-01-04 04:54:31 -03001434 break;
1435 case 2:
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -03001436 fep->guard_interval = GUARD_INTERVAL_1_8;
Olivier Grenie713d54a2011-01-04 04:54:31 -03001437 break;
1438 case 3:
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -03001439 fep->guard_interval = GUARD_INTERVAL_1_4;
Olivier Grenie713d54a2011-01-04 04:54:31 -03001440 break;
Patrick Boettchera75763f2006-10-18 08:34:16 -03001441 }
1442
1443 switch ((tps >> 14) & 0x3) {
Olivier Grenie713d54a2011-01-04 04:54:31 -03001444 case 0:
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -03001445 fep->modulation = QPSK;
Olivier Grenie713d54a2011-01-04 04:54:31 -03001446 break;
1447 case 1:
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -03001448 fep->modulation = QAM_16;
Olivier Grenie713d54a2011-01-04 04:54:31 -03001449 break;
1450 case 2:
1451 default:
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -03001452 fep->modulation = QAM_64;
Olivier Grenie713d54a2011-01-04 04:54:31 -03001453 break;
Patrick Boettchera75763f2006-10-18 08:34:16 -03001454 }
1455
1456 /* as long as the frontend_param structure is fixed for hierarchical transmission I refuse to use it */
1457 /* (tps >> 13) & 0x1 == hrch is used, (tps >> 10) & 0x7 == alpha */
1458
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -03001459 fep->hierarchy = HIERARCHY_NONE;
Patrick Boettchera75763f2006-10-18 08:34:16 -03001460 switch ((tps >> 5) & 0x7) {
Olivier Grenie713d54a2011-01-04 04:54:31 -03001461 case 1:
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -03001462 fep->code_rate_HP = FEC_1_2;
Olivier Grenie713d54a2011-01-04 04:54:31 -03001463 break;
1464 case 2:
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -03001465 fep->code_rate_HP = FEC_2_3;
Olivier Grenie713d54a2011-01-04 04:54:31 -03001466 break;
1467 case 3:
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -03001468 fep->code_rate_HP = FEC_3_4;
Olivier Grenie713d54a2011-01-04 04:54:31 -03001469 break;
1470 case 5:
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -03001471 fep->code_rate_HP = FEC_5_6;
Olivier Grenie713d54a2011-01-04 04:54:31 -03001472 break;
1473 case 7:
1474 default:
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -03001475 fep->code_rate_HP = FEC_7_8;
Olivier Grenie713d54a2011-01-04 04:54:31 -03001476 break;
Patrick Boettchera75763f2006-10-18 08:34:16 -03001477
1478 }
1479
1480 switch ((tps >> 2) & 0x7) {
Olivier Grenie713d54a2011-01-04 04:54:31 -03001481 case 1:
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -03001482 fep->code_rate_LP = FEC_1_2;
Olivier Grenie713d54a2011-01-04 04:54:31 -03001483 break;
1484 case 2:
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -03001485 fep->code_rate_LP = FEC_2_3;
Olivier Grenie713d54a2011-01-04 04:54:31 -03001486 break;
1487 case 3:
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -03001488 fep->code_rate_LP = FEC_3_4;
Olivier Grenie713d54a2011-01-04 04:54:31 -03001489 break;
1490 case 5:
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -03001491 fep->code_rate_LP = FEC_5_6;
Olivier Grenie713d54a2011-01-04 04:54:31 -03001492 break;
1493 case 7:
1494 default:
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -03001495 fep->code_rate_LP = FEC_7_8;
Olivier Grenie713d54a2011-01-04 04:54:31 -03001496 break;
Patrick Boettchera75763f2006-10-18 08:34:16 -03001497 }
1498
1499 /* native interleaver: (dib7000p_read_word(state, 464) >> 5) & 0x1 */
1500
1501 return 0;
1502}
1503
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -03001504static int dib7000p_set_frontend(struct dvb_frontend *fe)
Patrick Boettchera75763f2006-10-18 08:34:16 -03001505{
Mauro Carvalho Chehab7c61d802011-12-30 11:30:21 -03001506 struct dtv_frontend_properties *fep = &fe->dtv_property_cache;
Patrick Boettchera75763f2006-10-18 08:34:16 -03001507 struct dib7000p_state *state = fe->demodulator_priv;
Soeren Moch853ea132008-01-25 06:27:06 -03001508 int time, ret;
Patrick Boettchera75763f2006-10-18 08:34:16 -03001509
Olivier Grenie2e802862011-08-05 10:39:15 -03001510 if (state->version == SOC7090)
Olivier Grenie713d54a2011-01-04 04:54:31 -03001511 dib7090_set_diversity_in(fe, 0);
Olivier Grenie2e802862011-08-05 10:39:15 -03001512 else
Olivier Grenie713d54a2011-01-04 04:54:31 -03001513 dib7000p_set_output_mode(state, OUTMODE_HIGH_Z);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001514
Olivier Grenie713d54a2011-01-04 04:54:31 -03001515 /* maybe the parameter has been changed */
Matt Doran8f6956c2007-07-31 07:09:30 -03001516 state->sfn_workaround_active = buggy_sfn_workaround;
1517
Patrick Boettchera75763f2006-10-18 08:34:16 -03001518 if (fe->ops.tuner_ops.set_params)
Mauro Carvalho Chehab14d24d12011-12-24 12:24:33 -03001519 fe->ops.tuner_ops.set_params(fe);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001520
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001521 /* start up the AGC */
1522 state->agc_state = 0;
1523 do {
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -03001524 time = dib7000p_agc_startup(fe);
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001525 if (time != -1)
1526 msleep(time);
1527 } while (time != -1);
1528
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -03001529 if (fep->transmission_mode == TRANSMISSION_MODE_AUTO ||
1530 fep->guard_interval == GUARD_INTERVAL_AUTO || fep->modulation == QAM_AUTO || fep->code_rate_HP == FEC_AUTO) {
Patrick Boettchera75763f2006-10-18 08:34:16 -03001531 int i = 800, found;
1532
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -03001533 dib7000p_autosearch_start(fe);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001534 do {
1535 msleep(1);
1536 found = dib7000p_autosearch_is_irq(fe);
1537 } while (found == 0 && i--);
1538
Olivier Grenie713d54a2011-01-04 04:54:31 -03001539 dprintk("autosearch returns: %d", found);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001540 if (found == 0 || found == 1)
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001541 return 0;
Patrick Boettchera75763f2006-10-18 08:34:16 -03001542
Mauro Carvalho Chehab7c61d802011-12-30 11:30:21 -03001543 dib7000p_get_frontend(fe);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001544 }
1545
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -03001546 ret = dib7000p_tune(fe);
Soeren Moch853ea132008-01-25 06:27:06 -03001547
Patrick Boettchera75763f2006-10-18 08:34:16 -03001548 /* make this a config parameter */
Olivier Grenie2e802862011-08-05 10:39:15 -03001549 if (state->version == SOC7090) {
Olivier Grenie713d54a2011-01-04 04:54:31 -03001550 dib7090_set_output_mode(fe, state->cfg.output_mode);
Olivier Grenie2e802862011-08-05 10:39:15 -03001551 if (state->cfg.enMpegOutput == 0) {
1552 dib7090_setDibTxMux(state, MPEG_ON_DIBTX);
1553 dib7090_setHostBusMux(state, DIBTX_ON_HOSTBUS);
1554 }
1555 } else
Olivier Grenie713d54a2011-01-04 04:54:31 -03001556 dib7000p_set_output_mode(state, state->cfg.output_mode);
1557
1558 return ret;
Patrick Boettchera75763f2006-10-18 08:34:16 -03001559}
1560
Mauro Carvalho Chehab041ad442014-05-29 14:44:56 -03001561static int dib7000p_get_stats(struct dvb_frontend *fe, fe_status_t stat);
1562
Olivier Grenie713d54a2011-01-04 04:54:31 -03001563static int dib7000p_read_status(struct dvb_frontend *fe, fe_status_t * stat)
Patrick Boettchera75763f2006-10-18 08:34:16 -03001564{
1565 struct dib7000p_state *state = fe->demodulator_priv;
1566 u16 lock = dib7000p_read_word(state, 509);
1567
1568 *stat = 0;
1569
1570 if (lock & 0x8000)
1571 *stat |= FE_HAS_SIGNAL;
1572 if (lock & 0x3000)
1573 *stat |= FE_HAS_CARRIER;
1574 if (lock & 0x0100)
1575 *stat |= FE_HAS_VITERBI;
1576 if (lock & 0x0010)
1577 *stat |= FE_HAS_SYNC;
Olivier Grenie713d54a2011-01-04 04:54:31 -03001578 if ((lock & 0x0038) == 0x38)
Patrick Boettchera75763f2006-10-18 08:34:16 -03001579 *stat |= FE_HAS_LOCK;
1580
Mauro Carvalho Chehab041ad442014-05-29 14:44:56 -03001581 dib7000p_get_stats(fe, *stat);
1582
Patrick Boettchera75763f2006-10-18 08:34:16 -03001583 return 0;
1584}
1585
Olivier Grenie713d54a2011-01-04 04:54:31 -03001586static int dib7000p_read_ber(struct dvb_frontend *fe, u32 * ber)
Patrick Boettchera75763f2006-10-18 08:34:16 -03001587{
1588 struct dib7000p_state *state = fe->demodulator_priv;
1589 *ber = (dib7000p_read_word(state, 500) << 16) | dib7000p_read_word(state, 501);
1590 return 0;
1591}
1592
Olivier Grenie713d54a2011-01-04 04:54:31 -03001593static int dib7000p_read_unc_blocks(struct dvb_frontend *fe, u32 * unc)
Patrick Boettchera75763f2006-10-18 08:34:16 -03001594{
1595 struct dib7000p_state *state = fe->demodulator_priv;
1596 *unc = dib7000p_read_word(state, 506);
1597 return 0;
1598}
1599
Olivier Grenie713d54a2011-01-04 04:54:31 -03001600static int dib7000p_read_signal_strength(struct dvb_frontend *fe, u16 * strength)
Patrick Boettchera75763f2006-10-18 08:34:16 -03001601{
1602 struct dib7000p_state *state = fe->demodulator_priv;
1603 u16 val = dib7000p_read_word(state, 394);
1604 *strength = 65535 - val;
1605 return 0;
1606}
1607
Mauro Carvalho Chehab041ad442014-05-29 14:44:56 -03001608static u32 dib7000p_get_snr(struct dvb_frontend *fe)
Patrick Boettchera75763f2006-10-18 08:34:16 -03001609{
Olivier Grenieef801962009-09-15 06:46:52 -03001610 struct dib7000p_state *state = fe->demodulator_priv;
1611 u16 val;
1612 s32 signal_mant, signal_exp, noise_mant, noise_exp;
1613 u32 result = 0;
1614
1615 val = dib7000p_read_word(state, 479);
1616 noise_mant = (val >> 4) & 0xff;
1617 noise_exp = ((val & 0xf) << 2);
1618 val = dib7000p_read_word(state, 480);
1619 noise_exp += ((val >> 14) & 0x3);
1620 if ((noise_exp & 0x20) != 0)
1621 noise_exp -= 0x40;
1622
1623 signal_mant = (val >> 6) & 0xFF;
Olivier Grenie713d54a2011-01-04 04:54:31 -03001624 signal_exp = (val & 0x3F);
Olivier Grenieef801962009-09-15 06:46:52 -03001625 if ((signal_exp & 0x20) != 0)
1626 signal_exp -= 0x40;
1627
1628 if (signal_mant != 0)
Olivier Grenie713d54a2011-01-04 04:54:31 -03001629 result = intlog10(2) * 10 * signal_exp + 10 * intlog10(signal_mant);
Olivier Grenieef801962009-09-15 06:46:52 -03001630 else
1631 result = intlog10(2) * 10 * signal_exp - 100;
1632
1633 if (noise_mant != 0)
Olivier Grenie713d54a2011-01-04 04:54:31 -03001634 result -= intlog10(2) * 10 * noise_exp + 10 * intlog10(noise_mant);
Olivier Grenieef801962009-09-15 06:46:52 -03001635 else
1636 result -= intlog10(2) * 10 * noise_exp - 100;
1637
Mauro Carvalho Chehab041ad442014-05-29 14:44:56 -03001638 return result;
1639}
1640
1641static int dib7000p_read_snr(struct dvb_frontend *fe, u16 *snr)
1642{
1643 u32 result;
1644
1645 result = dib7000p_get_snr(fe);
1646
Olivier Grenieef801962009-09-15 06:46:52 -03001647 *snr = result / ((1 << 24) / 10);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001648 return 0;
1649}
1650
Mauro Carvalho Chehab041ad442014-05-29 14:44:56 -03001651static void dib7000p_reset_stats(struct dvb_frontend *demod)
1652{
1653 struct dib7000p_state *state = demod->demodulator_priv;
1654 struct dtv_frontend_properties *c = &demod->dtv_property_cache;
1655 u32 ucb;
1656
1657 memset(&c->strength, 0, sizeof(c->strength));
1658 memset(&c->cnr, 0, sizeof(c->cnr));
1659 memset(&c->post_bit_error, 0, sizeof(c->post_bit_error));
1660 memset(&c->post_bit_count, 0, sizeof(c->post_bit_count));
1661 memset(&c->block_error, 0, sizeof(c->block_error));
1662
1663 c->strength.len = 1;
1664 c->cnr.len = 1;
1665 c->block_error.len = 1;
1666 c->block_count.len = 1;
1667 c->post_bit_error.len = 1;
1668 c->post_bit_count.len = 1;
1669
1670 c->strength.stat[0].scale = FE_SCALE_DECIBEL;
1671 c->strength.stat[0].uvalue = 0;
1672
1673 c->cnr.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
1674 c->block_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
1675 c->block_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
1676 c->post_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
1677 c->post_bit_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
1678
1679 dib7000p_read_unc_blocks(demod, &ucb);
1680
1681 state->old_ucb = ucb;
1682 state->ber_jiffies_stats = 0;
1683 state->per_jiffies_stats = 0;
1684}
1685
1686struct linear_segments {
1687 unsigned x;
1688 signed y;
1689};
1690
1691/*
1692 * Table to estimate signal strength in dBm.
1693 * This table should be empirically determinated by measuring the signal
1694 * strength generated by a RF generator directly connected into
1695 * a device.
Mauro Carvalho Chehab3926d912014-05-29 14:44:57 -03001696 * This table was determinated by measuring the signal strength generated
1697 * by a DTA-2111 RF generator directly connected into a dib7000p device
1698 * (a Hauppauge Nova-TD stick), using a good quality 3 meters length
1699 * RC6 cable and good RC6 connectors, connected directly to antenna 1.
1700 * As the minimum output power of DTA-2111 is -31dBm, a 16 dBm attenuator
1701 * were used, for the lower power values.
1702 * The real value can actually be on other devices, or even at the
1703 * second antena input, depending on several factors, like if LNA
1704 * is enabled or not, if diversity is enabled, type of connectors, etc.
1705 * Yet, it is better to use this measure in dB than a random non-linear
1706 * percentage value, especially for antenna adjustments.
1707 * On my tests, the precision of the measure using this table is about
1708 * 0.5 dB, with sounds reasonable enough to adjust antennas.
Mauro Carvalho Chehab041ad442014-05-29 14:44:56 -03001709 */
Mauro Carvalho Chehab3926d912014-05-29 14:44:57 -03001710#define DB_OFFSET 131000
Mauro Carvalho Chehab041ad442014-05-29 14:44:56 -03001711
1712static struct linear_segments strength_to_db_table[] = {
Mauro Carvalho Chehab3926d912014-05-29 14:44:57 -03001713 { 63630, DB_OFFSET - 20500},
1714 { 62273, DB_OFFSET - 21000},
1715 { 60162, DB_OFFSET - 22000},
1716 { 58730, DB_OFFSET - 23000},
1717 { 58294, DB_OFFSET - 24000},
1718 { 57778, DB_OFFSET - 25000},
1719 { 57320, DB_OFFSET - 26000},
1720 { 56779, DB_OFFSET - 27000},
1721 { 56293, DB_OFFSET - 28000},
1722 { 55724, DB_OFFSET - 29000},
1723 { 55145, DB_OFFSET - 30000},
1724 { 54680, DB_OFFSET - 31000},
1725 { 54293, DB_OFFSET - 32000},
1726 { 53813, DB_OFFSET - 33000},
1727 { 53427, DB_OFFSET - 34000},
1728 { 52981, DB_OFFSET - 35000},
1729
1730 { 52636, DB_OFFSET - 36000},
1731 { 52014, DB_OFFSET - 37000},
1732 { 51674, DB_OFFSET - 38000},
1733 { 50692, DB_OFFSET - 39000},
1734 { 49824, DB_OFFSET - 40000},
1735 { 49052, DB_OFFSET - 41000},
1736 { 48436, DB_OFFSET - 42000},
1737 { 47836, DB_OFFSET - 43000},
1738 { 47368, DB_OFFSET - 44000},
1739 { 46468, DB_OFFSET - 45000},
1740 { 45597, DB_OFFSET - 46000},
1741 { 44586, DB_OFFSET - 47000},
1742 { 43667, DB_OFFSET - 48000},
1743 { 42673, DB_OFFSET - 49000},
1744 { 41816, DB_OFFSET - 50000},
1745 { 40876, DB_OFFSET - 51000},
Mauro Carvalho Chehab041ad442014-05-29 14:44:56 -03001746 { 0, 0},
1747};
1748
1749static u32 interpolate_value(u32 value, struct linear_segments *segments,
1750 unsigned len)
1751{
1752 u64 tmp64;
1753 u32 dx;
1754 s32 dy;
1755 int i, ret;
1756
1757 if (value >= segments[0].x)
1758 return segments[0].y;
1759 if (value < segments[len-1].x)
1760 return segments[len-1].y;
1761
1762 for (i = 1; i < len - 1; i++) {
1763 /* If value is identical, no need to interpolate */
1764 if (value == segments[i].x)
1765 return segments[i].y;
1766 if (value > segments[i].x)
1767 break;
1768 }
1769
1770 /* Linear interpolation between the two (x,y) points */
1771 dy = segments[i - 1].y - segments[i].y;
1772 dx = segments[i - 1].x - segments[i].x;
1773
1774 tmp64 = value - segments[i].x;
1775 tmp64 *= dy;
1776 do_div(tmp64, dx);
1777 ret = segments[i].y + tmp64;
1778
1779 return ret;
1780}
1781
1782/* FIXME: may require changes - this one was borrowed from dib8000 */
1783static u32 dib7000p_get_time_us(struct dvb_frontend *demod, int layer)
1784{
1785 struct dtv_frontend_properties *c = &demod->dtv_property_cache;
1786 u64 time_us, tmp64;
1787 u32 tmp, denom;
1788 int guard, rate_num, rate_denum = 1, bits_per_symbol;
1789 int interleaving = 0, fft_div;
1790
1791 switch (c->guard_interval) {
1792 case GUARD_INTERVAL_1_4:
1793 guard = 4;
1794 break;
1795 case GUARD_INTERVAL_1_8:
1796 guard = 8;
1797 break;
1798 case GUARD_INTERVAL_1_16:
1799 guard = 16;
1800 break;
1801 default:
1802 case GUARD_INTERVAL_1_32:
1803 guard = 32;
1804 break;
1805 }
1806
1807 switch (c->transmission_mode) {
1808 case TRANSMISSION_MODE_2K:
1809 fft_div = 4;
1810 break;
1811 case TRANSMISSION_MODE_4K:
1812 fft_div = 2;
1813 break;
1814 default:
1815 case TRANSMISSION_MODE_8K:
1816 fft_div = 1;
1817 break;
1818 }
1819
1820 switch (c->modulation) {
1821 case DQPSK:
1822 case QPSK:
1823 bits_per_symbol = 2;
1824 break;
1825 case QAM_16:
1826 bits_per_symbol = 4;
1827 break;
1828 default:
1829 case QAM_64:
1830 bits_per_symbol = 6;
1831 break;
1832 }
1833
1834 switch ((c->hierarchy == 0 || 1 == 1) ? c->code_rate_HP : c->code_rate_LP) {
1835 case FEC_1_2:
1836 rate_num = 1;
1837 rate_denum = 2;
1838 break;
1839 case FEC_2_3:
1840 rate_num = 2;
1841 rate_denum = 3;
1842 break;
1843 case FEC_3_4:
1844 rate_num = 3;
1845 rate_denum = 4;
1846 break;
1847 case FEC_5_6:
1848 rate_num = 5;
1849 rate_denum = 6;
1850 break;
1851 default:
1852 case FEC_7_8:
1853 rate_num = 7;
1854 rate_denum = 8;
1855 break;
1856 }
1857
1858 interleaving = interleaving;
1859
1860 denom = bits_per_symbol * rate_num * fft_div * 384;
1861
1862 /* If calculus gets wrong, wait for 1s for the next stats */
1863 if (!denom)
1864 return 0;
1865
1866 /* Estimate the period for the total bit rate */
1867 time_us = rate_denum * (1008 * 1562500L);
1868 tmp64 = time_us;
1869 do_div(tmp64, guard);
1870 time_us = time_us + tmp64;
1871 time_us += denom / 2;
1872 do_div(time_us, denom);
1873
1874 tmp = 1008 * 96 * interleaving;
1875 time_us += tmp + tmp / guard;
1876
1877 return time_us;
1878}
1879
1880static int dib7000p_get_stats(struct dvb_frontend *demod, fe_status_t stat)
1881{
1882 struct dib7000p_state *state = demod->demodulator_priv;
1883 struct dtv_frontend_properties *c = &demod->dtv_property_cache;
1884 int i;
1885 int show_per_stats = 0;
1886 u32 time_us = 0, val, snr;
1887 u64 blocks, ucb;
1888 s32 db;
1889 u16 strength;
1890
1891 /* Get Signal strength */
1892 dib7000p_read_signal_strength(demod, &strength);
1893 val = strength;
1894 db = interpolate_value(val,
1895 strength_to_db_table,
1896 ARRAY_SIZE(strength_to_db_table)) - DB_OFFSET;
1897 c->strength.stat[0].svalue = db;
1898
Mauro Carvalho Chehab041ad442014-05-29 14:44:56 -03001899 /* UCB/BER/CNR measures require lock */
1900 if (!(stat & FE_HAS_LOCK)) {
1901 c->cnr.len = 1;
1902 c->block_count.len = 1;
1903 c->block_error.len = 1;
1904 c->post_bit_error.len = 1;
1905 c->post_bit_count.len = 1;
1906 c->cnr.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
1907 c->post_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
1908 c->post_bit_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
1909 c->block_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
1910 c->block_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
1911 return 0;
1912 }
1913
1914 /* Check if time for stats was elapsed */
1915 if (time_after(jiffies, state->per_jiffies_stats)) {
1916 state->per_jiffies_stats = jiffies + msecs_to_jiffies(1000);
1917
1918 /* Get SNR */
1919 snr = dib7000p_get_snr(demod);
1920 if (snr)
1921 snr = (1000L * snr) >> 24;
1922 else
1923 snr = 0;
1924 c->cnr.stat[0].svalue = snr;
1925 c->cnr.stat[0].scale = FE_SCALE_DECIBEL;
1926
1927 /* Get UCB measures */
1928 dib7000p_read_unc_blocks(demod, &val);
1929 ucb = val - state->old_ucb;
1930 if (val < state->old_ucb)
1931 ucb += 0x100000000LL;
1932
1933 c->block_error.stat[0].scale = FE_SCALE_COUNTER;
1934 c->block_error.stat[0].uvalue = ucb;
1935
1936 /* Estimate the number of packets based on bitrate */
1937 if (!time_us)
1938 time_us = dib7000p_get_time_us(demod, -1);
1939
1940 if (time_us) {
1941 blocks = 1250000ULL * 1000000ULL;
1942 do_div(blocks, time_us * 8 * 204);
1943 c->block_count.stat[0].scale = FE_SCALE_COUNTER;
1944 c->block_count.stat[0].uvalue += blocks;
1945 }
1946
1947 show_per_stats = 1;
1948 }
1949
1950 /* Get post-BER measures */
1951 if (time_after(jiffies, state->ber_jiffies_stats)) {
1952 time_us = dib7000p_get_time_us(demod, -1);
1953 state->ber_jiffies_stats = jiffies + msecs_to_jiffies((time_us + 500) / 1000);
1954
1955 dprintk("Next all layers stats available in %u us.", time_us);
1956
1957 dib7000p_read_ber(demod, &val);
1958 c->post_bit_error.stat[0].scale = FE_SCALE_COUNTER;
1959 c->post_bit_error.stat[0].uvalue += val;
1960
1961 c->post_bit_count.stat[0].scale = FE_SCALE_COUNTER;
1962 c->post_bit_count.stat[0].uvalue += 100000000;
1963 }
1964
1965 /* Get PER measures */
1966 if (show_per_stats) {
1967 dib7000p_read_unc_blocks(demod, &val);
1968
1969 c->block_error.stat[0].scale = FE_SCALE_COUNTER;
1970 c->block_error.stat[0].uvalue += val;
1971
1972 time_us = dib7000p_get_time_us(demod, i);
1973 if (time_us) {
1974 blocks = 1250000ULL * 1000000ULL;
1975 do_div(blocks, time_us * 8 * 204);
1976 c->block_count.stat[0].scale = FE_SCALE_COUNTER;
1977 c->block_count.stat[0].uvalue += blocks;
1978 }
1979 }
1980 return 0;
1981}
1982
Olivier Grenie713d54a2011-01-04 04:54:31 -03001983static int dib7000p_fe_get_tune_settings(struct dvb_frontend *fe, struct dvb_frontend_tune_settings *tune)
Patrick Boettchera75763f2006-10-18 08:34:16 -03001984{
1985 tune->min_delay_ms = 1000;
1986 return 0;
1987}
1988
1989static void dib7000p_release(struct dvb_frontend *demod)
1990{
1991 struct dib7000p_state *st = demod->demodulator_priv;
1992 dibx000_exit_i2c_master(&st->i2c_master);
Olivier Grenie713d54a2011-01-04 04:54:31 -03001993 i2c_del_adapter(&st->dib7090_tuner_adap);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001994 kfree(st);
1995}
1996
Mauro Carvalho Chehab8abe4a02014-05-29 09:20:15 -03001997static int dib7000pc_detection(struct i2c_adapter *i2c_adap)
Patrick Boettchera75763f2006-10-18 08:34:16 -03001998{
Olivier Grenie5a0deee2011-05-03 12:27:33 -03001999 u8 *tx, *rx;
Patrick Boettchera75763f2006-10-18 08:34:16 -03002000 struct i2c_msg msg[2] = {
Olivier Grenie5a0deee2011-05-03 12:27:33 -03002001 {.addr = 18 >> 1, .flags = 0, .len = 2},
2002 {.addr = 18 >> 1, .flags = I2C_M_RD, .len = 2},
Patrick Boettchera75763f2006-10-18 08:34:16 -03002003 };
Olivier Grenie5a0deee2011-05-03 12:27:33 -03002004 int ret = 0;
2005
2006 tx = kzalloc(2*sizeof(u8), GFP_KERNEL);
2007 if (!tx)
2008 return -ENOMEM;
2009 rx = kzalloc(2*sizeof(u8), GFP_KERNEL);
2010 if (!rx) {
Olivier Grenie5a0deee2011-05-03 12:27:33 -03002011 ret = -ENOMEM;
Dan Carpenter0c61cc3b2011-08-06 05:00:34 -03002012 goto rx_memory_error;
Olivier Grenie5a0deee2011-05-03 12:27:33 -03002013 }
2014
2015 msg[0].buf = tx;
2016 msg[1].buf = rx;
Patrick Boettchera75763f2006-10-18 08:34:16 -03002017
2018 tx[0] = 0x03;
2019 tx[1] = 0x00;
2020
2021 if (i2c_transfer(i2c_adap, msg, 2) == 2)
2022 if (rx[0] == 0x01 && rx[1] == 0xb3) {
Patrick Boettcherb6884a12007-07-27 10:08:51 -03002023 dprintk("-D- DiB7000PC detected");
Patrick Boettchera75763f2006-10-18 08:34:16 -03002024 return 1;
2025 }
2026
2027 msg[0].addr = msg[1].addr = 0x40;
2028
2029 if (i2c_transfer(i2c_adap, msg, 2) == 2)
2030 if (rx[0] == 0x01 && rx[1] == 0xb3) {
Patrick Boettcherb6884a12007-07-27 10:08:51 -03002031 dprintk("-D- DiB7000PC detected");
Patrick Boettchera75763f2006-10-18 08:34:16 -03002032 return 1;
2033 }
2034
Patrick Boettcherb6884a12007-07-27 10:08:51 -03002035 dprintk("-D- DiB7000PC not detected");
Olivier Grenie5a0deee2011-05-03 12:27:33 -03002036
2037 kfree(rx);
2038rx_memory_error:
2039 kfree(tx);
2040 return ret;
Patrick Boettchera75763f2006-10-18 08:34:16 -03002041}
Patrick Boettchera75763f2006-10-18 08:34:16 -03002042
Mauro Carvalho Chehab8abe4a02014-05-29 09:20:15 -03002043static struct i2c_adapter *dib7000p_get_i2c_master(struct dvb_frontend *demod, enum dibx000_i2c_interface intf, int gating)
Patrick Boettchera75763f2006-10-18 08:34:16 -03002044{
2045 struct dib7000p_state *st = demod->demodulator_priv;
2046 return dibx000_get_i2c_adapter(&st->i2c_master, intf, gating);
2047}
Patrick Boettchera75763f2006-10-18 08:34:16 -03002048
Mauro Carvalho Chehab8abe4a02014-05-29 09:20:15 -03002049static int dib7000p_pid_filter_ctrl(struct dvb_frontend *fe, u8 onoff)
Olivier Grenief8731f42009-09-18 04:08:43 -03002050{
Olivier Grenie713d54a2011-01-04 04:54:31 -03002051 struct dib7000p_state *state = fe->demodulator_priv;
2052 u16 val = dib7000p_read_word(state, 235) & 0xffef;
2053 val |= (onoff & 0x1) << 4;
2054 dprintk("PID filter enabled %d", onoff);
2055 return dib7000p_write_word(state, 235, val);
Olivier Grenief8731f42009-09-18 04:08:43 -03002056}
Olivier Grenief8731f42009-09-18 04:08:43 -03002057
Mauro Carvalho Chehab8abe4a02014-05-29 09:20:15 -03002058static int dib7000p_pid_filter(struct dvb_frontend *fe, u8 id, u16 pid, u8 onoff)
Olivier Grenief8731f42009-09-18 04:08:43 -03002059{
Olivier Grenie713d54a2011-01-04 04:54:31 -03002060 struct dib7000p_state *state = fe->demodulator_priv;
2061 dprintk("PID filter: index %x, PID %d, OnOff %d", id, pid, onoff);
2062 return dib7000p_write_word(state, 241 + id, onoff ? (1 << 13) | pid : 0);
Olivier Grenief8731f42009-09-18 04:08:43 -03002063}
Olivier Grenief8731f42009-09-18 04:08:43 -03002064
Mauro Carvalho Chehab8abe4a02014-05-29 09:20:15 -03002065static int dib7000p_i2c_enumeration(struct i2c_adapter *i2c, int no_of_demods, u8 default_addr, struct dib7000p_config cfg[])
Patrick Boettchera75763f2006-10-18 08:34:16 -03002066{
Randy Dunlap30d81bb2010-02-08 20:30:44 -03002067 struct dib7000p_state *dpst;
Patrick Boettchera75763f2006-10-18 08:34:16 -03002068 int k = 0;
2069 u8 new_addr = 0;
2070
Randy Dunlap30d81bb2010-02-08 20:30:44 -03002071 dpst = kzalloc(sizeof(struct dib7000p_state), GFP_KERNEL);
2072 if (!dpst)
Andrew Morton0b427602010-04-27 19:09:45 -03002073 return -ENOMEM;
Randy Dunlap30d81bb2010-02-08 20:30:44 -03002074
2075 dpst->i2c_adap = i2c;
Patrick Boettcher79fcce32011-08-03 12:08:21 -03002076 mutex_init(&dpst->i2c_buffer_lock);
Randy Dunlap30d81bb2010-02-08 20:30:44 -03002077
Olivier Grenie713d54a2011-01-04 04:54:31 -03002078 for (k = no_of_demods - 1; k >= 0; k--) {
Randy Dunlap30d81bb2010-02-08 20:30:44 -03002079 dpst->cfg = cfg[k];
Patrick Boettchera75763f2006-10-18 08:34:16 -03002080
2081 /* designated i2c address */
Olivier Grenie713d54a2011-01-04 04:54:31 -03002082 if (cfg[k].default_i2c_addr != 0)
2083 new_addr = cfg[k].default_i2c_addr + (k << 1);
2084 else
2085 new_addr = (0x40 + k) << 1;
Randy Dunlap30d81bb2010-02-08 20:30:44 -03002086 dpst->i2c_addr = new_addr;
Olivier Grenie713d54a2011-01-04 04:54:31 -03002087 dib7000p_write_word(dpst, 1287, 0x0003); /* sram lead in, rdy */
Randy Dunlap30d81bb2010-02-08 20:30:44 -03002088 if (dib7000p_identify(dpst) != 0) {
2089 dpst->i2c_addr = default_addr;
Olivier Grenie713d54a2011-01-04 04:54:31 -03002090 dib7000p_write_word(dpst, 1287, 0x0003); /* sram lead in, rdy */
Randy Dunlap30d81bb2010-02-08 20:30:44 -03002091 if (dib7000p_identify(dpst) != 0) {
Patrick Boettchera75763f2006-10-18 08:34:16 -03002092 dprintk("DiB7000P #%d: not identified\n", k);
Randy Dunlap30d81bb2010-02-08 20:30:44 -03002093 kfree(dpst);
Patrick Boettchera75763f2006-10-18 08:34:16 -03002094 return -EIO;
2095 }
2096 }
2097
2098 /* start diversity to pull_down div_str - just for i2c-enumeration */
Randy Dunlap30d81bb2010-02-08 20:30:44 -03002099 dib7000p_set_output_mode(dpst, OUTMODE_DIVERSITY);
Patrick Boettchera75763f2006-10-18 08:34:16 -03002100
2101 /* set new i2c address and force divstart */
Randy Dunlap30d81bb2010-02-08 20:30:44 -03002102 dib7000p_write_word(dpst, 1285, (new_addr << 2) | 0x2);
Patrick Boettchera75763f2006-10-18 08:34:16 -03002103
Patrick Boettcherb6884a12007-07-27 10:08:51 -03002104 dprintk("IC %d initialized (to i2c_address 0x%x)", k, new_addr);
Patrick Boettchera75763f2006-10-18 08:34:16 -03002105 }
2106
2107 for (k = 0; k < no_of_demods; k++) {
Randy Dunlap30d81bb2010-02-08 20:30:44 -03002108 dpst->cfg = cfg[k];
Olivier Grenie713d54a2011-01-04 04:54:31 -03002109 if (cfg[k].default_i2c_addr != 0)
2110 dpst->i2c_addr = (cfg[k].default_i2c_addr + k) << 1;
2111 else
2112 dpst->i2c_addr = (0x40 + k) << 1;
Patrick Boettchera75763f2006-10-18 08:34:16 -03002113
2114 // unforce divstr
Randy Dunlap30d81bb2010-02-08 20:30:44 -03002115 dib7000p_write_word(dpst, 1285, dpst->i2c_addr << 2);
Patrick Boettchera75763f2006-10-18 08:34:16 -03002116
2117 /* deactivate div - it was just for i2c-enumeration */
Randy Dunlap30d81bb2010-02-08 20:30:44 -03002118 dib7000p_set_output_mode(dpst, OUTMODE_HIGH_Z);
Patrick Boettchera75763f2006-10-18 08:34:16 -03002119 }
2120
Randy Dunlap30d81bb2010-02-08 20:30:44 -03002121 kfree(dpst);
Patrick Boettchera75763f2006-10-18 08:34:16 -03002122 return 0;
2123}
Patrick Boettchera75763f2006-10-18 08:34:16 -03002124
Olivier Grenie713d54a2011-01-04 04:54:31 -03002125static const s32 lut_1000ln_mant[] = {
2126 6908, 6956, 7003, 7047, 7090, 7131, 7170, 7208, 7244, 7279, 7313, 7346, 7377, 7408, 7438, 7467, 7495, 7523, 7549, 7575, 7600
2127};
2128
2129static s32 dib7000p_get_adc_power(struct dvb_frontend *fe)
2130{
2131 struct dib7000p_state *state = fe->demodulator_priv;
2132 u32 tmp_val = 0, exp = 0, mant = 0;
2133 s32 pow_i;
2134 u16 buf[2];
2135 u8 ix = 0;
2136
2137 buf[0] = dib7000p_read_word(state, 0x184);
2138 buf[1] = dib7000p_read_word(state, 0x185);
2139 pow_i = (buf[0] << 16) | buf[1];
2140 dprintk("raw pow_i = %d", pow_i);
2141
2142 tmp_val = pow_i;
2143 while (tmp_val >>= 1)
2144 exp++;
2145
2146 mant = (pow_i * 1000 / (1 << exp));
2147 dprintk(" mant = %d exp = %d", mant / 1000, exp);
2148
2149 ix = (u8) ((mant - 1000) / 100); /* index of the LUT */
2150 dprintk(" ix = %d", ix);
2151
2152 pow_i = (lut_1000ln_mant[ix] + 693 * (exp - 20) - 6908);
2153 pow_i = (pow_i << 8) / 1000;
2154 dprintk(" pow_i = %d", pow_i);
2155
2156 return pow_i;
2157}
2158
2159static int map_addr_to_serpar_number(struct i2c_msg *msg)
2160{
2161 if ((msg->buf[0] <= 15))
2162 msg->buf[0] -= 1;
2163 else if (msg->buf[0] == 17)
2164 msg->buf[0] = 15;
2165 else if (msg->buf[0] == 16)
2166 msg->buf[0] = 17;
2167 else if (msg->buf[0] == 19)
2168 msg->buf[0] = 16;
2169 else if (msg->buf[0] >= 21 && msg->buf[0] <= 25)
2170 msg->buf[0] -= 3;
2171 else if (msg->buf[0] == 28)
2172 msg->buf[0] = 23;
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002173 else
Olivier Grenie713d54a2011-01-04 04:54:31 -03002174 return -EINVAL;
Olivier Grenie713d54a2011-01-04 04:54:31 -03002175 return 0;
2176}
2177
2178static int w7090p_tuner_write_serpar(struct i2c_adapter *i2c_adap, struct i2c_msg msg[], int num)
2179{
2180 struct dib7000p_state *state = i2c_get_adapdata(i2c_adap);
2181 u8 n_overflow = 1;
2182 u16 i = 1000;
2183 u16 serpar_num = msg[0].buf[0];
2184
2185 while (n_overflow == 1 && i) {
2186 n_overflow = (dib7000p_read_word(state, 1984) >> 1) & 0x1;
2187 i--;
2188 if (i == 0)
2189 dprintk("Tuner ITF: write busy (overflow)");
2190 }
2191 dib7000p_write_word(state, 1985, (1 << 6) | (serpar_num & 0x3f));
2192 dib7000p_write_word(state, 1986, (msg[0].buf[1] << 8) | msg[0].buf[2]);
2193
2194 return num;
2195}
2196
2197static int w7090p_tuner_read_serpar(struct i2c_adapter *i2c_adap, struct i2c_msg msg[], int num)
2198{
2199 struct dib7000p_state *state = i2c_get_adapdata(i2c_adap);
2200 u8 n_overflow = 1, n_empty = 1;
2201 u16 i = 1000;
2202 u16 serpar_num = msg[0].buf[0];
2203 u16 read_word;
2204
2205 while (n_overflow == 1 && i) {
2206 n_overflow = (dib7000p_read_word(state, 1984) >> 1) & 0x1;
2207 i--;
2208 if (i == 0)
2209 dprintk("TunerITF: read busy (overflow)");
2210 }
2211 dib7000p_write_word(state, 1985, (0 << 6) | (serpar_num & 0x3f));
2212
2213 i = 1000;
2214 while (n_empty == 1 && i) {
2215 n_empty = dib7000p_read_word(state, 1984) & 0x1;
2216 i--;
2217 if (i == 0)
2218 dprintk("TunerITF: read busy (empty)");
2219 }
2220 read_word = dib7000p_read_word(state, 1987);
2221 msg[1].buf[0] = (read_word >> 8) & 0xff;
2222 msg[1].buf[1] = (read_word) & 0xff;
2223
2224 return num;
2225}
2226
2227static int w7090p_tuner_rw_serpar(struct i2c_adapter *i2c_adap, struct i2c_msg msg[], int num)
2228{
2229 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... */
2230 if (num == 1) { /* write */
2231 return w7090p_tuner_write_serpar(i2c_adap, msg, 1);
2232 } else { /* read */
2233 return w7090p_tuner_read_serpar(i2c_adap, msg, 2);
2234 }
2235 }
2236 return num;
2237}
2238
Olivier Greniea685dbb2011-08-05 14:10:40 -03002239static int dib7090p_rw_on_apb(struct i2c_adapter *i2c_adap,
2240 struct i2c_msg msg[], int num, u16 apb_address)
Olivier Grenie713d54a2011-01-04 04:54:31 -03002241{
2242 struct dib7000p_state *state = i2c_get_adapdata(i2c_adap);
2243 u16 word;
2244
2245 if (num == 1) { /* write */
2246 dib7000p_write_word(state, apb_address, ((msg[0].buf[1] << 8) | (msg[0].buf[2])));
2247 } else {
2248 word = dib7000p_read_word(state, apb_address);
2249 msg[1].buf[0] = (word >> 8) & 0xff;
2250 msg[1].buf[1] = (word) & 0xff;
2251 }
2252
2253 return num;
2254}
2255
2256static int dib7090_tuner_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg msg[], int num)
2257{
2258 struct dib7000p_state *state = i2c_get_adapdata(i2c_adap);
2259
2260 u16 apb_address = 0, word;
2261 int i = 0;
2262 switch (msg[0].buf[0]) {
2263 case 0x12:
2264 apb_address = 1920;
2265 break;
2266 case 0x14:
2267 apb_address = 1921;
2268 break;
2269 case 0x24:
2270 apb_address = 1922;
2271 break;
2272 case 0x1a:
2273 apb_address = 1923;
2274 break;
2275 case 0x22:
2276 apb_address = 1924;
2277 break;
2278 case 0x33:
2279 apb_address = 1926;
2280 break;
2281 case 0x34:
2282 apb_address = 1927;
2283 break;
2284 case 0x35:
2285 apb_address = 1928;
2286 break;
2287 case 0x36:
2288 apb_address = 1929;
2289 break;
2290 case 0x37:
2291 apb_address = 1930;
2292 break;
2293 case 0x38:
2294 apb_address = 1931;
2295 break;
2296 case 0x39:
2297 apb_address = 1932;
2298 break;
2299 case 0x2a:
2300 apb_address = 1935;
2301 break;
2302 case 0x2b:
2303 apb_address = 1936;
2304 break;
2305 case 0x2c:
2306 apb_address = 1937;
2307 break;
2308 case 0x2d:
2309 apb_address = 1938;
2310 break;
2311 case 0x2e:
2312 apb_address = 1939;
2313 break;
2314 case 0x2f:
2315 apb_address = 1940;
2316 break;
2317 case 0x30:
2318 apb_address = 1941;
2319 break;
2320 case 0x31:
2321 apb_address = 1942;
2322 break;
2323 case 0x32:
2324 apb_address = 1943;
2325 break;
2326 case 0x3e:
2327 apb_address = 1944;
2328 break;
2329 case 0x3f:
2330 apb_address = 1945;
2331 break;
2332 case 0x40:
2333 apb_address = 1948;
2334 break;
2335 case 0x25:
2336 apb_address = 914;
2337 break;
2338 case 0x26:
2339 apb_address = 915;
2340 break;
2341 case 0x27:
Olivier Grenie2e802862011-08-05 10:39:15 -03002342 apb_address = 917;
Olivier Grenie713d54a2011-01-04 04:54:31 -03002343 break;
2344 case 0x28:
Olivier Grenie2e802862011-08-05 10:39:15 -03002345 apb_address = 916;
Olivier Grenie713d54a2011-01-04 04:54:31 -03002346 break;
2347 case 0x1d:
2348 i = ((dib7000p_read_word(state, 72) >> 12) & 0x3);
2349 word = dib7000p_read_word(state, 384 + i);
2350 msg[1].buf[0] = (word >> 8) & 0xff;
2351 msg[1].buf[1] = (word) & 0xff;
2352 return num;
2353 case 0x1f:
2354 if (num == 1) { /* write */
2355 word = (u16) ((msg[0].buf[1] << 8) | msg[0].buf[2]);
2356 word &= 0x3;
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002357 word = (dib7000p_read_word(state, 72) & ~(3 << 12)) | (word << 12);
Olivier Grenie713d54a2011-01-04 04:54:31 -03002358 dib7000p_write_word(state, 72, word); /* Set the proper input */
2359 return num;
2360 }
2361 }
2362
2363 if (apb_address != 0) /* R/W acces via APB */
2364 return dib7090p_rw_on_apb(i2c_adap, msg, num, apb_address);
2365 else /* R/W access via SERPAR */
2366 return w7090p_tuner_rw_serpar(i2c_adap, msg, num);
2367
2368 return 0;
2369}
2370
2371static u32 dib7000p_i2c_func(struct i2c_adapter *adapter)
2372{
2373 return I2C_FUNC_I2C;
2374}
2375
2376static struct i2c_algorithm dib7090_tuner_xfer_algo = {
2377 .master_xfer = dib7090_tuner_xfer,
2378 .functionality = dib7000p_i2c_func,
2379};
2380
Mauro Carvalho Chehab8abe4a02014-05-29 09:20:15 -03002381static struct i2c_adapter *dib7090_get_i2c_tuner(struct dvb_frontend *fe)
Olivier Grenie713d54a2011-01-04 04:54:31 -03002382{
2383 struct dib7000p_state *st = fe->demodulator_priv;
2384 return &st->dib7090_tuner_adap;
2385}
Olivier Grenie713d54a2011-01-04 04:54:31 -03002386
2387static int dib7090_host_bus_drive(struct dib7000p_state *state, u8 drive)
2388{
2389 u16 reg;
2390
2391 /* drive host bus 2, 3, 4 */
2392 reg = dib7000p_read_word(state, 1798) & ~((0x7) | (0x7 << 6) | (0x7 << 12));
2393 reg |= (drive << 12) | (drive << 6) | drive;
2394 dib7000p_write_word(state, 1798, reg);
2395
2396 /* drive host bus 5,6 */
2397 reg = dib7000p_read_word(state, 1799) & ~((0x7 << 2) | (0x7 << 8));
2398 reg |= (drive << 8) | (drive << 2);
2399 dib7000p_write_word(state, 1799, reg);
2400
2401 /* drive host bus 7, 8, 9 */
2402 reg = dib7000p_read_word(state, 1800) & ~((0x7) | (0x7 << 6) | (0x7 << 12));
2403 reg |= (drive << 12) | (drive << 6) | drive;
2404 dib7000p_write_word(state, 1800, reg);
2405
2406 /* drive host bus 10, 11 */
2407 reg = dib7000p_read_word(state, 1801) & ~((0x7 << 2) | (0x7 << 8));
2408 reg |= (drive << 8) | (drive << 2);
2409 dib7000p_write_word(state, 1801, reg);
2410
2411 /* drive host bus 12, 13, 14 */
2412 reg = dib7000p_read_word(state, 1802) & ~((0x7) | (0x7 << 6) | (0x7 << 12));
2413 reg |= (drive << 12) | (drive << 6) | drive;
2414 dib7000p_write_word(state, 1802, reg);
2415
2416 return 0;
2417}
2418
2419static u32 dib7090_calcSyncFreq(u32 P_Kin, u32 P_Kout, u32 insertExtSynchro, u32 syncSize)
2420{
2421 u32 quantif = 3;
2422 u32 nom = (insertExtSynchro * P_Kin + syncSize);
2423 u32 denom = P_Kout;
2424 u32 syncFreq = ((nom << quantif) / denom);
2425
2426 if ((syncFreq & ((1 << quantif) - 1)) != 0)
2427 syncFreq = (syncFreq >> quantif) + 1;
2428 else
2429 syncFreq = (syncFreq >> quantif);
2430
2431 if (syncFreq != 0)
2432 syncFreq = syncFreq - 1;
2433
2434 return syncFreq;
2435}
2436
2437static int dib7090_cfg_DibTx(struct dib7000p_state *state, u32 P_Kin, u32 P_Kout, u32 insertExtSynchro, u32 synchroMode, u32 syncWord, u32 syncSize)
2438{
Olivier Grenie713d54a2011-01-04 04:54:31 -03002439 dprintk("Configure DibStream Tx");
Olivier Grenie713d54a2011-01-04 04:54:31 -03002440
2441 dib7000p_write_word(state, 1615, 1);
2442 dib7000p_write_word(state, 1603, P_Kin);
2443 dib7000p_write_word(state, 1605, P_Kout);
2444 dib7000p_write_word(state, 1606, insertExtSynchro);
2445 dib7000p_write_word(state, 1608, synchroMode);
2446 dib7000p_write_word(state, 1609, (syncWord >> 16) & 0xffff);
2447 dib7000p_write_word(state, 1610, syncWord & 0xffff);
2448 dib7000p_write_word(state, 1612, syncSize);
2449 dib7000p_write_word(state, 1615, 0);
2450
Olivier Grenie713d54a2011-01-04 04:54:31 -03002451 return 0;
2452}
2453
2454static int dib7090_cfg_DibRx(struct dib7000p_state *state, u32 P_Kin, u32 P_Kout, u32 synchroMode, u32 insertExtSynchro, u32 syncWord, u32 syncSize,
2455 u32 dataOutRate)
2456{
2457 u32 syncFreq;
2458
2459 dprintk("Configure DibStream Rx");
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002460 if ((P_Kin != 0) && (P_Kout != 0)) {
Olivier Grenie713d54a2011-01-04 04:54:31 -03002461 syncFreq = dib7090_calcSyncFreq(P_Kin, P_Kout, insertExtSynchro, syncSize);
2462 dib7000p_write_word(state, 1542, syncFreq);
2463 }
2464 dib7000p_write_word(state, 1554, 1);
2465 dib7000p_write_word(state, 1536, P_Kin);
2466 dib7000p_write_word(state, 1537, P_Kout);
2467 dib7000p_write_word(state, 1539, synchroMode);
2468 dib7000p_write_word(state, 1540, (syncWord >> 16) & 0xffff);
2469 dib7000p_write_word(state, 1541, syncWord & 0xffff);
2470 dib7000p_write_word(state, 1543, syncSize);
2471 dib7000p_write_word(state, 1544, dataOutRate);
2472 dib7000p_write_word(state, 1554, 0);
2473
2474 return 0;
2475}
2476
Olivier Grenie2e802862011-08-05 10:39:15 -03002477static void dib7090_enMpegMux(struct dib7000p_state *state, int onoff)
Olivier Grenie713d54a2011-01-04 04:54:31 -03002478{
Olivier Grenie2e802862011-08-05 10:39:15 -03002479 u16 reg_1287 = dib7000p_read_word(state, 1287);
Olivier Grenie713d54a2011-01-04 04:54:31 -03002480
Olivier Grenie2e802862011-08-05 10:39:15 -03002481 switch (onoff) {
2482 case 1:
2483 reg_1287 &= ~(1<<7);
2484 break;
2485 case 0:
2486 reg_1287 |= (1<<7);
2487 break;
2488 }
Olivier Grenie713d54a2011-01-04 04:54:31 -03002489
Olivier Grenie2e802862011-08-05 10:39:15 -03002490 dib7000p_write_word(state, 1287, reg_1287);
Olivier Grenie713d54a2011-01-04 04:54:31 -03002491}
2492
Olivier Grenie2e802862011-08-05 10:39:15 -03002493static void dib7090_configMpegMux(struct dib7000p_state *state,
2494 u16 pulseWidth, u16 enSerialMode, u16 enSerialClkDiv2)
Olivier Grenie713d54a2011-01-04 04:54:31 -03002495{
Olivier Grenie713d54a2011-01-04 04:54:31 -03002496 dprintk("Enable Mpeg mux");
Olivier Grenie713d54a2011-01-04 04:54:31 -03002497
Olivier Grenie2e802862011-08-05 10:39:15 -03002498 dib7090_enMpegMux(state, 0);
Olivier Grenie713d54a2011-01-04 04:54:31 -03002499
Olivier Grenie2e802862011-08-05 10:39:15 -03002500 /* If the input mode is MPEG do not divide the serial clock */
2501 if ((enSerialMode == 1) && (state->input_mode_mpeg == 1))
2502 enSerialClkDiv2 = 0;
Olivier Grenie713d54a2011-01-04 04:54:31 -03002503
Olivier Grenie2e802862011-08-05 10:39:15 -03002504 dib7000p_write_word(state, 1287, ((pulseWidth & 0x1f) << 2)
2505 | ((enSerialMode & 0x1) << 1)
2506 | (enSerialClkDiv2 & 0x1));
2507
2508 dib7090_enMpegMux(state, 1);
Olivier Grenie713d54a2011-01-04 04:54:31 -03002509}
2510
Olivier Grenie2e802862011-08-05 10:39:15 -03002511static void dib7090_setDibTxMux(struct dib7000p_state *state, int mode)
Olivier Grenie713d54a2011-01-04 04:54:31 -03002512{
Olivier Grenie2e802862011-08-05 10:39:15 -03002513 u16 reg_1288 = dib7000p_read_word(state, 1288) & ~(0x7 << 7);
Olivier Grenie713d54a2011-01-04 04:54:31 -03002514
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002515 switch (mode) {
Olivier Grenie2e802862011-08-05 10:39:15 -03002516 case MPEG_ON_DIBTX:
2517 dprintk("SET MPEG ON DIBSTREAM TX");
2518 dib7090_cfg_DibTx(state, 8, 5, 0, 0, 0, 0);
2519 reg_1288 |= (1<<9);
Olivier Grenie713d54a2011-01-04 04:54:31 -03002520 break;
Olivier Grenie2e802862011-08-05 10:39:15 -03002521 case DIV_ON_DIBTX:
2522 dprintk("SET DIV_OUT ON DIBSTREAM TX");
2523 dib7090_cfg_DibTx(state, 5, 5, 0, 0, 0, 0);
2524 reg_1288 |= (1<<8);
Olivier Grenie713d54a2011-01-04 04:54:31 -03002525 break;
Olivier Grenie2e802862011-08-05 10:39:15 -03002526 case ADC_ON_DIBTX:
2527 dprintk("SET ADC_OUT ON DIBSTREAM TX");
2528 dib7090_cfg_DibTx(state, 20, 5, 10, 0, 0, 0);
2529 reg_1288 |= (1<<7);
2530 break;
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002531 default:
Olivier Grenie713d54a2011-01-04 04:54:31 -03002532 break;
2533 }
Olivier Grenie2e802862011-08-05 10:39:15 -03002534 dib7000p_write_word(state, 1288, reg_1288);
Olivier Grenie713d54a2011-01-04 04:54:31 -03002535}
2536
Olivier Grenie2e802862011-08-05 10:39:15 -03002537static void dib7090_setHostBusMux(struct dib7000p_state *state, int mode)
Olivier Grenie713d54a2011-01-04 04:54:31 -03002538{
Olivier Grenie2e802862011-08-05 10:39:15 -03002539 u16 reg_1288 = dib7000p_read_word(state, 1288) & ~(0x7 << 4);
2540
2541 switch (mode) {
2542 case DEMOUT_ON_HOSTBUS:
2543 dprintk("SET DEM OUT OLD INTERF ON HOST BUS");
2544 dib7090_enMpegMux(state, 0);
2545 reg_1288 |= (1<<6);
2546 break;
2547 case DIBTX_ON_HOSTBUS:
2548 dprintk("SET DIBSTREAM TX ON HOST BUS");
2549 dib7090_enMpegMux(state, 0);
2550 reg_1288 |= (1<<5);
2551 break;
2552 case MPEG_ON_HOSTBUS:
2553 dprintk("SET MPEG MUX ON HOST BUS");
2554 reg_1288 |= (1<<4);
2555 break;
2556 default:
2557 break;
2558 }
2559 dib7000p_write_word(state, 1288, reg_1288);
2560}
2561
Hans Verkuil18ef20d2014-08-20 16:58:35 -03002562static int dib7090_set_diversity_in(struct dvb_frontend *fe, int onoff)
Olivier Grenie2e802862011-08-05 10:39:15 -03002563{
2564 struct dib7000p_state *state = fe->demodulator_priv;
2565 u16 reg_1287;
2566
Olivier Grenie713d54a2011-01-04 04:54:31 -03002567 switch (onoff) {
Olivier Grenie2e802862011-08-05 10:39:15 -03002568 case 0: /* only use the internal way - not the diversity input */
2569 dprintk("%s mode OFF : by default Enable Mpeg INPUT", __func__);
2570 dib7090_cfg_DibRx(state, 8, 5, 0, 0, 0, 8, 0);
2571
2572 /* Do not divide the serial clock of MPEG MUX */
2573 /* in SERIAL MODE in case input mode MPEG is used */
2574 reg_1287 = dib7000p_read_word(state, 1287);
2575 /* enSerialClkDiv2 == 1 ? */
2576 if ((reg_1287 & 0x1) == 1) {
2577 /* force enSerialClkDiv2 = 0 */
2578 reg_1287 &= ~0x1;
2579 dib7000p_write_word(state, 1287, reg_1287);
2580 }
2581 state->input_mode_mpeg = 1;
2582 break;
2583 case 1: /* both ways */
2584 case 2: /* only the diversity input */
2585 dprintk("%s ON : Enable diversity INPUT", __func__);
2586 dib7090_cfg_DibRx(state, 5, 5, 0, 0, 0, 0, 0);
2587 state->input_mode_mpeg = 0;
2588 break;
Olivier Grenie713d54a2011-01-04 04:54:31 -03002589 }
2590
Olivier Grenie2e802862011-08-05 10:39:15 -03002591 dib7000p_set_diversity_in(&state->demod, onoff);
Olivier Grenie713d54a2011-01-04 04:54:31 -03002592 return 0;
2593}
2594
2595static int dib7090_set_output_mode(struct dvb_frontend *fe, int mode)
2596{
2597 struct dib7000p_state *state = fe->demodulator_priv;
2598
2599 u16 outreg, smo_mode, fifo_threshold;
2600 u8 prefer_mpeg_mux_use = 1;
2601 int ret = 0;
2602
2603 dib7090_host_bus_drive(state, 1);
2604
2605 fifo_threshold = 1792;
2606 smo_mode = (dib7000p_read_word(state, 235) & 0x0050) | (1 << 1);
2607 outreg = dib7000p_read_word(state, 1286) & ~((1 << 10) | (0x7 << 6) | (1 << 1));
2608
2609 switch (mode) {
2610 case OUTMODE_HIGH_Z:
2611 outreg = 0;
2612 break;
2613
2614 case OUTMODE_MPEG2_SERIAL:
2615 if (prefer_mpeg_mux_use) {
Olivier Grenie2e802862011-08-05 10:39:15 -03002616 dprintk("setting output mode TS_SERIAL using Mpeg Mux");
2617 dib7090_configMpegMux(state, 3, 1, 1);
2618 dib7090_setHostBusMux(state, MPEG_ON_HOSTBUS);
2619 } else {/* Use Smooth block */
2620 dprintk("setting output mode TS_SERIAL using Smooth bloc");
2621 dib7090_setHostBusMux(state, DEMOUT_ON_HOSTBUS);
2622 outreg |= (2<<6) | (0 << 1);
Olivier Grenie713d54a2011-01-04 04:54:31 -03002623 }
2624 break;
2625
2626 case OUTMODE_MPEG2_PAR_GATED_CLK:
2627 if (prefer_mpeg_mux_use) {
Olivier Grenie2e802862011-08-05 10:39:15 -03002628 dprintk("setting output mode TS_PARALLEL_GATED using Mpeg Mux");
2629 dib7090_configMpegMux(state, 2, 0, 0);
2630 dib7090_setHostBusMux(state, MPEG_ON_HOSTBUS);
2631 } else { /* Use Smooth block */
2632 dprintk("setting output mode TS_PARALLEL_GATED using Smooth block");
2633 dib7090_setHostBusMux(state, DEMOUT_ON_HOSTBUS);
2634 outreg |= (0<<6);
Olivier Grenie713d54a2011-01-04 04:54:31 -03002635 }
2636 break;
2637
2638 case OUTMODE_MPEG2_PAR_CONT_CLK: /* Using Smooth block only */
Olivier Grenie2e802862011-08-05 10:39:15 -03002639 dprintk("setting output mode TS_PARALLEL_CONT using Smooth block");
2640 dib7090_setHostBusMux(state, DEMOUT_ON_HOSTBUS);
2641 outreg |= (1<<6);
Olivier Grenie713d54a2011-01-04 04:54:31 -03002642 break;
2643
2644 case OUTMODE_MPEG2_FIFO: /* Using Smooth block because not supported by new Mpeg Mux bloc */
Olivier Grenie2e802862011-08-05 10:39:15 -03002645 dprintk("setting output mode TS_FIFO using Smooth block");
2646 dib7090_setHostBusMux(state, DEMOUT_ON_HOSTBUS);
2647 outreg |= (5<<6);
Olivier Grenie713d54a2011-01-04 04:54:31 -03002648 smo_mode |= (3 << 1);
2649 fifo_threshold = 512;
2650 break;
2651
2652 case OUTMODE_DIVERSITY:
Olivier Grenie2e802862011-08-05 10:39:15 -03002653 dprintk("setting output mode MODE_DIVERSITY");
2654 dib7090_setDibTxMux(state, DIV_ON_DIBTX);
2655 dib7090_setHostBusMux(state, DIBTX_ON_HOSTBUS);
Olivier Grenie713d54a2011-01-04 04:54:31 -03002656 break;
2657
2658 case OUTMODE_ANALOG_ADC:
Olivier Grenie2e802862011-08-05 10:39:15 -03002659 dprintk("setting output mode MODE_ANALOG_ADC");
2660 dib7090_setDibTxMux(state, ADC_ON_DIBTX);
2661 dib7090_setHostBusMux(state, DIBTX_ON_HOSTBUS);
Olivier Grenie713d54a2011-01-04 04:54:31 -03002662 break;
2663 }
Olivier Grenie2e802862011-08-05 10:39:15 -03002664 if (mode != OUTMODE_HIGH_Z)
2665 outreg |= (1 << 10);
Olivier Grenie713d54a2011-01-04 04:54:31 -03002666
2667 if (state->cfg.output_mpeg2_in_188_bytes)
2668 smo_mode |= (1 << 5);
2669
2670 ret |= dib7000p_write_word(state, 235, smo_mode);
2671 ret |= dib7000p_write_word(state, 236, fifo_threshold); /* synchronous fread */
Olivier Grenie2e802862011-08-05 10:39:15 -03002672 ret |= dib7000p_write_word(state, 1286, outreg);
Olivier Grenie713d54a2011-01-04 04:54:31 -03002673
2674 return ret;
2675}
2676
Mauro Carvalho Chehab8abe4a02014-05-29 09:20:15 -03002677static int dib7090_tuner_sleep(struct dvb_frontend *fe, int onoff)
Olivier Grenie713d54a2011-01-04 04:54:31 -03002678{
2679 struct dib7000p_state *state = fe->demodulator_priv;
2680 u16 en_cur_state;
2681
2682 dprintk("sleep dib7090: %d", onoff);
2683
2684 en_cur_state = dib7000p_read_word(state, 1922);
2685
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002686 if (en_cur_state > 0xff)
Olivier Grenie713d54a2011-01-04 04:54:31 -03002687 state->tuner_enable = en_cur_state;
Olivier Grenie713d54a2011-01-04 04:54:31 -03002688
2689 if (onoff)
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002690 en_cur_state &= 0x00ff;
Olivier Grenie713d54a2011-01-04 04:54:31 -03002691 else {
2692 if (state->tuner_enable != 0)
2693 en_cur_state = state->tuner_enable;
2694 }
2695
2696 dib7000p_write_word(state, 1922, en_cur_state);
2697
2698 return 0;
2699}
Olivier Grenie713d54a2011-01-04 04:54:31 -03002700
Mauro Carvalho Chehab8abe4a02014-05-29 09:20:15 -03002701static int dib7090_get_adc_power(struct dvb_frontend *fe)
Olivier Grenie713d54a2011-01-04 04:54:31 -03002702{
2703 return dib7000p_get_adc_power(fe);
2704}
Olivier Grenie713d54a2011-01-04 04:54:31 -03002705
Mauro Carvalho Chehab8abe4a02014-05-29 09:20:15 -03002706static int dib7090_slave_reset(struct dvb_frontend *fe)
Olivier Grenie713d54a2011-01-04 04:54:31 -03002707{
2708 struct dib7000p_state *state = fe->demodulator_priv;
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002709 u16 reg;
Olivier Grenie713d54a2011-01-04 04:54:31 -03002710
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002711 reg = dib7000p_read_word(state, 1794);
2712 dib7000p_write_word(state, 1794, reg | (4 << 12));
Olivier Grenie713d54a2011-01-04 04:54:31 -03002713
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002714 dib7000p_write_word(state, 1032, 0xffff);
2715 return 0;
Olivier Grenie713d54a2011-01-04 04:54:31 -03002716}
Olivier Grenie713d54a2011-01-04 04:54:31 -03002717
Patrick Boettchera75763f2006-10-18 08:34:16 -03002718static struct dvb_frontend_ops dib7000p_ops;
Mauro Carvalho Chehab8abe4a02014-05-29 09:20:15 -03002719static struct dvb_frontend *dib7000p_init(struct i2c_adapter *i2c_adap, u8 i2c_addr, struct dib7000p_config *cfg)
Patrick Boettchera75763f2006-10-18 08:34:16 -03002720{
2721 struct dvb_frontend *demod;
2722 struct dib7000p_state *st;
2723 st = kzalloc(sizeof(struct dib7000p_state), GFP_KERNEL);
2724 if (st == NULL)
2725 return NULL;
2726
2727 memcpy(&st->cfg, cfg, sizeof(struct dib7000p_config));
2728 st->i2c_adap = i2c_adap;
2729 st->i2c_addr = i2c_addr;
2730 st->gpio_val = cfg->gpio_val;
2731 st->gpio_dir = cfg->gpio_dir;
2732
Steven Totha38d6e32008-04-22 15:37:01 -03002733 /* Ensure the output mode remains at the previous default if it's
2734 * not specifically set by the caller.
2735 */
Olivier Grenie713d54a2011-01-04 04:54:31 -03002736 if ((st->cfg.output_mode != OUTMODE_MPEG2_SERIAL) && (st->cfg.output_mode != OUTMODE_MPEG2_PAR_GATED_CLK))
Steven Totha38d6e32008-04-22 15:37:01 -03002737 st->cfg.output_mode = OUTMODE_MPEG2_FIFO;
2738
Olivier Grenie713d54a2011-01-04 04:54:31 -03002739 demod = &st->demod;
Patrick Boettchera75763f2006-10-18 08:34:16 -03002740 demod->demodulator_priv = st;
2741 memcpy(&st->demod.ops, &dib7000p_ops, sizeof(struct dvb_frontend_ops));
Patrick Boettcher79fcce32011-08-03 12:08:21 -03002742 mutex_init(&st->i2c_buffer_lock);
Patrick Boettchera75763f2006-10-18 08:34:16 -03002743
Olivier Grenie713d54a2011-01-04 04:54:31 -03002744 dib7000p_write_word(st, 1287, 0x0003); /* sram lead in, rdy */
Olivier Grenieeac1fe12009-09-23 13:41:27 -03002745
Patrick Boettchera75763f2006-10-18 08:34:16 -03002746 if (dib7000p_identify(st) != 0)
2747 goto error;
2748
Olivier Grenie713d54a2011-01-04 04:54:31 -03002749 st->version = dib7000p_read_word(st, 897);
2750
Martin Samek7646b9d2009-09-30 22:59:09 -03002751 /* FIXME: make sure the dev.parent field is initialized, or else
Patrick Boettcher79fcce32011-08-03 12:08:21 -03002752 request_firmware() will hit an OOPS (this should be moved somewhere
2753 more common) */
2754 st->i2c_master.gated_tuner_i2c_adap.dev.parent = i2c_adap->dev.parent;
Martin Samek7646b9d2009-09-30 22:59:09 -03002755
Patrick Boettchera75763f2006-10-18 08:34:16 -03002756 dibx000_init_i2c_master(&st->i2c_master, DIB7000P, st->i2c_adap, st->i2c_addr);
2757
Olivier Grenie713d54a2011-01-04 04:54:31 -03002758 /* init 7090 tuner adapter */
2759 strncpy(st->dib7090_tuner_adap.name, "DiB7090 tuner interface", sizeof(st->dib7090_tuner_adap.name));
2760 st->dib7090_tuner_adap.algo = &dib7090_tuner_xfer_algo;
2761 st->dib7090_tuner_adap.algo_data = NULL;
2762 st->dib7090_tuner_adap.dev.parent = st->i2c_adap->dev.parent;
2763 i2c_set_adapdata(&st->dib7090_tuner_adap, st);
2764 i2c_add_adapter(&st->dib7090_tuner_adap);
2765
Patrick Boettchera75763f2006-10-18 08:34:16 -03002766 dib7000p_demod_reset(st);
2767
Mauro Carvalho Chehab041ad442014-05-29 14:44:56 -03002768 dib7000p_reset_stats(demod);
2769
Olivier Grenie713d54a2011-01-04 04:54:31 -03002770 if (st->version == SOC7090) {
2771 dib7090_set_output_mode(demod, st->cfg.output_mode);
2772 dib7090_set_diversity_in(demod, 0);
2773 }
2774
Patrick Boettchera75763f2006-10-18 08:34:16 -03002775 return demod;
2776
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002777error:
Patrick Boettchera75763f2006-10-18 08:34:16 -03002778 kfree(st);
2779 return NULL;
2780}
Mauro Carvalho Chehab8abe4a02014-05-29 09:20:15 -03002781
2782void *dib7000p_attach(struct dib7000p_ops *ops)
2783{
2784 if (!ops)
2785 return NULL;
2786
2787 ops->slave_reset = dib7090_slave_reset;
2788 ops->get_adc_power = dib7090_get_adc_power;
2789 ops->dib7000pc_detection = dib7000pc_detection;
2790 ops->get_i2c_tuner = dib7090_get_i2c_tuner;
2791 ops->tuner_sleep = dib7090_tuner_sleep;
2792 ops->init = dib7000p_init;
2793 ops->set_agc1_min = dib7000p_set_agc1_min;
2794 ops->set_gpio = dib7000p_set_gpio;
2795 ops->i2c_enumeration = dib7000p_i2c_enumeration;
2796 ops->pid_filter = dib7000p_pid_filter;
2797 ops->pid_filter_ctrl = dib7000p_pid_filter_ctrl;
2798 ops->get_i2c_master = dib7000p_get_i2c_master;
2799 ops->update_pll = dib7000p_update_pll;
2800 ops->ctrl_timf = dib7000p_ctrl_timf;
2801 ops->get_agc_values = dib7000p_get_agc_values;
2802 ops->set_wbd_ref = dib7000p_set_wbd_ref;
2803
2804 return ops;
2805}
2806EXPORT_SYMBOL(dib7000p_attach);
Patrick Boettchera75763f2006-10-18 08:34:16 -03002807
2808static struct dvb_frontend_ops dib7000p_ops = {
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -03002809 .delsys = { SYS_DVBT },
Patrick Boettchera75763f2006-10-18 08:34:16 -03002810 .info = {
Olivier Grenie713d54a2011-01-04 04:54:31 -03002811 .name = "DiBcom 7000PC",
Olivier Grenie713d54a2011-01-04 04:54:31 -03002812 .frequency_min = 44250000,
2813 .frequency_max = 867250000,
2814 .frequency_stepsize = 62500,
2815 .caps = FE_CAN_INVERSION_AUTO |
2816 FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
2817 FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
2818 FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO |
2819 FE_CAN_TRANSMISSION_MODE_AUTO | FE_CAN_GUARD_INTERVAL_AUTO | FE_CAN_RECOVER | FE_CAN_HIERARCHY_AUTO,
2820 },
Patrick Boettchera75763f2006-10-18 08:34:16 -03002821
Olivier Grenie713d54a2011-01-04 04:54:31 -03002822 .release = dib7000p_release,
Patrick Boettchera75763f2006-10-18 08:34:16 -03002823
Olivier Grenie713d54a2011-01-04 04:54:31 -03002824 .init = dib7000p_wakeup,
2825 .sleep = dib7000p_sleep,
Patrick Boettchera75763f2006-10-18 08:34:16 -03002826
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -03002827 .set_frontend = dib7000p_set_frontend,
Olivier Grenie713d54a2011-01-04 04:54:31 -03002828 .get_tune_settings = dib7000p_fe_get_tune_settings,
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -03002829 .get_frontend = dib7000p_get_frontend,
Patrick Boettchera75763f2006-10-18 08:34:16 -03002830
Olivier Grenie713d54a2011-01-04 04:54:31 -03002831 .read_status = dib7000p_read_status,
2832 .read_ber = dib7000p_read_ber,
Patrick Boettchera75763f2006-10-18 08:34:16 -03002833 .read_signal_strength = dib7000p_read_signal_strength,
Olivier Grenie713d54a2011-01-04 04:54:31 -03002834 .read_snr = dib7000p_read_snr,
2835 .read_ucblocks = dib7000p_read_unc_blocks,
Patrick Boettchera75763f2006-10-18 08:34:16 -03002836};
2837
Olivier Grenie713d54a2011-01-04 04:54:31 -03002838MODULE_AUTHOR("Olivier Grenie <ogrenie@dibcom.fr>");
Patrick Boettchera75763f2006-10-18 08:34:16 -03002839MODULE_AUTHOR("Patrick Boettcher <pboettcher@dibcom.fr>");
2840MODULE_DESCRIPTION("Driver for the DiBcom 7000PC COFDM demodulator");
2841MODULE_LICENSE("GPL");