blob: b3ddae8885ac23cc94b7bb46930eb5d1f3df689b [file] [log] [blame]
Patrick Boettcher91bb9be2006-12-02 21:15:51 -02001/*
2 * Linux-DVB Driver for DiBcom's DiB7000M and
3 * first generation DiB7000P-demodulator-family.
4 *
Patrick Boettcherb6884a12007-07-27 10:08:51 -03005 * Copyright (C) 2005-7 DiBcom (http://www.dibcom.fr/)
Patrick Boettcher91bb9be2006-12-02 21:15:51 -02006 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License as
9 * published by the Free Software Foundation, version 2.
10 */
11#include <linux/kernel.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090012#include <linux/slab.h>
Patrick Boettcher91bb9be2006-12-02 21:15:51 -020013#include <linux/i2c.h>
Patrick Boettcher79fcce32011-08-03 12:08:21 -030014#include <linux/mutex.h>
Patrick Boettcher91bb9be2006-12-02 21:15:51 -020015
16#include "dvb_frontend.h"
17
18#include "dib7000m.h"
19
20static int debug;
21module_param(debug, int, 0644);
22MODULE_PARM_DESC(debug, "turn on debugging (default: 0)");
23
Patrick Boettcherb6884a12007-07-27 10:08:51 -030024#define dprintk(args...) do { if (debug) { printk(KERN_DEBUG "DiB7000M: "); printk(args); printk("\n"); } } while (0)
Patrick Boettcher91bb9be2006-12-02 21:15:51 -020025
26struct dib7000m_state {
27 struct dvb_frontend demod;
28 struct dib7000m_config cfg;
29
30 u8 i2c_addr;
31 struct i2c_adapter *i2c_adap;
32
33 struct dibx000_i2c_master i2c_master;
34
35/* offset is 1 in case of the 7000MC */
36 u8 reg_offs;
37
38 u16 wbd_ref;
39
40 u8 current_band;
Mauro Carvalho Chehab88ab8982011-12-26 20:01:24 -030041 u32 current_bandwidth;
Patrick Boettcher91bb9be2006-12-02 21:15:51 -020042 struct dibx000_agc_config *current_agc;
Patrick Boettcher69ea31e2006-10-17 18:28:14 -030043 u32 timf;
Patrick Boettcherb6884a12007-07-27 10:08:51 -030044 u32 timf_default;
45 u32 internal_clk;
46
Patrick Boettcher01373a52007-07-30 12:49:04 -030047 u8 div_force_off : 1;
48 u8 div_state : 1;
49 u16 div_sync_wait;
Patrick Boettcher91bb9be2006-12-02 21:15:51 -020050
51 u16 revision;
Patrick Boettcherb6884a12007-07-27 10:08:51 -030052
53 u8 agc_state;
Olivier Grenie5a0deee2011-05-03 12:27:33 -030054
55 /* for the I2C transfer */
56 struct i2c_msg msg[2];
57 u8 i2c_write_buffer[4];
58 u8 i2c_read_buffer[2];
Patrick Boettcher79fcce32011-08-03 12:08:21 -030059 struct mutex i2c_buffer_lock;
Patrick Boettcher91bb9be2006-12-02 21:15:51 -020060};
61
Patrick Boettcher69ea31e2006-10-17 18:28:14 -030062enum dib7000m_power_mode {
63 DIB7000M_POWER_ALL = 0,
64
65 DIB7000M_POWER_NO,
66 DIB7000M_POWER_INTERF_ANALOG_AGC,
67 DIB7000M_POWER_COR4_DINTLV_ICIRM_EQUAL_CFROD,
68 DIB7000M_POWER_COR4_CRY_ESRAM_MOUT_NUD,
69 DIB7000M_POWER_INTERFACE_ONLY,
70};
71
Patrick Boettcher91bb9be2006-12-02 21:15:51 -020072static u16 dib7000m_read_word(struct dib7000m_state *state, u16 reg)
73{
Patrick Boettcher79fcce32011-08-03 12:08:21 -030074 u16 ret;
75
76 if (mutex_lock_interruptible(&state->i2c_buffer_lock) < 0) {
77 dprintk("could not acquire lock");
78 return 0;
79 }
80
Olivier Grenie5a0deee2011-05-03 12:27:33 -030081 state->i2c_write_buffer[0] = (reg >> 8) | 0x80;
82 state->i2c_write_buffer[1] = reg & 0xff;
Patrick Boettcher91bb9be2006-12-02 21:15:51 -020083
Olivier Grenie5a0deee2011-05-03 12:27:33 -030084 memset(state->msg, 0, 2 * sizeof(struct i2c_msg));
85 state->msg[0].addr = state->i2c_addr >> 1;
86 state->msg[0].flags = 0;
87 state->msg[0].buf = state->i2c_write_buffer;
88 state->msg[0].len = 2;
89 state->msg[1].addr = state->i2c_addr >> 1;
90 state->msg[1].flags = I2C_M_RD;
91 state->msg[1].buf = state->i2c_read_buffer;
92 state->msg[1].len = 2;
93
94 if (i2c_transfer(state->i2c_adap, state->msg, 2) != 2)
Patrick Boettcherb6884a12007-07-27 10:08:51 -030095 dprintk("i2c read error on %d",reg);
Patrick Boettcher91bb9be2006-12-02 21:15:51 -020096
Patrick Boettcher79fcce32011-08-03 12:08:21 -030097 ret = (state->i2c_read_buffer[0] << 8) | state->i2c_read_buffer[1];
98 mutex_unlock(&state->i2c_buffer_lock);
99
100 return ret;
Patrick Boettcher91bb9be2006-12-02 21:15:51 -0200101}
102
Patrick Boettcher91bb9be2006-12-02 21:15:51 -0200103static int dib7000m_write_word(struct dib7000m_state *state, u16 reg, u16 val)
104{
Patrick Boettcher79fcce32011-08-03 12:08:21 -0300105 int ret;
106
107 if (mutex_lock_interruptible(&state->i2c_buffer_lock) < 0) {
108 dprintk("could not acquire lock");
109 return -EINVAL;
110 }
111
Olivier Grenie5a0deee2011-05-03 12:27:33 -0300112 state->i2c_write_buffer[0] = (reg >> 8) & 0xff;
113 state->i2c_write_buffer[1] = reg & 0xff;
114 state->i2c_write_buffer[2] = (val >> 8) & 0xff;
115 state->i2c_write_buffer[3] = val & 0xff;
116
117 memset(&state->msg[0], 0, sizeof(struct i2c_msg));
118 state->msg[0].addr = state->i2c_addr >> 1;
119 state->msg[0].flags = 0;
120 state->msg[0].buf = state->i2c_write_buffer;
121 state->msg[0].len = 4;
122
Patrick Boettcher79fcce32011-08-03 12:08:21 -0300123 ret = (i2c_transfer(state->i2c_adap, state->msg, 1) != 1 ?
124 -EREMOTEIO : 0);
125 mutex_unlock(&state->i2c_buffer_lock);
126 return ret;
Patrick Boettcher91bb9be2006-12-02 21:15:51 -0200127}
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300128static void dib7000m_write_tab(struct dib7000m_state *state, u16 *buf)
129{
130 u16 l = 0, r, *n;
131 n = buf;
132 l = *n++;
133 while (l) {
134 r = *n++;
135
136 if (state->reg_offs && (r >= 112 && r <= 331)) // compensate for 7000MC
137 r++;
138
139 do {
140 dib7000m_write_word(state, r, *n++);
141 r++;
142 } while (--l);
143 l = *n++;
144 }
145}
146
Patrick Boettcher69ea31e2006-10-17 18:28:14 -0300147static int dib7000m_set_output_mode(struct dib7000m_state *state, int mode)
148{
149 int ret = 0;
150 u16 outreg, fifo_threshold, smo_mode,
151 sram = 0x0005; /* by default SRAM output is disabled */
152
153 outreg = 0;
154 fifo_threshold = 1792;
155 smo_mode = (dib7000m_read_word(state, 294 + state->reg_offs) & 0x0010) | (1 << 1);
156
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300157 dprintk( "setting output mode for demod %p to %d", &state->demod, mode);
Patrick Boettcher69ea31e2006-10-17 18:28:14 -0300158
159 switch (mode) {
160 case OUTMODE_MPEG2_PAR_GATED_CLK: // STBs with parallel gated clock
161 outreg = (1 << 10); /* 0x0400 */
162 break;
163 case OUTMODE_MPEG2_PAR_CONT_CLK: // STBs with parallel continues clock
164 outreg = (1 << 10) | (1 << 6); /* 0x0440 */
165 break;
166 case OUTMODE_MPEG2_SERIAL: // STBs with serial input
167 outreg = (1 << 10) | (2 << 6) | (0 << 1); /* 0x0482 */
168 break;
169 case OUTMODE_DIVERSITY:
170 if (state->cfg.hostbus_diversity)
171 outreg = (1 << 10) | (4 << 6); /* 0x0500 */
172 else
173 sram |= 0x0c00;
174 break;
175 case OUTMODE_MPEG2_FIFO: // e.g. USB feeding
176 smo_mode |= (3 << 1);
177 fifo_threshold = 512;
178 outreg = (1 << 10) | (5 << 6);
179 break;
180 case OUTMODE_HIGH_Z: // disable
181 outreg = 0;
182 break;
183 default:
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300184 dprintk( "Unhandled output_mode passed to be set for demod %p",&state->demod);
Patrick Boettcher69ea31e2006-10-17 18:28:14 -0300185 break;
186 }
187
188 if (state->cfg.output_mpeg2_in_188_bytes)
189 smo_mode |= (1 << 5) ;
190
191 ret |= dib7000m_write_word(state, 294 + state->reg_offs, smo_mode);
192 ret |= dib7000m_write_word(state, 295 + state->reg_offs, fifo_threshold); /* synchronous fread */
193 ret |= dib7000m_write_word(state, 1795, outreg);
194 ret |= dib7000m_write_word(state, 1805, sram);
195
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300196 if (state->revision == 0x4003) {
197 u16 clk_cfg1 = dib7000m_read_word(state, 909) & 0xfffd;
198 if (mode == OUTMODE_DIVERSITY)
199 clk_cfg1 |= (1 << 1); // P_O_CLK_en
200 dib7000m_write_word(state, 909, clk_cfg1);
201 }
Patrick Boettcher69ea31e2006-10-17 18:28:14 -0300202 return ret;
203}
204
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300205static void dib7000m_set_power_mode(struct dib7000m_state *state, enum dib7000m_power_mode mode)
Patrick Boettcher69ea31e2006-10-17 18:28:14 -0300206{
207 /* by default everything is going to be powered off */
208 u16 reg_903 = 0xffff, reg_904 = 0xffff, reg_905 = 0xffff, reg_906 = 0x3fff;
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300209 u8 offset = 0;
Patrick Boettcher69ea31e2006-10-17 18:28:14 -0300210
211 /* now, depending on the requested mode, we power on */
212 switch (mode) {
213 /* power up everything in the demod */
214 case DIB7000M_POWER_ALL:
215 reg_903 = 0x0000; reg_904 = 0x0000; reg_905 = 0x0000; reg_906 = 0x0000;
216 break;
217
218 /* just leave power on the control-interfaces: GPIO and (I2C or SDIO or SRAM) */
219 case DIB7000M_POWER_INTERFACE_ONLY: /* TODO power up either SDIO or I2C or SRAM */
220 reg_905 &= ~((1 << 7) | (1 << 6) | (1 << 5) | (1 << 2));
221 break;
222
223 case DIB7000M_POWER_INTERF_ANALOG_AGC:
224 reg_903 &= ~((1 << 15) | (1 << 14) | (1 << 11) | (1 << 10));
225 reg_905 &= ~((1 << 7) | (1 << 6) | (1 << 5) | (1 << 4) | (1 << 2));
226 reg_906 &= ~((1 << 0));
227 break;
228
229 case DIB7000M_POWER_COR4_DINTLV_ICIRM_EQUAL_CFROD:
230 reg_903 = 0x0000; reg_904 = 0x801f; reg_905 = 0x0000; reg_906 = 0x0000;
231 break;
232
233 case DIB7000M_POWER_COR4_CRY_ESRAM_MOUT_NUD:
234 reg_903 = 0x0000; reg_904 = 0x8000; reg_905 = 0x010b; reg_906 = 0x0000;
235 break;
236 case DIB7000M_POWER_NO:
237 break;
238 }
239
240 /* always power down unused parts */
241 if (!state->cfg.mobile_mode)
242 reg_904 |= (1 << 7) | (1 << 6) | (1 << 4) | (1 << 2) | (1 << 1);
243
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300244 /* P_sdio_select_clk = 0 on MC and after*/
Patrick Boettcher69ea31e2006-10-17 18:28:14 -0300245 if (state->revision != 0x4000)
246 reg_906 <<= 1;
247
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300248 if (state->revision == 0x4003)
249 offset = 1;
Patrick Boettcher69ea31e2006-10-17 18:28:14 -0300250
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300251 dib7000m_write_word(state, 903 + offset, reg_903);
252 dib7000m_write_word(state, 904 + offset, reg_904);
253 dib7000m_write_word(state, 905 + offset, reg_905);
254 dib7000m_write_word(state, 906 + offset, reg_906);
Patrick Boettcher69ea31e2006-10-17 18:28:14 -0300255}
256
257static int dib7000m_set_adc_state(struct dib7000m_state *state, enum dibx000_adc_states no)
258{
259 int ret = 0;
260 u16 reg_913 = dib7000m_read_word(state, 913),
261 reg_914 = dib7000m_read_word(state, 914);
262
263 switch (no) {
264 case DIBX000_SLOW_ADC_ON:
265 reg_914 |= (1 << 1) | (1 << 0);
266 ret |= dib7000m_write_word(state, 914, reg_914);
267 reg_914 &= ~(1 << 1);
268 break;
269
270 case DIBX000_SLOW_ADC_OFF:
271 reg_914 |= (1 << 1) | (1 << 0);
272 break;
273
274 case DIBX000_ADC_ON:
275 if (state->revision == 0x4000) { // workaround for PA/MA
276 // power-up ADC
277 dib7000m_write_word(state, 913, 0);
278 dib7000m_write_word(state, 914, reg_914 & 0x3);
279 // power-down bandgag
280 dib7000m_write_word(state, 913, (1 << 15));
281 dib7000m_write_word(state, 914, reg_914 & 0x3);
282 }
283
284 reg_913 &= 0x0fff;
285 reg_914 &= 0x0003;
286 break;
287
288 case DIBX000_ADC_OFF: // leave the VBG voltage on
289 reg_913 |= (1 << 14) | (1 << 13) | (1 << 12);
290 reg_914 |= (1 << 5) | (1 << 4) | (1 << 3) | (1 << 2);
291 break;
292
293 case DIBX000_VBG_ENABLE:
294 reg_913 &= ~(1 << 15);
295 break;
296
297 case DIBX000_VBG_DISABLE:
298 reg_913 |= (1 << 15);
299 break;
300
301 default:
302 break;
303 }
304
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300305// dprintk( "913: %x, 914: %x", reg_913, reg_914);
Patrick Boettcher69ea31e2006-10-17 18:28:14 -0300306 ret |= dib7000m_write_word(state, 913, reg_913);
307 ret |= dib7000m_write_word(state, 914, reg_914);
308
309 return ret;
310}
311
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300312static int dib7000m_set_bandwidth(struct dib7000m_state *state, u32 bw)
Patrick Boettcher69ea31e2006-10-17 18:28:14 -0300313{
Patrick Boettcher69ea31e2006-10-17 18:28:14 -0300314 u32 timf;
315
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -0300316 if (!bw)
317 bw = 8000;
318
Patrick Boettcher69ea31e2006-10-17 18:28:14 -0300319 // store the current bandwidth for later use
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300320 state->current_bandwidth = bw;
Patrick Boettcher69ea31e2006-10-17 18:28:14 -0300321
322 if (state->timf == 0) {
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300323 dprintk( "using default timf");
324 timf = state->timf_default;
Patrick Boettcher69ea31e2006-10-17 18:28:14 -0300325 } else {
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300326 dprintk( "using updated timf");
Patrick Boettcher69ea31e2006-10-17 18:28:14 -0300327 timf = state->timf;
328 }
329
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300330 timf = timf * (bw / 50) / 160;
Patrick Boettcher69ea31e2006-10-17 18:28:14 -0300331
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300332 dib7000m_write_word(state, 23, (u16) ((timf >> 16) & 0xffff));
333 dib7000m_write_word(state, 24, (u16) ((timf ) & 0xffff));
334
335 return 0;
336}
337
338static int dib7000m_set_diversity_in(struct dvb_frontend *demod, int onoff)
339{
340 struct dib7000m_state *state = demod->demodulator_priv;
341
342 if (state->div_force_off) {
343 dprintk( "diversity combination deactivated - forced by COFDM parameters");
344 onoff = 0;
345 }
Patrick Boettcher01373a52007-07-30 12:49:04 -0300346 state->div_state = (u8)onoff;
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300347
348 if (onoff) {
349 dib7000m_write_word(state, 263 + state->reg_offs, 6);
350 dib7000m_write_word(state, 264 + state->reg_offs, 6);
351 dib7000m_write_word(state, 266 + state->reg_offs, (state->div_sync_wait << 4) | (1 << 2) | (2 << 0));
352 } else {
353 dib7000m_write_word(state, 263 + state->reg_offs, 1);
354 dib7000m_write_word(state, 264 + state->reg_offs, 0);
355 dib7000m_write_word(state, 266 + state->reg_offs, 0);
356 }
Patrick Boettcher69ea31e2006-10-17 18:28:14 -0300357
358 return 0;
359}
360
361static int dib7000m_sad_calib(struct dib7000m_state *state)
362{
363
364/* internal */
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300365// dib7000m_write_word(state, 928, (3 << 14) | (1 << 12) | (524 << 0)); // sampling clock of the SAD is writting in set_bandwidth
Patrick Boettcher69ea31e2006-10-17 18:28:14 -0300366 dib7000m_write_word(state, 929, (0 << 1) | (0 << 0));
367 dib7000m_write_word(state, 930, 776); // 0.625*3.3 / 4096
368
369 /* do the calibration */
370 dib7000m_write_word(state, 929, (1 << 0));
371 dib7000m_write_word(state, 929, (0 << 0));
372
373 msleep(1);
374
375 return 0;
376}
377
378static void dib7000m_reset_pll_common(struct dib7000m_state *state, const struct dibx000_bandwidth_config *bw)
379{
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300380 dib7000m_write_word(state, 18, (u16) (((bw->internal*1000) >> 16) & 0xffff));
381 dib7000m_write_word(state, 19, (u16) ( (bw->internal*1000) & 0xffff));
382 dib7000m_write_word(state, 21, (u16) ( (bw->ifreq >> 16) & 0xffff));
383 dib7000m_write_word(state, 22, (u16) ( bw->ifreq & 0xffff));
Patrick Boettcher69ea31e2006-10-17 18:28:14 -0300384
385 dib7000m_write_word(state, 928, bw->sad_cfg);
386}
387
388static void dib7000m_reset_pll(struct dib7000m_state *state)
389{
390 const struct dibx000_bandwidth_config *bw = state->cfg.bw;
391 u16 reg_907,reg_910;
392
393 /* default */
394 reg_907 = (bw->pll_bypass << 15) | (bw->modulo << 7) |
395 (bw->ADClkSrc << 6) | (bw->IO_CLK_en_core << 5) | (bw->bypclk_div << 2) |
396 (bw->enable_refdiv << 1) | (0 << 0);
397 reg_910 = (((bw->pll_ratio >> 6) & 0x3) << 3) | (bw->pll_range << 1) | bw->pll_reset;
398
399 // for this oscillator frequency should be 30 MHz for the Master (default values in the board_parameters give that value)
400 // this is only working only for 30 MHz crystals
401 if (!state->cfg.quartz_direct) {
402 reg_910 |= (1 << 5); // forcing the predivider to 1
403
404 // if the previous front-end is baseband, its output frequency is 15 MHz (prev freq divided by 2)
405 if(state->cfg.input_clk_is_div_2)
406 reg_907 |= (16 << 9);
407 else // otherwise the previous front-end puts out its input (default 30MHz) - no extra division necessary
408 reg_907 |= (8 << 9);
409 } else {
410 reg_907 |= (bw->pll_ratio & 0x3f) << 9;
411 reg_910 |= (bw->pll_prediv << 5);
412 }
413
414 dib7000m_write_word(state, 910, reg_910); // pll cfg
415 dib7000m_write_word(state, 907, reg_907); // clk cfg0
416 dib7000m_write_word(state, 908, 0x0006); // clk_cfg1
417
418 dib7000m_reset_pll_common(state, bw);
419}
420
421static void dib7000mc_reset_pll(struct dib7000m_state *state)
422{
423 const struct dibx000_bandwidth_config *bw = state->cfg.bw;
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300424 u16 clk_cfg1;
Patrick Boettcher69ea31e2006-10-17 18:28:14 -0300425
426 // clk_cfg0
427 dib7000m_write_word(state, 907, (bw->pll_prediv << 8) | (bw->pll_ratio << 0));
428
429 // clk_cfg1
430 //dib7000m_write_word(state, 908, (1 << 14) | (3 << 12) |(0 << 11) |
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300431 clk_cfg1 = (0 << 14) | (3 << 12) |(0 << 11) |
Patrick Boettcher69ea31e2006-10-17 18:28:14 -0300432 (bw->IO_CLK_en_core << 10) | (bw->bypclk_div << 5) | (bw->enable_refdiv << 4) |
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300433 (1 << 3) | (bw->pll_range << 1) | (bw->pll_reset << 0);
434 dib7000m_write_word(state, 908, clk_cfg1);
435 clk_cfg1 = (clk_cfg1 & 0xfff7) | (bw->pll_bypass << 3);
436 dib7000m_write_word(state, 908, clk_cfg1);
Patrick Boettcher69ea31e2006-10-17 18:28:14 -0300437
438 // smpl_cfg
439 dib7000m_write_word(state, 910, (1 << 12) | (2 << 10) | (bw->modulo << 8) | (bw->ADClkSrc << 7));
440
441 dib7000m_reset_pll_common(state, bw);
442}
443
444static int dib7000m_reset_gpio(struct dib7000m_state *st)
445{
446 /* reset the GPIOs */
Patrick Boettcher69ea31e2006-10-17 18:28:14 -0300447 dib7000m_write_word(st, 773, st->cfg.gpio_dir);
448 dib7000m_write_word(st, 774, st->cfg.gpio_val);
449
450 /* TODO 782 is P_gpio_od */
451
452 dib7000m_write_word(st, 775, st->cfg.gpio_pwm_pos);
453
454 dib7000m_write_word(st, 780, st->cfg.pwm_freq_div);
455 return 0;
456}
457
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300458static u16 dib7000m_defaults_common[] =
459
460{
461 // auto search configuration
462 3, 2,
463 0x0004,
464 0x1000,
465 0x0814,
466
467 12, 6,
468 0x001b,
469 0x7740,
470 0x005b,
471 0x8d80,
472 0x01c9,
473 0xc380,
474 0x0000,
475 0x0080,
476 0x0000,
477 0x0090,
478 0x0001,
479 0xd4c0,
480
481 1, 26,
482 0x6680, // P_corm_thres Lock algorithms configuration
483
484 1, 170,
485 0x0410, // P_palf_alpha_regul, P_palf_filter_freeze, P_palf_filter_on
486
487 8, 173,
488 0,
489 0,
490 0,
491 0,
492 0,
493 0,
494 0,
495 0,
496
497 1, 182,
498 8192, // P_fft_nb_to_cut
499
500 2, 195,
501 0x0ccd, // P_pha3_thres
502 0, // P_cti_use_cpe, P_cti_use_prog
503
504 1, 205,
505 0x200f, // P_cspu_regul, P_cspu_win_cut
506
507 5, 214,
508 0x023d, // P_adp_regul_cnt
509 0x00a4, // P_adp_noise_cnt
510 0x00a4, // P_adp_regul_ext
511 0x7ff0, // P_adp_noise_ext
512 0x3ccc, // P_adp_fil
513
514 1, 226,
515 0, // P_2d_byp_ti_num
516
517 1, 255,
518 0x800, // P_equal_thres_wgn
519
520 1, 263,
521 0x0001,
522
523 1, 281,
524 0x0010, // P_fec_*
525
526 1, 294,
527 0x0062, // P_smo_mode, P_smo_rs_discard, P_smo_fifo_flush, P_smo_pid_parse, P_smo_error_discard
528
529 0
530};
531
532static u16 dib7000m_defaults[] =
533
534{
535 /* set ADC level to -16 */
536 11, 76,
537 (1 << 13) - 825 - 117,
538 (1 << 13) - 837 - 117,
539 (1 << 13) - 811 - 117,
540 (1 << 13) - 766 - 117,
541 (1 << 13) - 737 - 117,
542 (1 << 13) - 693 - 117,
543 (1 << 13) - 648 - 117,
544 (1 << 13) - 619 - 117,
545 (1 << 13) - 575 - 117,
546 (1 << 13) - 531 - 117,
547 (1 << 13) - 501 - 117,
548
549 // Tuner IO bank: max drive (14mA)
550 1, 912,
551 0x2c8a,
552
553 1, 1817,
554 1,
555
556 0,
557};
558
Patrick Boettcher69ea31e2006-10-17 18:28:14 -0300559static int dib7000m_demod_reset(struct dib7000m_state *state)
560{
561 dib7000m_set_power_mode(state, DIB7000M_POWER_ALL);
562
563 /* always leave the VBG voltage on - it consumes almost nothing but takes a long time to start */
564 dib7000m_set_adc_state(state, DIBX000_VBG_ENABLE);
565
566 /* restart all parts */
567 dib7000m_write_word(state, 898, 0xffff);
568 dib7000m_write_word(state, 899, 0xffff);
569 dib7000m_write_word(state, 900, 0xff0f);
570 dib7000m_write_word(state, 901, 0xfffc);
571
572 dib7000m_write_word(state, 898, 0);
573 dib7000m_write_word(state, 899, 0);
574 dib7000m_write_word(state, 900, 0);
575 dib7000m_write_word(state, 901, 0);
576
577 if (state->revision == 0x4000)
578 dib7000m_reset_pll(state);
579 else
580 dib7000mc_reset_pll(state);
581
582 if (dib7000m_reset_gpio(state) != 0)
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300583 dprintk( "GPIO reset was not successful.");
Patrick Boettcher69ea31e2006-10-17 18:28:14 -0300584
585 if (dib7000m_set_output_mode(state, OUTMODE_HIGH_Z) != 0)
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300586 dprintk( "OUTPUT_MODE could not be reset.");
Patrick Boettcher69ea31e2006-10-17 18:28:14 -0300587
588 /* unforce divstr regardless whether i2c enumeration was done or not */
589 dib7000m_write_word(state, 1794, dib7000m_read_word(state, 1794) & ~(1 << 1) );
590
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300591 dib7000m_set_bandwidth(state, 8000);
Patrick Boettcher69ea31e2006-10-17 18:28:14 -0300592
593 dib7000m_set_adc_state(state, DIBX000_SLOW_ADC_ON);
594 dib7000m_sad_calib(state);
595 dib7000m_set_adc_state(state, DIBX000_SLOW_ADC_OFF);
596
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300597 if (state->cfg.dvbt_mode)
598 dib7000m_write_word(state, 1796, 0x0); // select DVB-T output
599
600 if (state->cfg.mobile_mode)
601 dib7000m_write_word(state, 261 + state->reg_offs, 2);
602 else
603 dib7000m_write_word(state, 224 + state->reg_offs, 1);
604
605 // P_iqc_alpha_pha, P_iqc_alpha_amp, P_iqc_dcc_alpha, ...
606 if(state->cfg.tuner_is_baseband)
607 dib7000m_write_word(state, 36, 0x0755);
608 else
609 dib7000m_write_word(state, 36, 0x1f55);
610
611 // P_divclksel=3 P_divbitsel=1
612 if (state->revision == 0x4000)
613 dib7000m_write_word(state, 909, (3 << 10) | (1 << 6));
614 else
615 dib7000m_write_word(state, 909, (3 << 4) | 1);
616
617 dib7000m_write_tab(state, dib7000m_defaults_common);
618 dib7000m_write_tab(state, dib7000m_defaults);
619
Patrick Boettcher69ea31e2006-10-17 18:28:14 -0300620 dib7000m_set_power_mode(state, DIB7000M_POWER_INTERFACE_ONLY);
621
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300622 state->internal_clk = state->cfg.bw->internal;
623
Patrick Boettcher69ea31e2006-10-17 18:28:14 -0300624 return 0;
625}
626
627static void dib7000m_restart_agc(struct dib7000m_state *state)
628{
629 // P_restart_iqc & P_restart_agc
630 dib7000m_write_word(state, 898, 0x0c00);
631 dib7000m_write_word(state, 898, 0x0000);
632}
633
634static int dib7000m_agc_soft_split(struct dib7000m_state *state)
635{
636 u16 agc,split_offset;
637
638 if(!state->current_agc || !state->current_agc->perform_agc_softsplit || state->current_agc->split.max == 0)
639 return 0;
640
641 // n_agc_global
642 agc = dib7000m_read_word(state, 390);
643
644 if (agc > state->current_agc->split.min_thres)
645 split_offset = state->current_agc->split.min;
646 else if (agc < state->current_agc->split.max_thres)
647 split_offset = state->current_agc->split.max;
648 else
649 split_offset = state->current_agc->split.max *
650 (agc - state->current_agc->split.min_thres) /
651 (state->current_agc->split.max_thres - state->current_agc->split.min_thres);
652
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300653 dprintk( "AGC split_offset: %d",split_offset);
Patrick Boettcher69ea31e2006-10-17 18:28:14 -0300654
655 // P_agc_force_split and P_agc_split_offset
656 return dib7000m_write_word(state, 103, (dib7000m_read_word(state, 103) & 0xff00) | split_offset);
657}
658
659static int dib7000m_update_lna(struct dib7000m_state *state)
660{
Patrick Boettcher69ea31e2006-10-17 18:28:14 -0300661 u16 dyn_gain;
662
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300663 if (state->cfg.update_lna) {
Patrick Boettcher01373a52007-07-30 12:49:04 -0300664 // read dyn_gain here (because it is demod-dependent and not fe)
Patrick Boettcher69ea31e2006-10-17 18:28:14 -0300665 dyn_gain = dib7000m_read_word(state, 390);
666
Patrick Boettcher69ea31e2006-10-17 18:28:14 -0300667 if (state->cfg.update_lna(&state->demod,dyn_gain)) { // LNA has changed
668 dib7000m_restart_agc(state);
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300669 return 1;
670 }
Patrick Boettcher69ea31e2006-10-17 18:28:14 -0300671 }
672 return 0;
673}
674
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300675static int dib7000m_set_agc_config(struct dib7000m_state *state, u8 band)
Patrick Boettcher69ea31e2006-10-17 18:28:14 -0300676{
677 struct dibx000_agc_config *agc = NULL;
678 int i;
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300679 if (state->current_band == band && state->current_agc != NULL)
680 return 0;
Patrick Boettcher69ea31e2006-10-17 18:28:14 -0300681 state->current_band = band;
682
683 for (i = 0; i < state->cfg.agc_config_count; i++)
684 if (state->cfg.agc[i].band_caps & band) {
685 agc = &state->cfg.agc[i];
686 break;
687 }
688
689 if (agc == NULL) {
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300690 dprintk( "no valid AGC configuration found for band 0x%02x",band);
691 return -EINVAL;
Patrick Boettcher69ea31e2006-10-17 18:28:14 -0300692 }
693
694 state->current_agc = agc;
695
696 /* AGC */
697 dib7000m_write_word(state, 72 , agc->setup);
698 dib7000m_write_word(state, 73 , agc->inv_gain);
699 dib7000m_write_word(state, 74 , agc->time_stabiliz);
700 dib7000m_write_word(state, 97 , (agc->alpha_level << 12) | agc->thlock);
701
702 // Demod AGC loop configuration
703 dib7000m_write_word(state, 98, (agc->alpha_mant << 5) | agc->alpha_exp);
704 dib7000m_write_word(state, 99, (agc->beta_mant << 6) | agc->beta_exp);
705
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300706 dprintk( "WBD: ref: %d, sel: %d, active: %d, alpha: %d",
Patrick Boettcher69ea31e2006-10-17 18:28:14 -0300707 state->wbd_ref != 0 ? state->wbd_ref : agc->wbd_ref, agc->wbd_sel, !agc->perform_agc_softsplit, agc->wbd_sel);
708
709 /* AGC continued */
710 if (state->wbd_ref != 0)
711 dib7000m_write_word(state, 102, state->wbd_ref);
712 else // use default
713 dib7000m_write_word(state, 102, agc->wbd_ref);
714
715 dib7000m_write_word(state, 103, (agc->wbd_alpha << 9) | (agc->perform_agc_softsplit << 8) );
716 dib7000m_write_word(state, 104, agc->agc1_max);
717 dib7000m_write_word(state, 105, agc->agc1_min);
718 dib7000m_write_word(state, 106, agc->agc2_max);
719 dib7000m_write_word(state, 107, agc->agc2_min);
720 dib7000m_write_word(state, 108, (agc->agc1_pt1 << 8) | agc->agc1_pt2 );
721 dib7000m_write_word(state, 109, (agc->agc1_slope1 << 8) | agc->agc1_slope2);
722 dib7000m_write_word(state, 110, (agc->agc2_pt1 << 8) | agc->agc2_pt2);
723 dib7000m_write_word(state, 111, (agc->agc2_slope1 << 8) | agc->agc2_slope2);
724
725 if (state->revision > 0x4000) { // settings for the MC
726 dib7000m_write_word(state, 71, agc->agc1_pt3);
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300727// dprintk( "929: %x %d %d",
Patrick Boettcher69ea31e2006-10-17 18:28:14 -0300728// (dib7000m_read_word(state, 929) & 0xffe3) | (agc->wbd_inv << 4) | (agc->wbd_sel << 2), agc->wbd_inv, agc->wbd_sel);
729 dib7000m_write_word(state, 929, (dib7000m_read_word(state, 929) & 0xffe3) | (agc->wbd_inv << 4) | (agc->wbd_sel << 2));
730 } else {
731 // wrong default values
732 u16 b[9] = { 676, 696, 717, 737, 758, 778, 799, 819, 840 };
733 for (i = 0; i < 9; i++)
734 dib7000m_write_word(state, 88 + i, b[i]);
735 }
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300736 return 0;
Patrick Boettcher69ea31e2006-10-17 18:28:14 -0300737}
738
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300739static void dib7000m_update_timf(struct dib7000m_state *state)
Patrick Boettcher69ea31e2006-10-17 18:28:14 -0300740{
741 u32 timf = (dib7000m_read_word(state, 436) << 16) | dib7000m_read_word(state, 437);
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300742 state->timf = timf * 160 / (state->current_bandwidth / 50);
Patrick Boettcher69ea31e2006-10-17 18:28:14 -0300743 dib7000m_write_word(state, 23, (u16) (timf >> 16));
744 dib7000m_write_word(state, 24, (u16) (timf & 0xffff));
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300745 dprintk( "updated timf_frequency: %d (default: %d)",state->timf, state->timf_default);
Patrick Boettcher69ea31e2006-10-17 18:28:14 -0300746}
747
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -0300748static int dib7000m_agc_startup(struct dvb_frontend *demod)
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300749{
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -0300750 struct dtv_frontend_properties *ch = &demod->dtv_property_cache;
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300751 struct dib7000m_state *state = demod->demodulator_priv;
752 u16 cfg_72 = dib7000m_read_word(state, 72);
753 int ret = -1;
754 u8 *agc_state = &state->agc_state;
755 u8 agc_split;
756
757 switch (state->agc_state) {
758 case 0:
759 // set power-up level: interf+analog+AGC
760 dib7000m_set_power_mode(state, DIB7000M_POWER_INTERF_ANALOG_AGC);
761 dib7000m_set_adc_state(state, DIBX000_ADC_ON);
762
763 if (dib7000m_set_agc_config(state, BAND_OF_FREQUENCY(ch->frequency/1000)) != 0)
764 return -1;
765
766 ret = 7; /* ADC power up */
767 (*agc_state)++;
768 break;
769
770 case 1:
771 /* AGC initialization */
772 if (state->cfg.agc_control)
773 state->cfg.agc_control(&state->demod, 1);
774
775 dib7000m_write_word(state, 75, 32768);
776 if (!state->current_agc->perform_agc_softsplit) {
777 /* we are using the wbd - so slow AGC startup */
778 dib7000m_write_word(state, 103, 1 << 8); /* force 0 split on WBD and restart AGC */
779 (*agc_state)++;
780 ret = 5;
781 } else {
782 /* default AGC startup */
783 (*agc_state) = 4;
784 /* wait AGC rough lock time */
785 ret = 7;
786 }
787
788 dib7000m_restart_agc(state);
789 break;
790
791 case 2: /* fast split search path after 5sec */
792 dib7000m_write_word(state, 72, cfg_72 | (1 << 4)); /* freeze AGC loop */
793 dib7000m_write_word(state, 103, 2 << 9); /* fast split search 0.25kHz */
794 (*agc_state)++;
795 ret = 14;
796 break;
797
798 case 3: /* split search ended */
Patrick Boettcher01373a52007-07-30 12:49:04 -0300799 agc_split = (u8)dib7000m_read_word(state, 392); /* store the split value for the next time */
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300800 dib7000m_write_word(state, 75, dib7000m_read_word(state, 390)); /* set AGC gain start value */
801
802 dib7000m_write_word(state, 72, cfg_72 & ~(1 << 4)); /* std AGC loop */
803 dib7000m_write_word(state, 103, (state->current_agc->wbd_alpha << 9) | agc_split); /* standard split search */
804
805 dib7000m_restart_agc(state);
806
807 dprintk( "SPLIT %p: %hd", demod, agc_split);
808
809 (*agc_state)++;
810 ret = 5;
811 break;
812
813 case 4: /* LNA startup */
814 /* wait AGC accurate lock time */
815 ret = 7;
816
817 if (dib7000m_update_lna(state))
818 // wait only AGC rough lock time
819 ret = 5;
820 else
821 (*agc_state)++;
822 break;
823
824 case 5:
825 dib7000m_agc_soft_split(state);
826
827 if (state->cfg.agc_control)
828 state->cfg.agc_control(&state->demod, 0);
829
830 (*agc_state)++;
831 break;
832
833 default:
834 break;
835 }
836 return ret;
837}
838
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -0300839static void dib7000m_set_channel(struct dib7000m_state *state, struct dtv_frontend_properties *ch,
840 u8 seq)
Patrick Boettcher69ea31e2006-10-17 18:28:14 -0300841{
842 u16 value, est[4];
843
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -0300844 dib7000m_set_bandwidth(state, BANDWIDTH_TO_KHZ(ch->bandwidth_hz));
Patrick Boettcher69ea31e2006-10-17 18:28:14 -0300845
846 /* nfft, guard, qam, alpha */
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300847 value = 0;
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -0300848 switch (ch->transmission_mode) {
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300849 case TRANSMISSION_MODE_2K: value |= (0 << 7); break;
Mauro Carvalho Chehab2e94b532010-12-27 11:55:07 -0300850 case TRANSMISSION_MODE_4K: value |= (2 << 7); break;
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300851 default:
852 case TRANSMISSION_MODE_8K: value |= (1 << 7); break;
853 }
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -0300854 switch (ch->guard_interval) {
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300855 case GUARD_INTERVAL_1_32: value |= (0 << 5); break;
856 case GUARD_INTERVAL_1_16: value |= (1 << 5); break;
857 case GUARD_INTERVAL_1_4: value |= (3 << 5); break;
858 default:
859 case GUARD_INTERVAL_1_8: value |= (2 << 5); break;
860 }
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -0300861 switch (ch->modulation) {
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300862 case QPSK: value |= (0 << 3); break;
863 case QAM_16: value |= (1 << 3); break;
864 default:
865 case QAM_64: value |= (2 << 3); break;
866 }
867 switch (HIERARCHY_1) {
868 case HIERARCHY_2: value |= 2; break;
869 case HIERARCHY_4: value |= 4; break;
870 default:
871 case HIERARCHY_1: value |= 1; break;
872 }
873 dib7000m_write_word(state, 0, value);
Patrick Boettcher69ea31e2006-10-17 18:28:14 -0300874 dib7000m_write_word(state, 5, (seq << 4));
875
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300876 /* P_dintl_native, P_dintlv_inv, P_hrch, P_code_rate, P_select_hp */
877 value = 0;
878 if (1 != 0)
879 value |= (1 << 6);
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -0300880 if (ch->hierarchy == 1)
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300881 value |= (1 << 4);
882 if (1 == 1)
883 value |= 1;
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -0300884 switch ((ch->hierarchy == 0 || 1 == 1) ? ch->code_rate_HP : ch->code_rate_LP) {
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300885 case FEC_2_3: value |= (2 << 1); break;
886 case FEC_3_4: value |= (3 << 1); break;
887 case FEC_5_6: value |= (5 << 1); break;
888 case FEC_7_8: value |= (7 << 1); break;
889 default:
890 case FEC_1_2: value |= (1 << 1); break;
891 }
Patrick Boettcher69ea31e2006-10-17 18:28:14 -0300892 dib7000m_write_word(state, 267 + state->reg_offs, value);
893
894 /* offset loop parameters */
895
896 /* P_timf_alpha = 6, P_corm_alpha=6, P_corm_thres=0x80 */
897 dib7000m_write_word(state, 26, (6 << 12) | (6 << 8) | 0x80);
898
899 /* P_ctrl_inh_cor=0, P_ctrl_alpha_cor=4, P_ctrl_inh_isi=1, P_ctrl_alpha_isi=3, P_ctrl_inh_cor4=1, P_ctrl_alpha_cor4=3 */
900 dib7000m_write_word(state, 29, (0 << 14) | (4 << 10) | (1 << 9) | (3 << 5) | (1 << 4) | (0x3));
901
902 /* P_ctrl_freeze_pha_shift=0, P_ctrl_pha_off_max=3 */
903 dib7000m_write_word(state, 32, (0 << 4) | 0x3);
904
905 /* P_ctrl_sfreq_inh=0, P_ctrl_sfreq_step=5 */
906 dib7000m_write_word(state, 33, (0 << 4) | 0x5);
907
908 /* P_dvsy_sync_wait */
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -0300909 switch (ch->transmission_mode) {
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300910 case TRANSMISSION_MODE_8K: value = 256; break;
Mauro Carvalho Chehab2e94b532010-12-27 11:55:07 -0300911 case TRANSMISSION_MODE_4K: value = 128; break;
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300912 case TRANSMISSION_MODE_2K:
Patrick Boettcher69ea31e2006-10-17 18:28:14 -0300913 default: value = 64; break;
914 }
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -0300915 switch (ch->guard_interval) {
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300916 case GUARD_INTERVAL_1_16: value *= 2; break;
917 case GUARD_INTERVAL_1_8: value *= 4; break;
918 case GUARD_INTERVAL_1_4: value *= 8; break;
919 default:
920 case GUARD_INTERVAL_1_32: value *= 1; break;
921 }
922 state->div_sync_wait = (value * 3) / 2 + 32; // add 50% SFN margin + compensate for one DVSY-fifo TODO
Patrick Boettcher69ea31e2006-10-17 18:28:14 -0300923
924 /* deactive the possibility of diversity reception if extended interleave - not for 7000MC */
925 /* P_dvsy_sync_mode = 0, P_dvsy_sync_enable=1, P_dvcb_comb_mode=2 */
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300926 if (1 == 1 || state->revision > 0x4000)
927 state->div_force_off = 0;
Patrick Boettcher69ea31e2006-10-17 18:28:14 -0300928 else
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300929 state->div_force_off = 1;
930 dib7000m_set_diversity_in(&state->demod, state->div_state);
Patrick Boettcher69ea31e2006-10-17 18:28:14 -0300931
932 /* channel estimation fine configuration */
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -0300933 switch (ch->modulation) {
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300934 case QAM_64:
Patrick Boettcher69ea31e2006-10-17 18:28:14 -0300935 est[0] = 0x0148; /* P_adp_regul_cnt 0.04 */
936 est[1] = 0xfff0; /* P_adp_noise_cnt -0.002 */
937 est[2] = 0x00a4; /* P_adp_regul_ext 0.02 */
938 est[3] = 0xfff8; /* P_adp_noise_ext -0.001 */
939 break;
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300940 case QAM_16:
Patrick Boettcher69ea31e2006-10-17 18:28:14 -0300941 est[0] = 0x023d; /* P_adp_regul_cnt 0.07 */
942 est[1] = 0xffdf; /* P_adp_noise_cnt -0.004 */
943 est[2] = 0x00a4; /* P_adp_regul_ext 0.02 */
944 est[3] = 0xfff0; /* P_adp_noise_ext -0.002 */
945 break;
946 default:
947 est[0] = 0x099a; /* P_adp_regul_cnt 0.3 */
948 est[1] = 0xffae; /* P_adp_noise_cnt -0.01 */
949 est[2] = 0x0333; /* P_adp_regul_ext 0.1 */
950 est[3] = 0xfff8; /* P_adp_noise_ext -0.002 */
951 break;
952 }
953 for (value = 0; value < 4; value++)
954 dib7000m_write_word(state, 214 + value + state->reg_offs, est[value]);
955
Patrick Boettcher69ea31e2006-10-17 18:28:14 -0300956 // set power-up level: autosearch
957 dib7000m_set_power_mode(state, DIB7000M_POWER_COR4_DINTLV_ICIRM_EQUAL_CFROD);
958}
959
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -0300960static int dib7000m_autosearch_start(struct dvb_frontend *demod)
Patrick Boettcher69ea31e2006-10-17 18:28:14 -0300961{
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -0300962 struct dtv_frontend_properties *ch = &demod->dtv_property_cache;
Patrick Boettcher69ea31e2006-10-17 18:28:14 -0300963 struct dib7000m_state *state = demod->demodulator_priv;
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -0300964 struct dtv_frontend_properties schan;
Patrick Boettcher69ea31e2006-10-17 18:28:14 -0300965 int ret = 0;
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300966 u32 value, factor;
Patrick Boettcher69ea31e2006-10-17 18:28:14 -0300967
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300968 schan = *ch;
Patrick Boettcher69ea31e2006-10-17 18:28:14 -0300969
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -0300970 schan.modulation = QAM_64;
971 schan.guard_interval = GUARD_INTERVAL_1_32;
972 schan.transmission_mode = TRANSMISSION_MODE_8K;
973 schan.code_rate_HP = FEC_2_3;
974 schan.code_rate_LP = FEC_3_4;
975 schan.hierarchy = 0;
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300976
977 dib7000m_set_channel(state, &schan, 7);
978
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -0300979 factor = BANDWIDTH_TO_KHZ(schan.bandwidth_hz);
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300980 if (factor >= 5000)
981 factor = 1;
982 else
983 factor = 6;
Patrick Boettcher69ea31e2006-10-17 18:28:14 -0300984
985 // always use the setting for 8MHz here lock_time for 7,6 MHz are longer
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300986 value = 30 * state->internal_clk * factor;
Patrick Boettcher69ea31e2006-10-17 18:28:14 -0300987 ret |= dib7000m_write_word(state, 6, (u16) ((value >> 16) & 0xffff)); // lock0 wait time
988 ret |= dib7000m_write_word(state, 7, (u16) (value & 0xffff)); // lock0 wait time
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300989 value = 100 * state->internal_clk * factor;
Patrick Boettcher69ea31e2006-10-17 18:28:14 -0300990 ret |= dib7000m_write_word(state, 8, (u16) ((value >> 16) & 0xffff)); // lock1 wait time
991 ret |= dib7000m_write_word(state, 9, (u16) (value & 0xffff)); // lock1 wait time
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300992 value = 500 * state->internal_clk * factor;
Patrick Boettcher69ea31e2006-10-17 18:28:14 -0300993 ret |= dib7000m_write_word(state, 10, (u16) ((value >> 16) & 0xffff)); // lock2 wait time
994 ret |= dib7000m_write_word(state, 11, (u16) (value & 0xffff)); // lock2 wait time
995
996 // start search
997 value = dib7000m_read_word(state, 0);
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300998 ret |= dib7000m_write_word(state, 0, (u16) (value | (1 << 9)));
Patrick Boettcher69ea31e2006-10-17 18:28:14 -0300999
1000 /* clear n_irq_pending */
1001 if (state->revision == 0x4000)
1002 dib7000m_write_word(state, 1793, 0);
1003 else
1004 dib7000m_read_word(state, 537);
1005
1006 ret |= dib7000m_write_word(state, 0, (u16) value);
1007
1008 return ret;
1009}
1010
1011static int dib7000m_autosearch_irq(struct dib7000m_state *state, u16 reg)
1012{
1013 u16 irq_pending = dib7000m_read_word(state, reg);
1014
1015 if (irq_pending & 0x1) { // failed
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001016 dprintk( "autosearch failed");
Patrick Boettcher69ea31e2006-10-17 18:28:14 -03001017 return 1;
1018 }
1019
1020 if (irq_pending & 0x2) { // succeeded
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001021 dprintk( "autosearch succeeded");
Patrick Boettcher69ea31e2006-10-17 18:28:14 -03001022 return 2;
1023 }
1024 return 0; // still pending
1025}
1026
1027static int dib7000m_autosearch_is_irq(struct dvb_frontend *demod)
1028{
1029 struct dib7000m_state *state = demod->demodulator_priv;
1030 if (state->revision == 0x4000)
1031 return dib7000m_autosearch_irq(state, 1793);
1032 else
1033 return dib7000m_autosearch_irq(state, 537);
1034}
1035
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -03001036static int dib7000m_tune(struct dvb_frontend *demod)
Patrick Boettcher69ea31e2006-10-17 18:28:14 -03001037{
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -03001038 struct dtv_frontend_properties *ch = &demod->dtv_property_cache;
Patrick Boettcher69ea31e2006-10-17 18:28:14 -03001039 struct dib7000m_state *state = demod->demodulator_priv;
1040 int ret = 0;
1041 u16 value;
1042
1043 // we are already tuned - just resuming from suspend
Himangi Saraogi157a5fe2014-07-15 18:31:17 -03001044 dib7000m_set_channel(state, ch, 0);
Patrick Boettcher69ea31e2006-10-17 18:28:14 -03001045
1046 // restart demod
1047 ret |= dib7000m_write_word(state, 898, 0x4000);
1048 ret |= dib7000m_write_word(state, 898, 0x0000);
1049 msleep(45);
1050
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001051 dib7000m_set_power_mode(state, DIB7000M_POWER_COR4_CRY_ESRAM_MOUT_NUD);
Patrick Boettcher69ea31e2006-10-17 18:28:14 -03001052 /* 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 */
1053 ret |= dib7000m_write_word(state, 29, (0 << 14) | (4 << 10) | (0 << 9) | (3 << 5) | (1 << 4) | (0x3));
1054
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001055 // never achieved a lock before - wait for timfreq to update
Patrick Boettcher69ea31e2006-10-17 18:28:14 -03001056 if (state->timf == 0)
1057 msleep(200);
1058
1059 //dump_reg(state);
1060 /* P_timf_alpha, P_corm_alpha=6, P_corm_thres=0x80 */
1061 value = (6 << 8) | 0x80;
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -03001062 switch (ch->transmission_mode) {
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001063 case TRANSMISSION_MODE_2K: value |= (7 << 12); break;
Mauro Carvalho Chehab2e94b532010-12-27 11:55:07 -03001064 case TRANSMISSION_MODE_4K: value |= (8 << 12); break;
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001065 default:
1066 case TRANSMISSION_MODE_8K: value |= (9 << 12); break;
Patrick Boettcher69ea31e2006-10-17 18:28:14 -03001067 }
1068 ret |= dib7000m_write_word(state, 26, value);
1069
1070 /* P_ctrl_freeze_pha_shift=0, P_ctrl_pha_off_max */
1071 value = (0 << 4);
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -03001072 switch (ch->transmission_mode) {
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001073 case TRANSMISSION_MODE_2K: value |= 0x6; break;
Mauro Carvalho Chehab2e94b532010-12-27 11:55:07 -03001074 case TRANSMISSION_MODE_4K: value |= 0x7; break;
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001075 default:
1076 case TRANSMISSION_MODE_8K: value |= 0x8; break;
Patrick Boettcher69ea31e2006-10-17 18:28:14 -03001077 }
1078 ret |= dib7000m_write_word(state, 32, value);
1079
1080 /* P_ctrl_sfreq_inh=0, P_ctrl_sfreq_step */
1081 value = (0 << 4);
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -03001082 switch (ch->transmission_mode) {
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001083 case TRANSMISSION_MODE_2K: value |= 0x6; break;
Mauro Carvalho Chehab2e94b532010-12-27 11:55:07 -03001084 case TRANSMISSION_MODE_4K: value |= 0x7; break;
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001085 default:
1086 case TRANSMISSION_MODE_8K: value |= 0x8; break;
Patrick Boettcher69ea31e2006-10-17 18:28:14 -03001087 }
1088 ret |= dib7000m_write_word(state, 33, value);
1089
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001090 // we achieved a lock - it's time to update the timf freq
Patrick Boettcher69ea31e2006-10-17 18:28:14 -03001091 if ((dib7000m_read_word(state, 535) >> 6) & 0x1)
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001092 dib7000m_update_timf(state);
Patrick Boettcher69ea31e2006-10-17 18:28:14 -03001093
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -03001094 dib7000m_set_bandwidth(state, BANDWIDTH_TO_KHZ(ch->bandwidth_hz));
Patrick Boettcher69ea31e2006-10-17 18:28:14 -03001095 return ret;
1096}
1097
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001098static int dib7000m_wakeup(struct dvb_frontend *demod)
Patrick Boettcher69ea31e2006-10-17 18:28:14 -03001099{
1100 struct dib7000m_state *state = demod->demodulator_priv;
Patrick Boettcher69ea31e2006-10-17 18:28:14 -03001101
1102 dib7000m_set_power_mode(state, DIB7000M_POWER_ALL);
1103
1104 if (dib7000m_set_adc_state(state, DIBX000_SLOW_ADC_ON) != 0)
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001105 dprintk( "could not start Slow ADC");
Patrick Boettcher69ea31e2006-10-17 18:28:14 -03001106
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001107 return 0;
Patrick Boettcher69ea31e2006-10-17 18:28:14 -03001108}
1109
1110static int dib7000m_sleep(struct dvb_frontend *demod)
1111{
1112 struct dib7000m_state *st = demod->demodulator_priv;
1113 dib7000m_set_output_mode(st, OUTMODE_HIGH_Z);
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001114 dib7000m_set_power_mode(st, DIB7000M_POWER_INTERFACE_ONLY);
1115 return dib7000m_set_adc_state(st, DIBX000_SLOW_ADC_OFF) |
Patrick Boettcher69ea31e2006-10-17 18:28:14 -03001116 dib7000m_set_adc_state(st, DIBX000_ADC_OFF);
1117}
1118
1119static int dib7000m_identify(struct dib7000m_state *state)
1120{
1121 u16 value;
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001122
Patrick Boettcher69ea31e2006-10-17 18:28:14 -03001123 if ((value = dib7000m_read_word(state, 896)) != 0x01b3) {
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001124 dprintk( "wrong Vendor ID (0x%x)",value);
Patrick Boettcher69ea31e2006-10-17 18:28:14 -03001125 return -EREMOTEIO;
1126 }
1127
1128 state->revision = dib7000m_read_word(state, 897);
1129 if (state->revision != 0x4000 &&
1130 state->revision != 0x4001 &&
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001131 state->revision != 0x4002 &&
1132 state->revision != 0x4003) {
1133 dprintk( "wrong Device ID (0x%x)",value);
Patrick Boettcher69ea31e2006-10-17 18:28:14 -03001134 return -EREMOTEIO;
1135 }
1136
1137 /* protect this driver to be used with 7000PC */
1138 if (state->revision == 0x4000 && dib7000m_read_word(state, 769) == 0x4000) {
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001139 dprintk( "this driver does not work with DiB7000PC");
Patrick Boettcher69ea31e2006-10-17 18:28:14 -03001140 return -EREMOTEIO;
1141 }
1142
1143 switch (state->revision) {
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001144 case 0x4000: dprintk( "found DiB7000MA/PA/MB/PB"); break;
1145 case 0x4001: state->reg_offs = 1; dprintk( "found DiB7000HC"); break;
1146 case 0x4002: state->reg_offs = 1; dprintk( "found DiB7000MC"); break;
1147 case 0x4003: state->reg_offs = 1; dprintk( "found DiB9000"); break;
Patrick Boettcher69ea31e2006-10-17 18:28:14 -03001148 }
1149
1150 return 0;
1151}
1152
Patrick Boettcher91bb9be2006-12-02 21:15:51 -02001153
Mauro Carvalho Chehab7e3e68b2016-02-04 12:58:30 -02001154static int dib7000m_get_frontend(struct dvb_frontend* fe,
1155 struct dtv_frontend_properties *fep)
Patrick Boettcher91bb9be2006-12-02 21:15:51 -02001156{
1157 struct dib7000m_state *state = fe->demodulator_priv;
1158 u16 tps = dib7000m_read_word(state,480);
1159
1160 fep->inversion = INVERSION_AUTO;
1161
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -03001162 fep->bandwidth_hz = BANDWIDTH_TO_HZ(state->current_bandwidth);
Patrick Boettcher91bb9be2006-12-02 21:15:51 -02001163
Patrick Boettcherd92532d2006-10-18 08:35:16 -03001164 switch ((tps >> 8) & 0x3) {
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -03001165 case 0: fep->transmission_mode = TRANSMISSION_MODE_2K; break;
1166 case 1: fep->transmission_mode = TRANSMISSION_MODE_8K; break;
1167 /* case 2: fep->transmission_mode = TRANSMISSION_MODE_4K; break; */
Patrick Boettcher91bb9be2006-12-02 21:15:51 -02001168 }
1169
1170 switch (tps & 0x3) {
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -03001171 case 0: fep->guard_interval = GUARD_INTERVAL_1_32; break;
1172 case 1: fep->guard_interval = GUARD_INTERVAL_1_16; break;
1173 case 2: fep->guard_interval = GUARD_INTERVAL_1_8; break;
1174 case 3: fep->guard_interval = GUARD_INTERVAL_1_4; break;
Patrick Boettcher91bb9be2006-12-02 21:15:51 -02001175 }
1176
1177 switch ((tps >> 14) & 0x3) {
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -03001178 case 0: fep->modulation = QPSK; break;
1179 case 1: fep->modulation = QAM_16; break;
Patrick Boettcher91bb9be2006-12-02 21:15:51 -02001180 case 2:
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -03001181 default: fep->modulation = QAM_64; break;
Patrick Boettcher91bb9be2006-12-02 21:15:51 -02001182 }
1183
1184 /* as long as the frontend_param structure is fixed for hierarchical transmission I refuse to use it */
1185 /* (tps >> 13) & 0x1 == hrch is used, (tps >> 10) & 0x7 == alpha */
1186
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -03001187 fep->hierarchy = HIERARCHY_NONE;
Patrick Boettcher91bb9be2006-12-02 21:15:51 -02001188 switch ((tps >> 5) & 0x7) {
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -03001189 case 1: fep->code_rate_HP = FEC_1_2; break;
1190 case 2: fep->code_rate_HP = FEC_2_3; break;
1191 case 3: fep->code_rate_HP = FEC_3_4; break;
1192 case 5: fep->code_rate_HP = FEC_5_6; break;
Patrick Boettcher91bb9be2006-12-02 21:15:51 -02001193 case 7:
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -03001194 default: fep->code_rate_HP = FEC_7_8; break;
Patrick Boettcher91bb9be2006-12-02 21:15:51 -02001195
1196 }
1197
1198 switch ((tps >> 2) & 0x7) {
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -03001199 case 1: fep->code_rate_LP = FEC_1_2; break;
1200 case 2: fep->code_rate_LP = FEC_2_3; break;
1201 case 3: fep->code_rate_LP = FEC_3_4; break;
1202 case 5: fep->code_rate_LP = FEC_5_6; break;
Patrick Boettcher91bb9be2006-12-02 21:15:51 -02001203 case 7:
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -03001204 default: fep->code_rate_LP = FEC_7_8; break;
Patrick Boettcher91bb9be2006-12-02 21:15:51 -02001205 }
1206
1207 /* native interleaver: (dib7000m_read_word(state, 481) >> 5) & 0x1 */
1208
1209 return 0;
1210}
1211
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -03001212static int dib7000m_set_frontend(struct dvb_frontend *fe)
Patrick Boettcher91bb9be2006-12-02 21:15:51 -02001213{
Mauro Carvalho Chehab7c61d802011-12-30 11:30:21 -03001214 struct dtv_frontend_properties *fep = &fe->dtv_property_cache;
Patrick Boettcher69ea31e2006-10-17 18:28:14 -03001215 struct dib7000m_state *state = fe->demodulator_priv;
Soeren Moch853ea132008-01-25 06:27:06 -03001216 int time, ret;
1217
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -03001218 dib7000m_set_output_mode(state, OUTMODE_HIGH_Z);
Patrick Boettcher69ea31e2006-10-17 18:28:14 -03001219
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -03001220 dib7000m_set_bandwidth(state, BANDWIDTH_TO_KHZ(fep->bandwidth_hz));
Patrick Boettcher69ea31e2006-10-17 18:28:14 -03001221
1222 if (fe->ops.tuner_ops.set_params)
Mauro Carvalho Chehab14d24d12011-12-24 12:24:33 -03001223 fe->ops.tuner_ops.set_params(fe);
Patrick Boettcher69ea31e2006-10-17 18:28:14 -03001224
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001225 /* start up the AGC */
1226 state->agc_state = 0;
1227 do {
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -03001228 time = dib7000m_agc_startup(fe);
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001229 if (time != -1)
1230 msleep(time);
1231 } while (time != -1);
1232
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -03001233 if (fep->transmission_mode == TRANSMISSION_MODE_AUTO ||
1234 fep->guard_interval == GUARD_INTERVAL_AUTO ||
1235 fep->modulation == QAM_AUTO ||
1236 fep->code_rate_HP == FEC_AUTO) {
Patrick Boettcher69ea31e2006-10-17 18:28:14 -03001237 int i = 800, found;
1238
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -03001239 dib7000m_autosearch_start(fe);
Patrick Boettcher69ea31e2006-10-17 18:28:14 -03001240 do {
1241 msleep(1);
1242 found = dib7000m_autosearch_is_irq(fe);
1243 } while (found == 0 && i--);
1244
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001245 dprintk("autosearch returns: %d",found);
Patrick Boettcher69ea31e2006-10-17 18:28:14 -03001246 if (found == 0 || found == 1)
1247 return 0; // no channel found
1248
Mauro Carvalho Chehab7e3e68b2016-02-04 12:58:30 -02001249 dib7000m_get_frontend(fe, fep);
Patrick Boettcher69ea31e2006-10-17 18:28:14 -03001250 }
1251
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -03001252 ret = dib7000m_tune(fe);
Soeren Moch853ea132008-01-25 06:27:06 -03001253
Patrick Boettcher69ea31e2006-10-17 18:28:14 -03001254 /* make this a config parameter */
1255 dib7000m_set_output_mode(state, OUTMODE_MPEG2_FIFO);
Soeren Moch853ea132008-01-25 06:27:06 -03001256 return ret;
Patrick Boettcher91bb9be2006-12-02 21:15:51 -02001257}
1258
Mauro Carvalho Chehab0df289a2015-06-07 14:53:52 -03001259static int dib7000m_read_status(struct dvb_frontend *fe, enum fe_status *stat)
Patrick Boettcher91bb9be2006-12-02 21:15:51 -02001260{
1261 struct dib7000m_state *state = fe->demodulator_priv;
Patrick Boettcher69ea31e2006-10-17 18:28:14 -03001262 u16 lock = dib7000m_read_word(state, 535);
Patrick Boettcher91bb9be2006-12-02 21:15:51 -02001263
1264 *stat = 0;
1265
1266 if (lock & 0x8000)
1267 *stat |= FE_HAS_SIGNAL;
1268 if (lock & 0x3000)
1269 *stat |= FE_HAS_CARRIER;
1270 if (lock & 0x0100)
1271 *stat |= FE_HAS_VITERBI;
1272 if (lock & 0x0010)
1273 *stat |= FE_HAS_SYNC;
1274 if (lock & 0x0008)
1275 *stat |= FE_HAS_LOCK;
1276
1277 return 0;
1278}
1279
1280static int dib7000m_read_ber(struct dvb_frontend *fe, u32 *ber)
1281{
1282 struct dib7000m_state *state = fe->demodulator_priv;
1283 *ber = (dib7000m_read_word(state, 526) << 16) | dib7000m_read_word(state, 527);
1284 return 0;
1285}
1286
1287static int dib7000m_read_unc_blocks(struct dvb_frontend *fe, u32 *unc)
1288{
1289 struct dib7000m_state *state = fe->demodulator_priv;
1290 *unc = dib7000m_read_word(state, 534);
1291 return 0;
1292}
1293
1294static int dib7000m_read_signal_strength(struct dvb_frontend *fe, u16 *strength)
1295{
1296 struct dib7000m_state *state = fe->demodulator_priv;
1297 u16 val = dib7000m_read_word(state, 390);
1298 *strength = 65535 - val;
1299 return 0;
1300}
1301
1302static int dib7000m_read_snr(struct dvb_frontend* fe, u16 *snr)
1303{
1304 *snr = 0x0000;
1305 return 0;
1306}
1307
1308static int dib7000m_fe_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings *tune)
1309{
1310 tune->min_delay_ms = 1000;
1311 return 0;
1312}
1313
Patrick Boettcher69ea31e2006-10-17 18:28:14 -03001314static void dib7000m_release(struct dvb_frontend *demod)
Patrick Boettcher91bb9be2006-12-02 21:15:51 -02001315{
Patrick Boettcher69ea31e2006-10-17 18:28:14 -03001316 struct dib7000m_state *st = demod->demodulator_priv;
1317 dibx000_exit_i2c_master(&st->i2c_master);
1318 kfree(st);
Patrick Boettcher91bb9be2006-12-02 21:15:51 -02001319}
1320
Patrick Boettcher69ea31e2006-10-17 18:28:14 -03001321struct i2c_adapter * dib7000m_get_i2c_master(struct dvb_frontend *demod, enum dibx000_i2c_interface intf, int gating)
Patrick Boettcher91bb9be2006-12-02 21:15:51 -02001322{
Patrick Boettcher69ea31e2006-10-17 18:28:14 -03001323 struct dib7000m_state *st = demod->demodulator_priv;
1324 return dibx000_get_i2c_adapter(&st->i2c_master, intf, gating);
1325}
1326EXPORT_SYMBOL(dib7000m_get_i2c_master);
1327
Olivier Greniee192a7c2011-01-14 13:58:59 -03001328int dib7000m_pid_filter_ctrl(struct dvb_frontend *fe, u8 onoff)
1329{
1330 struct dib7000m_state *state = fe->demodulator_priv;
1331 u16 val = dib7000m_read_word(state, 294 + state->reg_offs) & 0xffef;
1332 val |= (onoff & 0x1) << 4;
1333 dprintk("PID filter enabled %d", onoff);
1334 return dib7000m_write_word(state, 294 + state->reg_offs, val);
1335}
1336EXPORT_SYMBOL(dib7000m_pid_filter_ctrl);
1337
1338int dib7000m_pid_filter(struct dvb_frontend *fe, u8 id, u16 pid, u8 onoff)
1339{
1340 struct dib7000m_state *state = fe->demodulator_priv;
1341 dprintk("PID filter: index %x, PID %d, OnOff %d", id, pid, onoff);
1342 return dib7000m_write_word(state, 300 + state->reg_offs + id,
1343 onoff ? (1 << 13) | pid : 0);
1344}
1345EXPORT_SYMBOL(dib7000m_pid_filter);
1346
Hans Verkuil942648a2008-09-07 08:38:50 -03001347#if 0
1348/* used with some prototype boards */
1349int dib7000m_i2c_enumeration(struct i2c_adapter *i2c, int no_of_demods,
Hans Verkuild45b9b82008-09-04 03:33:43 -03001350 u8 default_addr, struct dib7000m_config cfg[])
Patrick Boettcher69ea31e2006-10-17 18:28:14 -03001351{
1352 struct dib7000m_state st = { .i2c_adap = i2c };
1353 int k = 0;
1354 u8 new_addr = 0;
1355
1356 for (k = no_of_demods-1; k >= 0; k--) {
1357 st.cfg = cfg[k];
1358
1359 /* designated i2c address */
1360 new_addr = (0x40 + k) << 1;
1361 st.i2c_addr = new_addr;
1362 if (dib7000m_identify(&st) != 0) {
1363 st.i2c_addr = default_addr;
1364 if (dib7000m_identify(&st) != 0) {
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001365 dprintk("DiB7000M #%d: not identified", k);
Patrick Boettcher69ea31e2006-10-17 18:28:14 -03001366 return -EIO;
1367 }
1368 }
1369
1370 /* start diversity to pull_down div_str - just for i2c-enumeration */
1371 dib7000m_set_output_mode(&st, OUTMODE_DIVERSITY);
1372
1373 dib7000m_write_word(&st, 1796, 0x0); // select DVB-T output
1374
1375 /* set new i2c address and force divstart */
1376 dib7000m_write_word(&st, 1794, (new_addr << 2) | 0x2);
1377
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001378 dprintk("IC %d initialized (to i2c_address 0x%x)", k, new_addr);
Patrick Boettcher69ea31e2006-10-17 18:28:14 -03001379 }
1380
1381 for (k = 0; k < no_of_demods; k++) {
1382 st.cfg = cfg[k];
1383 st.i2c_addr = (0x40 + k) << 1;
1384
1385 // unforce divstr
1386 dib7000m_write_word(&st,1794, st.i2c_addr << 2);
1387
1388 /* deactivate div - it was just for i2c-enumeration */
1389 dib7000m_set_output_mode(&st, OUTMODE_HIGH_Z);
1390 }
1391
Patrick Boettcher91bb9be2006-12-02 21:15:51 -02001392 return 0;
1393}
Patrick Boettcher69ea31e2006-10-17 18:28:14 -03001394EXPORT_SYMBOL(dib7000m_i2c_enumeration);
Hans Verkuil942648a2008-09-07 08:38:50 -03001395#endif
Patrick Boettcher91bb9be2006-12-02 21:15:51 -02001396
Patrick Boettcher69ea31e2006-10-17 18:28:14 -03001397static struct dvb_frontend_ops dib7000m_ops;
1398struct dvb_frontend * dib7000m_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr, struct dib7000m_config *cfg)
1399{
1400 struct dvb_frontend *demod;
1401 struct dib7000m_state *st;
1402 st = kzalloc(sizeof(struct dib7000m_state), GFP_KERNEL);
1403 if (st == NULL)
1404 return NULL;
1405
1406 memcpy(&st->cfg, cfg, sizeof(struct dib7000m_config));
1407 st->i2c_adap = i2c_adap;
1408 st->i2c_addr = i2c_addr;
1409
1410 demod = &st->demod;
1411 demod->demodulator_priv = st;
1412 memcpy(&st->demod.ops, &dib7000m_ops, sizeof(struct dvb_frontend_ops));
Patrick Boettcher79fcce32011-08-03 12:08:21 -03001413 mutex_init(&st->i2c_buffer_lock);
Patrick Boettcher69ea31e2006-10-17 18:28:14 -03001414
Patrick Boettcher3db78e52007-07-31 08:19:28 -03001415 st->timf_default = cfg->bw->timf;
1416
Patrick Boettcher69ea31e2006-10-17 18:28:14 -03001417 if (dib7000m_identify(st) != 0)
1418 goto error;
1419
1420 if (st->revision == 0x4000)
1421 dibx000_init_i2c_master(&st->i2c_master, DIB7000, st->i2c_adap, st->i2c_addr);
1422 else
1423 dibx000_init_i2c_master(&st->i2c_master, DIB7000MC, st->i2c_adap, st->i2c_addr);
1424
1425 dib7000m_demod_reset(st);
1426
1427 return demod;
1428
1429error:
1430 kfree(st);
1431 return NULL;
1432}
1433EXPORT_SYMBOL(dib7000m_attach);
Patrick Boettcher91bb9be2006-12-02 21:15:51 -02001434
1435static struct dvb_frontend_ops dib7000m_ops = {
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -03001436 .delsys = { SYS_DVBT },
Patrick Boettcher91bb9be2006-12-02 21:15:51 -02001437 .info = {
1438 .name = "DiBcom 7000MA/MB/PA/PB/MC",
Patrick Boettcher91bb9be2006-12-02 21:15:51 -02001439 .frequency_min = 44250000,
1440 .frequency_max = 867250000,
1441 .frequency_stepsize = 62500,
1442 .caps = FE_CAN_INVERSION_AUTO |
1443 FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
1444 FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
1445 FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO |
1446 FE_CAN_TRANSMISSION_MODE_AUTO |
1447 FE_CAN_GUARD_INTERVAL_AUTO |
1448 FE_CAN_RECOVER |
1449 FE_CAN_HIERARCHY_AUTO,
1450 },
1451
1452 .release = dib7000m_release,
1453
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001454 .init = dib7000m_wakeup,
Patrick Boettcher91bb9be2006-12-02 21:15:51 -02001455 .sleep = dib7000m_sleep,
1456
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -03001457 .set_frontend = dib7000m_set_frontend,
Patrick Boettcher91bb9be2006-12-02 21:15:51 -02001458 .get_tune_settings = dib7000m_fe_get_tune_settings,
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -03001459 .get_frontend = dib7000m_get_frontend,
Patrick Boettcher91bb9be2006-12-02 21:15:51 -02001460
1461 .read_status = dib7000m_read_status,
1462 .read_ber = dib7000m_read_ber,
1463 .read_signal_strength = dib7000m_read_signal_strength,
1464 .read_snr = dib7000m_read_snr,
1465 .read_ucblocks = dib7000m_read_unc_blocks,
1466};
1467
Patrick Boettcher99e44da2016-01-24 12:56:58 -02001468MODULE_AUTHOR("Patrick Boettcher <patrick.boettcher@posteo.de>");
Patrick Boettcher91bb9be2006-12-02 21:15:51 -02001469MODULE_DESCRIPTION("Driver for the DiBcom 7000MA/MB/PA/PB/MC COFDM demodulator");
1470MODULE_LICENSE("GPL");