blob: 389db9077ad5530b5d3997e9c2ca5f7a35b50078 [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 */
Mauro Carvalho Chehab75702272016-10-14 08:57:27 -030011
12#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
13
Patrick Boettcher91bb9be2006-12-02 21:15:51 -020014#include <linux/kernel.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090015#include <linux/slab.h>
Patrick Boettcher91bb9be2006-12-02 21:15:51 -020016#include <linux/i2c.h>
Patrick Boettcher79fcce32011-08-03 12:08:21 -030017#include <linux/mutex.h>
Patrick Boettcher91bb9be2006-12-02 21:15:51 -020018
Mauro Carvalho Chehabfada1932017-12-28 13:03:51 -050019#include <media/dvb_frontend.h>
Patrick Boettcher91bb9be2006-12-02 21:15:51 -020020
21#include "dib7000m.h"
22
23static int debug;
24module_param(debug, int, 0644);
25MODULE_PARM_DESC(debug, "turn on debugging (default: 0)");
26
Mauro Carvalho Chehab75702272016-10-14 08:57:27 -030027#define dprintk(fmt, arg...) do { \
28 if (debug) \
29 printk(KERN_DEBUG pr_fmt("%s: " fmt), \
30 __func__, ##arg); \
31} while (0)
Patrick Boettcher91bb9be2006-12-02 21:15:51 -020032
33struct dib7000m_state {
34 struct dvb_frontend demod;
35 struct dib7000m_config cfg;
36
37 u8 i2c_addr;
38 struct i2c_adapter *i2c_adap;
39
40 struct dibx000_i2c_master i2c_master;
41
42/* offset is 1 in case of the 7000MC */
43 u8 reg_offs;
44
45 u16 wbd_ref;
46
47 u8 current_band;
Mauro Carvalho Chehab88ab8982011-12-26 20:01:24 -030048 u32 current_bandwidth;
Patrick Boettcher91bb9be2006-12-02 21:15:51 -020049 struct dibx000_agc_config *current_agc;
Patrick Boettcher69ea31e2006-10-17 18:28:14 -030050 u32 timf;
Patrick Boettcherb6884a12007-07-27 10:08:51 -030051 u32 timf_default;
52 u32 internal_clk;
53
Patrick Boettcher01373a52007-07-30 12:49:04 -030054 u8 div_force_off : 1;
55 u8 div_state : 1;
56 u16 div_sync_wait;
Patrick Boettcher91bb9be2006-12-02 21:15:51 -020057
58 u16 revision;
Patrick Boettcherb6884a12007-07-27 10:08:51 -030059
60 u8 agc_state;
Olivier Grenie5a0deee2011-05-03 12:27:33 -030061
62 /* for the I2C transfer */
63 struct i2c_msg msg[2];
64 u8 i2c_write_buffer[4];
65 u8 i2c_read_buffer[2];
Patrick Boettcher79fcce32011-08-03 12:08:21 -030066 struct mutex i2c_buffer_lock;
Patrick Boettcher91bb9be2006-12-02 21:15:51 -020067};
68
Patrick Boettcher69ea31e2006-10-17 18:28:14 -030069enum dib7000m_power_mode {
70 DIB7000M_POWER_ALL = 0,
71
72 DIB7000M_POWER_NO,
73 DIB7000M_POWER_INTERF_ANALOG_AGC,
74 DIB7000M_POWER_COR4_DINTLV_ICIRM_EQUAL_CFROD,
75 DIB7000M_POWER_COR4_CRY_ESRAM_MOUT_NUD,
76 DIB7000M_POWER_INTERFACE_ONLY,
77};
78
Patrick Boettcher91bb9be2006-12-02 21:15:51 -020079static u16 dib7000m_read_word(struct dib7000m_state *state, u16 reg)
80{
Patrick Boettcher79fcce32011-08-03 12:08:21 -030081 u16 ret;
82
83 if (mutex_lock_interruptible(&state->i2c_buffer_lock) < 0) {
Mauro Carvalho Chehab75702272016-10-14 08:57:27 -030084 dprintk("could not acquire lock\n");
Patrick Boettcher79fcce32011-08-03 12:08:21 -030085 return 0;
86 }
87
Olivier Grenie5a0deee2011-05-03 12:27:33 -030088 state->i2c_write_buffer[0] = (reg >> 8) | 0x80;
89 state->i2c_write_buffer[1] = reg & 0xff;
Patrick Boettcher91bb9be2006-12-02 21:15:51 -020090
Olivier Grenie5a0deee2011-05-03 12:27:33 -030091 memset(state->msg, 0, 2 * sizeof(struct i2c_msg));
92 state->msg[0].addr = state->i2c_addr >> 1;
93 state->msg[0].flags = 0;
94 state->msg[0].buf = state->i2c_write_buffer;
95 state->msg[0].len = 2;
96 state->msg[1].addr = state->i2c_addr >> 1;
97 state->msg[1].flags = I2C_M_RD;
98 state->msg[1].buf = state->i2c_read_buffer;
99 state->msg[1].len = 2;
100
101 if (i2c_transfer(state->i2c_adap, state->msg, 2) != 2)
Mauro Carvalho Chehab75702272016-10-14 08:57:27 -0300102 dprintk("i2c read error on %d\n", reg);
Patrick Boettcher91bb9be2006-12-02 21:15:51 -0200103
Patrick Boettcher79fcce32011-08-03 12:08:21 -0300104 ret = (state->i2c_read_buffer[0] << 8) | state->i2c_read_buffer[1];
105 mutex_unlock(&state->i2c_buffer_lock);
106
107 return ret;
Patrick Boettcher91bb9be2006-12-02 21:15:51 -0200108}
109
Patrick Boettcher91bb9be2006-12-02 21:15:51 -0200110static int dib7000m_write_word(struct dib7000m_state *state, u16 reg, u16 val)
111{
Patrick Boettcher79fcce32011-08-03 12:08:21 -0300112 int ret;
113
114 if (mutex_lock_interruptible(&state->i2c_buffer_lock) < 0) {
Mauro Carvalho Chehab75702272016-10-14 08:57:27 -0300115 dprintk("could not acquire lock\n");
Patrick Boettcher79fcce32011-08-03 12:08:21 -0300116 return -EINVAL;
117 }
118
Olivier Grenie5a0deee2011-05-03 12:27:33 -0300119 state->i2c_write_buffer[0] = (reg >> 8) & 0xff;
120 state->i2c_write_buffer[1] = reg & 0xff;
121 state->i2c_write_buffer[2] = (val >> 8) & 0xff;
122 state->i2c_write_buffer[3] = val & 0xff;
123
124 memset(&state->msg[0], 0, sizeof(struct i2c_msg));
125 state->msg[0].addr = state->i2c_addr >> 1;
126 state->msg[0].flags = 0;
127 state->msg[0].buf = state->i2c_write_buffer;
128 state->msg[0].len = 4;
129
Patrick Boettcher79fcce32011-08-03 12:08:21 -0300130 ret = (i2c_transfer(state->i2c_adap, state->msg, 1) != 1 ?
131 -EREMOTEIO : 0);
132 mutex_unlock(&state->i2c_buffer_lock);
133 return ret;
Patrick Boettcher91bb9be2006-12-02 21:15:51 -0200134}
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300135static void dib7000m_write_tab(struct dib7000m_state *state, u16 *buf)
136{
137 u16 l = 0, r, *n;
138 n = buf;
139 l = *n++;
140 while (l) {
141 r = *n++;
142
143 if (state->reg_offs && (r >= 112 && r <= 331)) // compensate for 7000MC
144 r++;
145
146 do {
147 dib7000m_write_word(state, r, *n++);
148 r++;
149 } while (--l);
150 l = *n++;
151 }
152}
153
Patrick Boettcher69ea31e2006-10-17 18:28:14 -0300154static int dib7000m_set_output_mode(struct dib7000m_state *state, int mode)
155{
156 int ret = 0;
157 u16 outreg, fifo_threshold, smo_mode,
158 sram = 0x0005; /* by default SRAM output is disabled */
159
160 outreg = 0;
161 fifo_threshold = 1792;
162 smo_mode = (dib7000m_read_word(state, 294 + state->reg_offs) & 0x0010) | (1 << 1);
163
Mauro Carvalho Chehab75702272016-10-14 08:57:27 -0300164 dprintk("setting output mode for demod %p to %d\n", &state->demod, mode);
Patrick Boettcher69ea31e2006-10-17 18:28:14 -0300165
166 switch (mode) {
167 case OUTMODE_MPEG2_PAR_GATED_CLK: // STBs with parallel gated clock
168 outreg = (1 << 10); /* 0x0400 */
169 break;
170 case OUTMODE_MPEG2_PAR_CONT_CLK: // STBs with parallel continues clock
171 outreg = (1 << 10) | (1 << 6); /* 0x0440 */
172 break;
173 case OUTMODE_MPEG2_SERIAL: // STBs with serial input
174 outreg = (1 << 10) | (2 << 6) | (0 << 1); /* 0x0482 */
175 break;
176 case OUTMODE_DIVERSITY:
177 if (state->cfg.hostbus_diversity)
178 outreg = (1 << 10) | (4 << 6); /* 0x0500 */
179 else
180 sram |= 0x0c00;
181 break;
182 case OUTMODE_MPEG2_FIFO: // e.g. USB feeding
183 smo_mode |= (3 << 1);
184 fifo_threshold = 512;
185 outreg = (1 << 10) | (5 << 6);
186 break;
187 case OUTMODE_HIGH_Z: // disable
188 outreg = 0;
189 break;
190 default:
Mauro Carvalho Chehab75702272016-10-14 08:57:27 -0300191 dprintk("Unhandled output_mode passed to be set for demod %p\n", &state->demod);
Patrick Boettcher69ea31e2006-10-17 18:28:14 -0300192 break;
193 }
194
195 if (state->cfg.output_mpeg2_in_188_bytes)
196 smo_mode |= (1 << 5) ;
197
198 ret |= dib7000m_write_word(state, 294 + state->reg_offs, smo_mode);
199 ret |= dib7000m_write_word(state, 295 + state->reg_offs, fifo_threshold); /* synchronous fread */
200 ret |= dib7000m_write_word(state, 1795, outreg);
201 ret |= dib7000m_write_word(state, 1805, sram);
202
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300203 if (state->revision == 0x4003) {
204 u16 clk_cfg1 = dib7000m_read_word(state, 909) & 0xfffd;
205 if (mode == OUTMODE_DIVERSITY)
206 clk_cfg1 |= (1 << 1); // P_O_CLK_en
207 dib7000m_write_word(state, 909, clk_cfg1);
208 }
Patrick Boettcher69ea31e2006-10-17 18:28:14 -0300209 return ret;
210}
211
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300212static void dib7000m_set_power_mode(struct dib7000m_state *state, enum dib7000m_power_mode mode)
Patrick Boettcher69ea31e2006-10-17 18:28:14 -0300213{
214 /* by default everything is going to be powered off */
215 u16 reg_903 = 0xffff, reg_904 = 0xffff, reg_905 = 0xffff, reg_906 = 0x3fff;
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300216 u8 offset = 0;
Patrick Boettcher69ea31e2006-10-17 18:28:14 -0300217
218 /* now, depending on the requested mode, we power on */
219 switch (mode) {
220 /* power up everything in the demod */
221 case DIB7000M_POWER_ALL:
222 reg_903 = 0x0000; reg_904 = 0x0000; reg_905 = 0x0000; reg_906 = 0x0000;
223 break;
224
225 /* just leave power on the control-interfaces: GPIO and (I2C or SDIO or SRAM) */
226 case DIB7000M_POWER_INTERFACE_ONLY: /* TODO power up either SDIO or I2C or SRAM */
227 reg_905 &= ~((1 << 7) | (1 << 6) | (1 << 5) | (1 << 2));
228 break;
229
230 case DIB7000M_POWER_INTERF_ANALOG_AGC:
231 reg_903 &= ~((1 << 15) | (1 << 14) | (1 << 11) | (1 << 10));
232 reg_905 &= ~((1 << 7) | (1 << 6) | (1 << 5) | (1 << 4) | (1 << 2));
233 reg_906 &= ~((1 << 0));
234 break;
235
236 case DIB7000M_POWER_COR4_DINTLV_ICIRM_EQUAL_CFROD:
237 reg_903 = 0x0000; reg_904 = 0x801f; reg_905 = 0x0000; reg_906 = 0x0000;
238 break;
239
240 case DIB7000M_POWER_COR4_CRY_ESRAM_MOUT_NUD:
241 reg_903 = 0x0000; reg_904 = 0x8000; reg_905 = 0x010b; reg_906 = 0x0000;
242 break;
243 case DIB7000M_POWER_NO:
244 break;
245 }
246
247 /* always power down unused parts */
248 if (!state->cfg.mobile_mode)
249 reg_904 |= (1 << 7) | (1 << 6) | (1 << 4) | (1 << 2) | (1 << 1);
250
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300251 /* P_sdio_select_clk = 0 on MC and after*/
Patrick Boettcher69ea31e2006-10-17 18:28:14 -0300252 if (state->revision != 0x4000)
253 reg_906 <<= 1;
254
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300255 if (state->revision == 0x4003)
256 offset = 1;
Patrick Boettcher69ea31e2006-10-17 18:28:14 -0300257
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300258 dib7000m_write_word(state, 903 + offset, reg_903);
259 dib7000m_write_word(state, 904 + offset, reg_904);
260 dib7000m_write_word(state, 905 + offset, reg_905);
261 dib7000m_write_word(state, 906 + offset, reg_906);
Patrick Boettcher69ea31e2006-10-17 18:28:14 -0300262}
263
264static int dib7000m_set_adc_state(struct dib7000m_state *state, enum dibx000_adc_states no)
265{
266 int ret = 0;
267 u16 reg_913 = dib7000m_read_word(state, 913),
268 reg_914 = dib7000m_read_word(state, 914);
269
270 switch (no) {
271 case DIBX000_SLOW_ADC_ON:
272 reg_914 |= (1 << 1) | (1 << 0);
273 ret |= dib7000m_write_word(state, 914, reg_914);
274 reg_914 &= ~(1 << 1);
275 break;
276
277 case DIBX000_SLOW_ADC_OFF:
278 reg_914 |= (1 << 1) | (1 << 0);
279 break;
280
281 case DIBX000_ADC_ON:
282 if (state->revision == 0x4000) { // workaround for PA/MA
283 // power-up ADC
284 dib7000m_write_word(state, 913, 0);
285 dib7000m_write_word(state, 914, reg_914 & 0x3);
286 // power-down bandgag
287 dib7000m_write_word(state, 913, (1 << 15));
288 dib7000m_write_word(state, 914, reg_914 & 0x3);
289 }
290
291 reg_913 &= 0x0fff;
292 reg_914 &= 0x0003;
293 break;
294
295 case DIBX000_ADC_OFF: // leave the VBG voltage on
296 reg_913 |= (1 << 14) | (1 << 13) | (1 << 12);
297 reg_914 |= (1 << 5) | (1 << 4) | (1 << 3) | (1 << 2);
298 break;
299
300 case DIBX000_VBG_ENABLE:
301 reg_913 &= ~(1 << 15);
302 break;
303
304 case DIBX000_VBG_DISABLE:
305 reg_913 |= (1 << 15);
306 break;
307
308 default:
309 break;
310 }
311
Mauro Carvalho Chehab75702272016-10-14 08:57:27 -0300312// dprintk("913: %x, 914: %x\n", reg_913, reg_914);
Patrick Boettcher69ea31e2006-10-17 18:28:14 -0300313 ret |= dib7000m_write_word(state, 913, reg_913);
314 ret |= dib7000m_write_word(state, 914, reg_914);
315
316 return ret;
317}
318
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300319static int dib7000m_set_bandwidth(struct dib7000m_state *state, u32 bw)
Patrick Boettcher69ea31e2006-10-17 18:28:14 -0300320{
Patrick Boettcher69ea31e2006-10-17 18:28:14 -0300321 u32 timf;
322
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -0300323 if (!bw)
324 bw = 8000;
325
Patrick Boettcher69ea31e2006-10-17 18:28:14 -0300326 // store the current bandwidth for later use
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300327 state->current_bandwidth = bw;
Patrick Boettcher69ea31e2006-10-17 18:28:14 -0300328
329 if (state->timf == 0) {
Mauro Carvalho Chehab75702272016-10-14 08:57:27 -0300330 dprintk("using default timf\n");
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300331 timf = state->timf_default;
Patrick Boettcher69ea31e2006-10-17 18:28:14 -0300332 } else {
Mauro Carvalho Chehab75702272016-10-14 08:57:27 -0300333 dprintk("using updated timf\n");
Patrick Boettcher69ea31e2006-10-17 18:28:14 -0300334 timf = state->timf;
335 }
336
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300337 timf = timf * (bw / 50) / 160;
Patrick Boettcher69ea31e2006-10-17 18:28:14 -0300338
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300339 dib7000m_write_word(state, 23, (u16) ((timf >> 16) & 0xffff));
340 dib7000m_write_word(state, 24, (u16) ((timf ) & 0xffff));
341
342 return 0;
343}
344
345static int dib7000m_set_diversity_in(struct dvb_frontend *demod, int onoff)
346{
347 struct dib7000m_state *state = demod->demodulator_priv;
348
349 if (state->div_force_off) {
Mauro Carvalho Chehab75702272016-10-14 08:57:27 -0300350 dprintk("diversity combination deactivated - forced by COFDM parameters\n");
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300351 onoff = 0;
352 }
Patrick Boettcher01373a52007-07-30 12:49:04 -0300353 state->div_state = (u8)onoff;
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300354
355 if (onoff) {
356 dib7000m_write_word(state, 263 + state->reg_offs, 6);
357 dib7000m_write_word(state, 264 + state->reg_offs, 6);
358 dib7000m_write_word(state, 266 + state->reg_offs, (state->div_sync_wait << 4) | (1 << 2) | (2 << 0));
359 } else {
360 dib7000m_write_word(state, 263 + state->reg_offs, 1);
361 dib7000m_write_word(state, 264 + state->reg_offs, 0);
362 dib7000m_write_word(state, 266 + state->reg_offs, 0);
363 }
Patrick Boettcher69ea31e2006-10-17 18:28:14 -0300364
365 return 0;
366}
367
368static int dib7000m_sad_calib(struct dib7000m_state *state)
369{
370
371/* internal */
Mauro Carvalho Chehab868c9a12019-02-18 14:28:55 -0500372// dib7000m_write_word(state, 928, (3 << 14) | (1 << 12) | (524 << 0)); // sampling clock of the SAD is writing in set_bandwidth
Patrick Boettcher69ea31e2006-10-17 18:28:14 -0300373 dib7000m_write_word(state, 929, (0 << 1) | (0 << 0));
374 dib7000m_write_word(state, 930, 776); // 0.625*3.3 / 4096
375
376 /* do the calibration */
377 dib7000m_write_word(state, 929, (1 << 0));
378 dib7000m_write_word(state, 929, (0 << 0));
379
380 msleep(1);
381
382 return 0;
383}
384
385static void dib7000m_reset_pll_common(struct dib7000m_state *state, const struct dibx000_bandwidth_config *bw)
386{
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300387 dib7000m_write_word(state, 18, (u16) (((bw->internal*1000) >> 16) & 0xffff));
388 dib7000m_write_word(state, 19, (u16) ( (bw->internal*1000) & 0xffff));
389 dib7000m_write_word(state, 21, (u16) ( (bw->ifreq >> 16) & 0xffff));
390 dib7000m_write_word(state, 22, (u16) ( bw->ifreq & 0xffff));
Patrick Boettcher69ea31e2006-10-17 18:28:14 -0300391
392 dib7000m_write_word(state, 928, bw->sad_cfg);
393}
394
395static void dib7000m_reset_pll(struct dib7000m_state *state)
396{
397 const struct dibx000_bandwidth_config *bw = state->cfg.bw;
398 u16 reg_907,reg_910;
399
400 /* default */
401 reg_907 = (bw->pll_bypass << 15) | (bw->modulo << 7) |
402 (bw->ADClkSrc << 6) | (bw->IO_CLK_en_core << 5) | (bw->bypclk_div << 2) |
403 (bw->enable_refdiv << 1) | (0 << 0);
404 reg_910 = (((bw->pll_ratio >> 6) & 0x3) << 3) | (bw->pll_range << 1) | bw->pll_reset;
405
406 // for this oscillator frequency should be 30 MHz for the Master (default values in the board_parameters give that value)
407 // this is only working only for 30 MHz crystals
408 if (!state->cfg.quartz_direct) {
409 reg_910 |= (1 << 5); // forcing the predivider to 1
410
411 // if the previous front-end is baseband, its output frequency is 15 MHz (prev freq divided by 2)
412 if(state->cfg.input_clk_is_div_2)
413 reg_907 |= (16 << 9);
414 else // otherwise the previous front-end puts out its input (default 30MHz) - no extra division necessary
415 reg_907 |= (8 << 9);
416 } else {
417 reg_907 |= (bw->pll_ratio & 0x3f) << 9;
418 reg_910 |= (bw->pll_prediv << 5);
419 }
420
421 dib7000m_write_word(state, 910, reg_910); // pll cfg
422 dib7000m_write_word(state, 907, reg_907); // clk cfg0
423 dib7000m_write_word(state, 908, 0x0006); // clk_cfg1
424
425 dib7000m_reset_pll_common(state, bw);
426}
427
428static void dib7000mc_reset_pll(struct dib7000m_state *state)
429{
430 const struct dibx000_bandwidth_config *bw = state->cfg.bw;
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300431 u16 clk_cfg1;
Patrick Boettcher69ea31e2006-10-17 18:28:14 -0300432
433 // clk_cfg0
434 dib7000m_write_word(state, 907, (bw->pll_prediv << 8) | (bw->pll_ratio << 0));
435
436 // clk_cfg1
437 //dib7000m_write_word(state, 908, (1 << 14) | (3 << 12) |(0 << 11) |
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300438 clk_cfg1 = (0 << 14) | (3 << 12) |(0 << 11) |
Patrick Boettcher69ea31e2006-10-17 18:28:14 -0300439 (bw->IO_CLK_en_core << 10) | (bw->bypclk_div << 5) | (bw->enable_refdiv << 4) |
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300440 (1 << 3) | (bw->pll_range << 1) | (bw->pll_reset << 0);
441 dib7000m_write_word(state, 908, clk_cfg1);
442 clk_cfg1 = (clk_cfg1 & 0xfff7) | (bw->pll_bypass << 3);
443 dib7000m_write_word(state, 908, clk_cfg1);
Patrick Boettcher69ea31e2006-10-17 18:28:14 -0300444
445 // smpl_cfg
446 dib7000m_write_word(state, 910, (1 << 12) | (2 << 10) | (bw->modulo << 8) | (bw->ADClkSrc << 7));
447
448 dib7000m_reset_pll_common(state, bw);
449}
450
451static int dib7000m_reset_gpio(struct dib7000m_state *st)
452{
453 /* reset the GPIOs */
Patrick Boettcher69ea31e2006-10-17 18:28:14 -0300454 dib7000m_write_word(st, 773, st->cfg.gpio_dir);
455 dib7000m_write_word(st, 774, st->cfg.gpio_val);
456
457 /* TODO 782 is P_gpio_od */
458
459 dib7000m_write_word(st, 775, st->cfg.gpio_pwm_pos);
460
461 dib7000m_write_word(st, 780, st->cfg.pwm_freq_div);
462 return 0;
463}
464
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300465static u16 dib7000m_defaults_common[] =
466
467{
468 // auto search configuration
469 3, 2,
470 0x0004,
471 0x1000,
472 0x0814,
473
474 12, 6,
475 0x001b,
476 0x7740,
477 0x005b,
478 0x8d80,
479 0x01c9,
480 0xc380,
481 0x0000,
482 0x0080,
483 0x0000,
484 0x0090,
485 0x0001,
486 0xd4c0,
487
488 1, 26,
489 0x6680, // P_corm_thres Lock algorithms configuration
490
491 1, 170,
492 0x0410, // P_palf_alpha_regul, P_palf_filter_freeze, P_palf_filter_on
493
494 8, 173,
495 0,
496 0,
497 0,
498 0,
499 0,
500 0,
501 0,
502 0,
503
504 1, 182,
505 8192, // P_fft_nb_to_cut
506
507 2, 195,
508 0x0ccd, // P_pha3_thres
509 0, // P_cti_use_cpe, P_cti_use_prog
510
511 1, 205,
512 0x200f, // P_cspu_regul, P_cspu_win_cut
513
514 5, 214,
515 0x023d, // P_adp_regul_cnt
516 0x00a4, // P_adp_noise_cnt
517 0x00a4, // P_adp_regul_ext
518 0x7ff0, // P_adp_noise_ext
519 0x3ccc, // P_adp_fil
520
521 1, 226,
522 0, // P_2d_byp_ti_num
523
524 1, 255,
525 0x800, // P_equal_thres_wgn
526
527 1, 263,
528 0x0001,
529
530 1, 281,
531 0x0010, // P_fec_*
532
533 1, 294,
534 0x0062, // P_smo_mode, P_smo_rs_discard, P_smo_fifo_flush, P_smo_pid_parse, P_smo_error_discard
535
536 0
537};
538
539static u16 dib7000m_defaults[] =
540
541{
542 /* set ADC level to -16 */
543 11, 76,
544 (1 << 13) - 825 - 117,
545 (1 << 13) - 837 - 117,
546 (1 << 13) - 811 - 117,
547 (1 << 13) - 766 - 117,
548 (1 << 13) - 737 - 117,
549 (1 << 13) - 693 - 117,
550 (1 << 13) - 648 - 117,
551 (1 << 13) - 619 - 117,
552 (1 << 13) - 575 - 117,
553 (1 << 13) - 531 - 117,
554 (1 << 13) - 501 - 117,
555
556 // Tuner IO bank: max drive (14mA)
557 1, 912,
558 0x2c8a,
559
560 1, 1817,
561 1,
562
563 0,
564};
565
Patrick Boettcher69ea31e2006-10-17 18:28:14 -0300566static int dib7000m_demod_reset(struct dib7000m_state *state)
567{
568 dib7000m_set_power_mode(state, DIB7000M_POWER_ALL);
569
570 /* always leave the VBG voltage on - it consumes almost nothing but takes a long time to start */
571 dib7000m_set_adc_state(state, DIBX000_VBG_ENABLE);
572
573 /* restart all parts */
574 dib7000m_write_word(state, 898, 0xffff);
575 dib7000m_write_word(state, 899, 0xffff);
576 dib7000m_write_word(state, 900, 0xff0f);
577 dib7000m_write_word(state, 901, 0xfffc);
578
579 dib7000m_write_word(state, 898, 0);
580 dib7000m_write_word(state, 899, 0);
581 dib7000m_write_word(state, 900, 0);
582 dib7000m_write_word(state, 901, 0);
583
584 if (state->revision == 0x4000)
585 dib7000m_reset_pll(state);
586 else
587 dib7000mc_reset_pll(state);
588
589 if (dib7000m_reset_gpio(state) != 0)
Mauro Carvalho Chehab75702272016-10-14 08:57:27 -0300590 dprintk("GPIO reset was not successful.\n");
Patrick Boettcher69ea31e2006-10-17 18:28:14 -0300591
592 if (dib7000m_set_output_mode(state, OUTMODE_HIGH_Z) != 0)
Mauro Carvalho Chehab75702272016-10-14 08:57:27 -0300593 dprintk("OUTPUT_MODE could not be reset.\n");
Patrick Boettcher69ea31e2006-10-17 18:28:14 -0300594
595 /* unforce divstr regardless whether i2c enumeration was done or not */
596 dib7000m_write_word(state, 1794, dib7000m_read_word(state, 1794) & ~(1 << 1) );
597
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300598 dib7000m_set_bandwidth(state, 8000);
Patrick Boettcher69ea31e2006-10-17 18:28:14 -0300599
600 dib7000m_set_adc_state(state, DIBX000_SLOW_ADC_ON);
601 dib7000m_sad_calib(state);
602 dib7000m_set_adc_state(state, DIBX000_SLOW_ADC_OFF);
603
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300604 if (state->cfg.dvbt_mode)
605 dib7000m_write_word(state, 1796, 0x0); // select DVB-T output
606
607 if (state->cfg.mobile_mode)
608 dib7000m_write_word(state, 261 + state->reg_offs, 2);
609 else
610 dib7000m_write_word(state, 224 + state->reg_offs, 1);
611
612 // P_iqc_alpha_pha, P_iqc_alpha_amp, P_iqc_dcc_alpha, ...
613 if(state->cfg.tuner_is_baseband)
614 dib7000m_write_word(state, 36, 0x0755);
615 else
616 dib7000m_write_word(state, 36, 0x1f55);
617
618 // P_divclksel=3 P_divbitsel=1
619 if (state->revision == 0x4000)
620 dib7000m_write_word(state, 909, (3 << 10) | (1 << 6));
621 else
622 dib7000m_write_word(state, 909, (3 << 4) | 1);
623
624 dib7000m_write_tab(state, dib7000m_defaults_common);
625 dib7000m_write_tab(state, dib7000m_defaults);
626
Patrick Boettcher69ea31e2006-10-17 18:28:14 -0300627 dib7000m_set_power_mode(state, DIB7000M_POWER_INTERFACE_ONLY);
628
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300629 state->internal_clk = state->cfg.bw->internal;
630
Patrick Boettcher69ea31e2006-10-17 18:28:14 -0300631 return 0;
632}
633
634static void dib7000m_restart_agc(struct dib7000m_state *state)
635{
636 // P_restart_iqc & P_restart_agc
637 dib7000m_write_word(state, 898, 0x0c00);
638 dib7000m_write_word(state, 898, 0x0000);
639}
640
641static int dib7000m_agc_soft_split(struct dib7000m_state *state)
642{
643 u16 agc,split_offset;
644
645 if(!state->current_agc || !state->current_agc->perform_agc_softsplit || state->current_agc->split.max == 0)
646 return 0;
647
648 // n_agc_global
649 agc = dib7000m_read_word(state, 390);
650
651 if (agc > state->current_agc->split.min_thres)
652 split_offset = state->current_agc->split.min;
653 else if (agc < state->current_agc->split.max_thres)
654 split_offset = state->current_agc->split.max;
655 else
656 split_offset = state->current_agc->split.max *
657 (agc - state->current_agc->split.min_thres) /
658 (state->current_agc->split.max_thres - state->current_agc->split.min_thres);
659
Mauro Carvalho Chehab75702272016-10-14 08:57:27 -0300660 dprintk("AGC split_offset: %d\n", split_offset);
Patrick Boettcher69ea31e2006-10-17 18:28:14 -0300661
662 // P_agc_force_split and P_agc_split_offset
663 return dib7000m_write_word(state, 103, (dib7000m_read_word(state, 103) & 0xff00) | split_offset);
664}
665
666static int dib7000m_update_lna(struct dib7000m_state *state)
667{
Patrick Boettcher69ea31e2006-10-17 18:28:14 -0300668 u16 dyn_gain;
669
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300670 if (state->cfg.update_lna) {
Patrick Boettcher01373a52007-07-30 12:49:04 -0300671 // read dyn_gain here (because it is demod-dependent and not fe)
Patrick Boettcher69ea31e2006-10-17 18:28:14 -0300672 dyn_gain = dib7000m_read_word(state, 390);
673
Patrick Boettcher69ea31e2006-10-17 18:28:14 -0300674 if (state->cfg.update_lna(&state->demod,dyn_gain)) { // LNA has changed
675 dib7000m_restart_agc(state);
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300676 return 1;
677 }
Patrick Boettcher69ea31e2006-10-17 18:28:14 -0300678 }
679 return 0;
680}
681
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300682static int dib7000m_set_agc_config(struct dib7000m_state *state, u8 band)
Patrick Boettcher69ea31e2006-10-17 18:28:14 -0300683{
684 struct dibx000_agc_config *agc = NULL;
685 int i;
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300686 if (state->current_band == band && state->current_agc != NULL)
687 return 0;
Patrick Boettcher69ea31e2006-10-17 18:28:14 -0300688 state->current_band = band;
689
690 for (i = 0; i < state->cfg.agc_config_count; i++)
691 if (state->cfg.agc[i].band_caps & band) {
692 agc = &state->cfg.agc[i];
693 break;
694 }
695
696 if (agc == NULL) {
Mauro Carvalho Chehab75702272016-10-14 08:57:27 -0300697 dprintk("no valid AGC configuration found for band 0x%02x\n", band);
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300698 return -EINVAL;
Patrick Boettcher69ea31e2006-10-17 18:28:14 -0300699 }
700
701 state->current_agc = agc;
702
703 /* AGC */
704 dib7000m_write_word(state, 72 , agc->setup);
705 dib7000m_write_word(state, 73 , agc->inv_gain);
706 dib7000m_write_word(state, 74 , agc->time_stabiliz);
707 dib7000m_write_word(state, 97 , (agc->alpha_level << 12) | agc->thlock);
708
709 // Demod AGC loop configuration
710 dib7000m_write_word(state, 98, (agc->alpha_mant << 5) | agc->alpha_exp);
711 dib7000m_write_word(state, 99, (agc->beta_mant << 6) | agc->beta_exp);
712
Mauro Carvalho Chehab75702272016-10-14 08:57:27 -0300713 dprintk("WBD: ref: %d, sel: %d, active: %d, alpha: %d\n",
Patrick Boettcher69ea31e2006-10-17 18:28:14 -0300714 state->wbd_ref != 0 ? state->wbd_ref : agc->wbd_ref, agc->wbd_sel, !agc->perform_agc_softsplit, agc->wbd_sel);
715
716 /* AGC continued */
717 if (state->wbd_ref != 0)
718 dib7000m_write_word(state, 102, state->wbd_ref);
719 else // use default
720 dib7000m_write_word(state, 102, agc->wbd_ref);
721
722 dib7000m_write_word(state, 103, (agc->wbd_alpha << 9) | (agc->perform_agc_softsplit << 8) );
723 dib7000m_write_word(state, 104, agc->agc1_max);
724 dib7000m_write_word(state, 105, agc->agc1_min);
725 dib7000m_write_word(state, 106, agc->agc2_max);
726 dib7000m_write_word(state, 107, agc->agc2_min);
727 dib7000m_write_word(state, 108, (agc->agc1_pt1 << 8) | agc->agc1_pt2 );
728 dib7000m_write_word(state, 109, (agc->agc1_slope1 << 8) | agc->agc1_slope2);
729 dib7000m_write_word(state, 110, (agc->agc2_pt1 << 8) | agc->agc2_pt2);
730 dib7000m_write_word(state, 111, (agc->agc2_slope1 << 8) | agc->agc2_slope2);
731
732 if (state->revision > 0x4000) { // settings for the MC
733 dib7000m_write_word(state, 71, agc->agc1_pt3);
Mauro Carvalho Chehab75702272016-10-14 08:57:27 -0300734// dprintk("929: %x %d %d\n",
Patrick Boettcher69ea31e2006-10-17 18:28:14 -0300735// (dib7000m_read_word(state, 929) & 0xffe3) | (agc->wbd_inv << 4) | (agc->wbd_sel << 2), agc->wbd_inv, agc->wbd_sel);
736 dib7000m_write_word(state, 929, (dib7000m_read_word(state, 929) & 0xffe3) | (agc->wbd_inv << 4) | (agc->wbd_sel << 2));
737 } else {
738 // wrong default values
739 u16 b[9] = { 676, 696, 717, 737, 758, 778, 799, 819, 840 };
740 for (i = 0; i < 9; i++)
741 dib7000m_write_word(state, 88 + i, b[i]);
742 }
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300743 return 0;
Patrick Boettcher69ea31e2006-10-17 18:28:14 -0300744}
745
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300746static void dib7000m_update_timf(struct dib7000m_state *state)
Patrick Boettcher69ea31e2006-10-17 18:28:14 -0300747{
748 u32 timf = (dib7000m_read_word(state, 436) << 16) | dib7000m_read_word(state, 437);
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300749 state->timf = timf * 160 / (state->current_bandwidth / 50);
Patrick Boettcher69ea31e2006-10-17 18:28:14 -0300750 dib7000m_write_word(state, 23, (u16) (timf >> 16));
751 dib7000m_write_word(state, 24, (u16) (timf & 0xffff));
Mauro Carvalho Chehab75702272016-10-14 08:57:27 -0300752 dprintk("updated timf_frequency: %d (default: %d)\n", state->timf, state->timf_default);
Patrick Boettcher69ea31e2006-10-17 18:28:14 -0300753}
754
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -0300755static int dib7000m_agc_startup(struct dvb_frontend *demod)
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300756{
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -0300757 struct dtv_frontend_properties *ch = &demod->dtv_property_cache;
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300758 struct dib7000m_state *state = demod->demodulator_priv;
759 u16 cfg_72 = dib7000m_read_word(state, 72);
760 int ret = -1;
761 u8 *agc_state = &state->agc_state;
762 u8 agc_split;
763
764 switch (state->agc_state) {
765 case 0:
766 // set power-up level: interf+analog+AGC
767 dib7000m_set_power_mode(state, DIB7000M_POWER_INTERF_ANALOG_AGC);
768 dib7000m_set_adc_state(state, DIBX000_ADC_ON);
769
770 if (dib7000m_set_agc_config(state, BAND_OF_FREQUENCY(ch->frequency/1000)) != 0)
771 return -1;
772
773 ret = 7; /* ADC power up */
774 (*agc_state)++;
775 break;
776
777 case 1:
778 /* AGC initialization */
779 if (state->cfg.agc_control)
780 state->cfg.agc_control(&state->demod, 1);
781
782 dib7000m_write_word(state, 75, 32768);
783 if (!state->current_agc->perform_agc_softsplit) {
784 /* we are using the wbd - so slow AGC startup */
785 dib7000m_write_word(state, 103, 1 << 8); /* force 0 split on WBD and restart AGC */
786 (*agc_state)++;
787 ret = 5;
788 } else {
789 /* default AGC startup */
790 (*agc_state) = 4;
791 /* wait AGC rough lock time */
792 ret = 7;
793 }
794
795 dib7000m_restart_agc(state);
796 break;
797
798 case 2: /* fast split search path after 5sec */
799 dib7000m_write_word(state, 72, cfg_72 | (1 << 4)); /* freeze AGC loop */
800 dib7000m_write_word(state, 103, 2 << 9); /* fast split search 0.25kHz */
801 (*agc_state)++;
802 ret = 14;
803 break;
804
805 case 3: /* split search ended */
Patrick Boettcher01373a52007-07-30 12:49:04 -0300806 agc_split = (u8)dib7000m_read_word(state, 392); /* store the split value for the next time */
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300807 dib7000m_write_word(state, 75, dib7000m_read_word(state, 390)); /* set AGC gain start value */
808
809 dib7000m_write_word(state, 72, cfg_72 & ~(1 << 4)); /* std AGC loop */
810 dib7000m_write_word(state, 103, (state->current_agc->wbd_alpha << 9) | agc_split); /* standard split search */
811
812 dib7000m_restart_agc(state);
813
Mauro Carvalho Chehab75702272016-10-14 08:57:27 -0300814 dprintk("SPLIT %p: %hd\n", demod, agc_split);
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300815
816 (*agc_state)++;
817 ret = 5;
818 break;
819
820 case 4: /* LNA startup */
821 /* wait AGC accurate lock time */
822 ret = 7;
823
824 if (dib7000m_update_lna(state))
825 // wait only AGC rough lock time
826 ret = 5;
827 else
828 (*agc_state)++;
829 break;
830
831 case 5:
832 dib7000m_agc_soft_split(state);
833
834 if (state->cfg.agc_control)
835 state->cfg.agc_control(&state->demod, 0);
836
837 (*agc_state)++;
838 break;
839
840 default:
841 break;
842 }
843 return ret;
844}
845
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -0300846static void dib7000m_set_channel(struct dib7000m_state *state, struct dtv_frontend_properties *ch,
847 u8 seq)
Patrick Boettcher69ea31e2006-10-17 18:28:14 -0300848{
849 u16 value, est[4];
850
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -0300851 dib7000m_set_bandwidth(state, BANDWIDTH_TO_KHZ(ch->bandwidth_hz));
Patrick Boettcher69ea31e2006-10-17 18:28:14 -0300852
853 /* nfft, guard, qam, alpha */
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300854 value = 0;
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -0300855 switch (ch->transmission_mode) {
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300856 case TRANSMISSION_MODE_2K: value |= (0 << 7); break;
Mauro Carvalho Chehab2e94b532010-12-27 11:55:07 -0300857 case TRANSMISSION_MODE_4K: value |= (2 << 7); break;
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300858 default:
859 case TRANSMISSION_MODE_8K: value |= (1 << 7); break;
860 }
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -0300861 switch (ch->guard_interval) {
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300862 case GUARD_INTERVAL_1_32: value |= (0 << 5); break;
863 case GUARD_INTERVAL_1_16: value |= (1 << 5); break;
864 case GUARD_INTERVAL_1_4: value |= (3 << 5); break;
865 default:
866 case GUARD_INTERVAL_1_8: value |= (2 << 5); break;
867 }
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -0300868 switch (ch->modulation) {
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300869 case QPSK: value |= (0 << 3); break;
870 case QAM_16: value |= (1 << 3); break;
871 default:
872 case QAM_64: value |= (2 << 3); break;
873 }
874 switch (HIERARCHY_1) {
875 case HIERARCHY_2: value |= 2; break;
876 case HIERARCHY_4: value |= 4; break;
877 default:
878 case HIERARCHY_1: value |= 1; break;
879 }
880 dib7000m_write_word(state, 0, value);
Patrick Boettcher69ea31e2006-10-17 18:28:14 -0300881 dib7000m_write_word(state, 5, (seq << 4));
882
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300883 /* P_dintl_native, P_dintlv_inv, P_hrch, P_code_rate, P_select_hp */
884 value = 0;
885 if (1 != 0)
886 value |= (1 << 6);
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -0300887 if (ch->hierarchy == 1)
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300888 value |= (1 << 4);
889 if (1 == 1)
890 value |= 1;
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -0300891 switch ((ch->hierarchy == 0 || 1 == 1) ? ch->code_rate_HP : ch->code_rate_LP) {
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300892 case FEC_2_3: value |= (2 << 1); break;
893 case FEC_3_4: value |= (3 << 1); break;
894 case FEC_5_6: value |= (5 << 1); break;
895 case FEC_7_8: value |= (7 << 1); break;
896 default:
897 case FEC_1_2: value |= (1 << 1); break;
898 }
Patrick Boettcher69ea31e2006-10-17 18:28:14 -0300899 dib7000m_write_word(state, 267 + state->reg_offs, value);
900
901 /* offset loop parameters */
902
903 /* P_timf_alpha = 6, P_corm_alpha=6, P_corm_thres=0x80 */
904 dib7000m_write_word(state, 26, (6 << 12) | (6 << 8) | 0x80);
905
906 /* 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 */
907 dib7000m_write_word(state, 29, (0 << 14) | (4 << 10) | (1 << 9) | (3 << 5) | (1 << 4) | (0x3));
908
909 /* P_ctrl_freeze_pha_shift=0, P_ctrl_pha_off_max=3 */
910 dib7000m_write_word(state, 32, (0 << 4) | 0x3);
911
912 /* P_ctrl_sfreq_inh=0, P_ctrl_sfreq_step=5 */
913 dib7000m_write_word(state, 33, (0 << 4) | 0x5);
914
915 /* P_dvsy_sync_wait */
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -0300916 switch (ch->transmission_mode) {
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300917 case TRANSMISSION_MODE_8K: value = 256; break;
Mauro Carvalho Chehab2e94b532010-12-27 11:55:07 -0300918 case TRANSMISSION_MODE_4K: value = 128; break;
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300919 case TRANSMISSION_MODE_2K:
Patrick Boettcher69ea31e2006-10-17 18:28:14 -0300920 default: value = 64; break;
921 }
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -0300922 switch (ch->guard_interval) {
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300923 case GUARD_INTERVAL_1_16: value *= 2; break;
924 case GUARD_INTERVAL_1_8: value *= 4; break;
925 case GUARD_INTERVAL_1_4: value *= 8; break;
926 default:
927 case GUARD_INTERVAL_1_32: value *= 1; break;
928 }
929 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 -0300930
Mauro Carvalho Chehab868c9a12019-02-18 14:28:55 -0500931 /* deactivate the possibility of diversity reception if extended interleave - not for 7000MC */
Patrick Boettcher69ea31e2006-10-17 18:28:14 -0300932 /* P_dvsy_sync_mode = 0, P_dvsy_sync_enable=1, P_dvcb_comb_mode=2 */
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300933 if (1 == 1 || state->revision > 0x4000)
934 state->div_force_off = 0;
Patrick Boettcher69ea31e2006-10-17 18:28:14 -0300935 else
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300936 state->div_force_off = 1;
937 dib7000m_set_diversity_in(&state->demod, state->div_state);
Patrick Boettcher69ea31e2006-10-17 18:28:14 -0300938
939 /* channel estimation fine configuration */
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -0300940 switch (ch->modulation) {
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300941 case QAM_64:
Patrick Boettcher69ea31e2006-10-17 18:28:14 -0300942 est[0] = 0x0148; /* P_adp_regul_cnt 0.04 */
943 est[1] = 0xfff0; /* P_adp_noise_cnt -0.002 */
944 est[2] = 0x00a4; /* P_adp_regul_ext 0.02 */
945 est[3] = 0xfff8; /* P_adp_noise_ext -0.001 */
946 break;
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300947 case QAM_16:
Patrick Boettcher69ea31e2006-10-17 18:28:14 -0300948 est[0] = 0x023d; /* P_adp_regul_cnt 0.07 */
949 est[1] = 0xffdf; /* P_adp_noise_cnt -0.004 */
950 est[2] = 0x00a4; /* P_adp_regul_ext 0.02 */
951 est[3] = 0xfff0; /* P_adp_noise_ext -0.002 */
952 break;
953 default:
954 est[0] = 0x099a; /* P_adp_regul_cnt 0.3 */
955 est[1] = 0xffae; /* P_adp_noise_cnt -0.01 */
956 est[2] = 0x0333; /* P_adp_regul_ext 0.1 */
957 est[3] = 0xfff8; /* P_adp_noise_ext -0.002 */
958 break;
959 }
960 for (value = 0; value < 4; value++)
961 dib7000m_write_word(state, 214 + value + state->reg_offs, est[value]);
962
Patrick Boettcher69ea31e2006-10-17 18:28:14 -0300963 // set power-up level: autosearch
964 dib7000m_set_power_mode(state, DIB7000M_POWER_COR4_DINTLV_ICIRM_EQUAL_CFROD);
965}
966
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -0300967static int dib7000m_autosearch_start(struct dvb_frontend *demod)
Patrick Boettcher69ea31e2006-10-17 18:28:14 -0300968{
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -0300969 struct dtv_frontend_properties *ch = &demod->dtv_property_cache;
Patrick Boettcher69ea31e2006-10-17 18:28:14 -0300970 struct dib7000m_state *state = demod->demodulator_priv;
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -0300971 struct dtv_frontend_properties schan;
Patrick Boettcher69ea31e2006-10-17 18:28:14 -0300972 int ret = 0;
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300973 u32 value, factor;
Patrick Boettcher69ea31e2006-10-17 18:28:14 -0300974
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300975 schan = *ch;
Patrick Boettcher69ea31e2006-10-17 18:28:14 -0300976
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -0300977 schan.modulation = QAM_64;
978 schan.guard_interval = GUARD_INTERVAL_1_32;
979 schan.transmission_mode = TRANSMISSION_MODE_8K;
980 schan.code_rate_HP = FEC_2_3;
981 schan.code_rate_LP = FEC_3_4;
982 schan.hierarchy = 0;
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300983
984 dib7000m_set_channel(state, &schan, 7);
985
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -0300986 factor = BANDWIDTH_TO_KHZ(schan.bandwidth_hz);
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300987 if (factor >= 5000)
988 factor = 1;
989 else
990 factor = 6;
Patrick Boettcher69ea31e2006-10-17 18:28:14 -0300991
992 // always use the setting for 8MHz here lock_time for 7,6 MHz are longer
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300993 value = 30 * state->internal_clk * factor;
Patrick Boettcher69ea31e2006-10-17 18:28:14 -0300994 ret |= dib7000m_write_word(state, 6, (u16) ((value >> 16) & 0xffff)); // lock0 wait time
995 ret |= dib7000m_write_word(state, 7, (u16) (value & 0xffff)); // lock0 wait time
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300996 value = 100 * state->internal_clk * factor;
Patrick Boettcher69ea31e2006-10-17 18:28:14 -0300997 ret |= dib7000m_write_word(state, 8, (u16) ((value >> 16) & 0xffff)); // lock1 wait time
998 ret |= dib7000m_write_word(state, 9, (u16) (value & 0xffff)); // lock1 wait time
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300999 value = 500 * state->internal_clk * factor;
Patrick Boettcher69ea31e2006-10-17 18:28:14 -03001000 ret |= dib7000m_write_word(state, 10, (u16) ((value >> 16) & 0xffff)); // lock2 wait time
1001 ret |= dib7000m_write_word(state, 11, (u16) (value & 0xffff)); // lock2 wait time
1002
1003 // start search
1004 value = dib7000m_read_word(state, 0);
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001005 ret |= dib7000m_write_word(state, 0, (u16) (value | (1 << 9)));
Patrick Boettcher69ea31e2006-10-17 18:28:14 -03001006
1007 /* clear n_irq_pending */
1008 if (state->revision == 0x4000)
1009 dib7000m_write_word(state, 1793, 0);
1010 else
1011 dib7000m_read_word(state, 537);
1012
1013 ret |= dib7000m_write_word(state, 0, (u16) value);
1014
1015 return ret;
1016}
1017
1018static int dib7000m_autosearch_irq(struct dib7000m_state *state, u16 reg)
1019{
1020 u16 irq_pending = dib7000m_read_word(state, reg);
1021
1022 if (irq_pending & 0x1) { // failed
Mauro Carvalho Chehab75702272016-10-14 08:57:27 -03001023 dprintk("autosearch failed\n");
Patrick Boettcher69ea31e2006-10-17 18:28:14 -03001024 return 1;
1025 }
1026
1027 if (irq_pending & 0x2) { // succeeded
Mauro Carvalho Chehab75702272016-10-14 08:57:27 -03001028 dprintk("autosearch succeeded\n");
Patrick Boettcher69ea31e2006-10-17 18:28:14 -03001029 return 2;
1030 }
1031 return 0; // still pending
1032}
1033
1034static int dib7000m_autosearch_is_irq(struct dvb_frontend *demod)
1035{
1036 struct dib7000m_state *state = demod->demodulator_priv;
1037 if (state->revision == 0x4000)
1038 return dib7000m_autosearch_irq(state, 1793);
1039 else
1040 return dib7000m_autosearch_irq(state, 537);
1041}
1042
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -03001043static int dib7000m_tune(struct dvb_frontend *demod)
Patrick Boettcher69ea31e2006-10-17 18:28:14 -03001044{
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -03001045 struct dtv_frontend_properties *ch = &demod->dtv_property_cache;
Patrick Boettcher69ea31e2006-10-17 18:28:14 -03001046 struct dib7000m_state *state = demod->demodulator_priv;
1047 int ret = 0;
1048 u16 value;
1049
1050 // we are already tuned - just resuming from suspend
Himangi Saraogi157a5fe2014-07-15 18:31:17 -03001051 dib7000m_set_channel(state, ch, 0);
Patrick Boettcher69ea31e2006-10-17 18:28:14 -03001052
1053 // restart demod
1054 ret |= dib7000m_write_word(state, 898, 0x4000);
1055 ret |= dib7000m_write_word(state, 898, 0x0000);
1056 msleep(45);
1057
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001058 dib7000m_set_power_mode(state, DIB7000M_POWER_COR4_CRY_ESRAM_MOUT_NUD);
Patrick Boettcher69ea31e2006-10-17 18:28:14 -03001059 /* 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 */
1060 ret |= dib7000m_write_word(state, 29, (0 << 14) | (4 << 10) | (0 << 9) | (3 << 5) | (1 << 4) | (0x3));
1061
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001062 // never achieved a lock before - wait for timfreq to update
Patrick Boettcher69ea31e2006-10-17 18:28:14 -03001063 if (state->timf == 0)
1064 msleep(200);
1065
1066 //dump_reg(state);
1067 /* P_timf_alpha, P_corm_alpha=6, P_corm_thres=0x80 */
1068 value = (6 << 8) | 0x80;
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -03001069 switch (ch->transmission_mode) {
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001070 case TRANSMISSION_MODE_2K: value |= (7 << 12); break;
Mauro Carvalho Chehab2e94b532010-12-27 11:55:07 -03001071 case TRANSMISSION_MODE_4K: value |= (8 << 12); break;
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001072 default:
1073 case TRANSMISSION_MODE_8K: value |= (9 << 12); break;
Patrick Boettcher69ea31e2006-10-17 18:28:14 -03001074 }
1075 ret |= dib7000m_write_word(state, 26, value);
1076
1077 /* P_ctrl_freeze_pha_shift=0, P_ctrl_pha_off_max */
1078 value = (0 << 4);
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -03001079 switch (ch->transmission_mode) {
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001080 case TRANSMISSION_MODE_2K: value |= 0x6; break;
Mauro Carvalho Chehab2e94b532010-12-27 11:55:07 -03001081 case TRANSMISSION_MODE_4K: value |= 0x7; break;
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001082 default:
1083 case TRANSMISSION_MODE_8K: value |= 0x8; break;
Patrick Boettcher69ea31e2006-10-17 18:28:14 -03001084 }
1085 ret |= dib7000m_write_word(state, 32, value);
1086
1087 /* P_ctrl_sfreq_inh=0, P_ctrl_sfreq_step */
1088 value = (0 << 4);
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -03001089 switch (ch->transmission_mode) {
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001090 case TRANSMISSION_MODE_2K: value |= 0x6; break;
Mauro Carvalho Chehab2e94b532010-12-27 11:55:07 -03001091 case TRANSMISSION_MODE_4K: value |= 0x7; break;
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001092 default:
1093 case TRANSMISSION_MODE_8K: value |= 0x8; break;
Patrick Boettcher69ea31e2006-10-17 18:28:14 -03001094 }
1095 ret |= dib7000m_write_word(state, 33, value);
1096
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001097 // we achieved a lock - it's time to update the timf freq
Patrick Boettcher69ea31e2006-10-17 18:28:14 -03001098 if ((dib7000m_read_word(state, 535) >> 6) & 0x1)
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001099 dib7000m_update_timf(state);
Patrick Boettcher69ea31e2006-10-17 18:28:14 -03001100
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -03001101 dib7000m_set_bandwidth(state, BANDWIDTH_TO_KHZ(ch->bandwidth_hz));
Patrick Boettcher69ea31e2006-10-17 18:28:14 -03001102 return ret;
1103}
1104
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001105static int dib7000m_wakeup(struct dvb_frontend *demod)
Patrick Boettcher69ea31e2006-10-17 18:28:14 -03001106{
1107 struct dib7000m_state *state = demod->demodulator_priv;
Patrick Boettcher69ea31e2006-10-17 18:28:14 -03001108
1109 dib7000m_set_power_mode(state, DIB7000M_POWER_ALL);
1110
1111 if (dib7000m_set_adc_state(state, DIBX000_SLOW_ADC_ON) != 0)
Mauro Carvalho Chehab75702272016-10-14 08:57:27 -03001112 dprintk("could not start Slow ADC\n");
Patrick Boettcher69ea31e2006-10-17 18:28:14 -03001113
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001114 return 0;
Patrick Boettcher69ea31e2006-10-17 18:28:14 -03001115}
1116
1117static int dib7000m_sleep(struct dvb_frontend *demod)
1118{
1119 struct dib7000m_state *st = demod->demodulator_priv;
1120 dib7000m_set_output_mode(st, OUTMODE_HIGH_Z);
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001121 dib7000m_set_power_mode(st, DIB7000M_POWER_INTERFACE_ONLY);
1122 return dib7000m_set_adc_state(st, DIBX000_SLOW_ADC_OFF) |
Patrick Boettcher69ea31e2006-10-17 18:28:14 -03001123 dib7000m_set_adc_state(st, DIBX000_ADC_OFF);
1124}
1125
1126static int dib7000m_identify(struct dib7000m_state *state)
1127{
1128 u16 value;
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001129
Patrick Boettcher69ea31e2006-10-17 18:28:14 -03001130 if ((value = dib7000m_read_word(state, 896)) != 0x01b3) {
Mauro Carvalho Chehab75702272016-10-14 08:57:27 -03001131 dprintk("wrong Vendor ID (0x%x)\n", value);
Patrick Boettcher69ea31e2006-10-17 18:28:14 -03001132 return -EREMOTEIO;
1133 }
1134
1135 state->revision = dib7000m_read_word(state, 897);
1136 if (state->revision != 0x4000 &&
1137 state->revision != 0x4001 &&
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001138 state->revision != 0x4002 &&
1139 state->revision != 0x4003) {
Mauro Carvalho Chehab75702272016-10-14 08:57:27 -03001140 dprintk("wrong Device ID (0x%x)\n", value);
Patrick Boettcher69ea31e2006-10-17 18:28:14 -03001141 return -EREMOTEIO;
1142 }
1143
1144 /* protect this driver to be used with 7000PC */
1145 if (state->revision == 0x4000 && dib7000m_read_word(state, 769) == 0x4000) {
Mauro Carvalho Chehab75702272016-10-14 08:57:27 -03001146 dprintk("this driver does not work with DiB7000PC\n");
Patrick Boettcher69ea31e2006-10-17 18:28:14 -03001147 return -EREMOTEIO;
1148 }
1149
1150 switch (state->revision) {
Mauro Carvalho Chehab75702272016-10-14 08:57:27 -03001151 case 0x4000: dprintk("found DiB7000MA/PA/MB/PB\n"); break;
1152 case 0x4001: state->reg_offs = 1; dprintk("found DiB7000HC\n"); break;
1153 case 0x4002: state->reg_offs = 1; dprintk("found DiB7000MC\n"); break;
1154 case 0x4003: state->reg_offs = 1; dprintk("found DiB9000\n"); break;
Patrick Boettcher69ea31e2006-10-17 18:28:14 -03001155 }
1156
1157 return 0;
1158}
1159
Patrick Boettcher91bb9be2006-12-02 21:15:51 -02001160
Mauro Carvalho Chehab7e3e68b2016-02-04 12:58:30 -02001161static int dib7000m_get_frontend(struct dvb_frontend* fe,
1162 struct dtv_frontend_properties *fep)
Patrick Boettcher91bb9be2006-12-02 21:15:51 -02001163{
1164 struct dib7000m_state *state = fe->demodulator_priv;
1165 u16 tps = dib7000m_read_word(state,480);
1166
1167 fep->inversion = INVERSION_AUTO;
1168
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -03001169 fep->bandwidth_hz = BANDWIDTH_TO_HZ(state->current_bandwidth);
Patrick Boettcher91bb9be2006-12-02 21:15:51 -02001170
Patrick Boettcherd92532d2006-10-18 08:35:16 -03001171 switch ((tps >> 8) & 0x3) {
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -03001172 case 0: fep->transmission_mode = TRANSMISSION_MODE_2K; break;
1173 case 1: fep->transmission_mode = TRANSMISSION_MODE_8K; break;
1174 /* case 2: fep->transmission_mode = TRANSMISSION_MODE_4K; break; */
Patrick Boettcher91bb9be2006-12-02 21:15:51 -02001175 }
1176
1177 switch (tps & 0x3) {
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -03001178 case 0: fep->guard_interval = GUARD_INTERVAL_1_32; break;
1179 case 1: fep->guard_interval = GUARD_INTERVAL_1_16; break;
1180 case 2: fep->guard_interval = GUARD_INTERVAL_1_8; break;
1181 case 3: fep->guard_interval = GUARD_INTERVAL_1_4; break;
Patrick Boettcher91bb9be2006-12-02 21:15:51 -02001182 }
1183
1184 switch ((tps >> 14) & 0x3) {
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -03001185 case 0: fep->modulation = QPSK; break;
1186 case 1: fep->modulation = QAM_16; break;
Patrick Boettcher91bb9be2006-12-02 21:15:51 -02001187 case 2:
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -03001188 default: fep->modulation = QAM_64; break;
Patrick Boettcher91bb9be2006-12-02 21:15:51 -02001189 }
1190
1191 /* as long as the frontend_param structure is fixed for hierarchical transmission I refuse to use it */
1192 /* (tps >> 13) & 0x1 == hrch is used, (tps >> 10) & 0x7 == alpha */
1193
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -03001194 fep->hierarchy = HIERARCHY_NONE;
Patrick Boettcher91bb9be2006-12-02 21:15:51 -02001195 switch ((tps >> 5) & 0x7) {
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -03001196 case 1: fep->code_rate_HP = FEC_1_2; break;
1197 case 2: fep->code_rate_HP = FEC_2_3; break;
1198 case 3: fep->code_rate_HP = FEC_3_4; break;
1199 case 5: fep->code_rate_HP = FEC_5_6; break;
Patrick Boettcher91bb9be2006-12-02 21:15:51 -02001200 case 7:
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -03001201 default: fep->code_rate_HP = FEC_7_8; break;
Patrick Boettcher91bb9be2006-12-02 21:15:51 -02001202
1203 }
1204
1205 switch ((tps >> 2) & 0x7) {
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -03001206 case 1: fep->code_rate_LP = FEC_1_2; break;
1207 case 2: fep->code_rate_LP = FEC_2_3; break;
1208 case 3: fep->code_rate_LP = FEC_3_4; break;
1209 case 5: fep->code_rate_LP = FEC_5_6; break;
Patrick Boettcher91bb9be2006-12-02 21:15:51 -02001210 case 7:
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -03001211 default: fep->code_rate_LP = FEC_7_8; break;
Patrick Boettcher91bb9be2006-12-02 21:15:51 -02001212 }
1213
1214 /* native interleaver: (dib7000m_read_word(state, 481) >> 5) & 0x1 */
1215
1216 return 0;
1217}
1218
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -03001219static int dib7000m_set_frontend(struct dvb_frontend *fe)
Patrick Boettcher91bb9be2006-12-02 21:15:51 -02001220{
Mauro Carvalho Chehab7c61d802011-12-30 11:30:21 -03001221 struct dtv_frontend_properties *fep = &fe->dtv_property_cache;
Patrick Boettcher69ea31e2006-10-17 18:28:14 -03001222 struct dib7000m_state *state = fe->demodulator_priv;
Soeren Moch853ea132008-01-25 06:27:06 -03001223 int time, ret;
1224
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -03001225 dib7000m_set_output_mode(state, OUTMODE_HIGH_Z);
Patrick Boettcher69ea31e2006-10-17 18:28:14 -03001226
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -03001227 dib7000m_set_bandwidth(state, BANDWIDTH_TO_KHZ(fep->bandwidth_hz));
Patrick Boettcher69ea31e2006-10-17 18:28:14 -03001228
1229 if (fe->ops.tuner_ops.set_params)
Mauro Carvalho Chehab14d24d12011-12-24 12:24:33 -03001230 fe->ops.tuner_ops.set_params(fe);
Patrick Boettcher69ea31e2006-10-17 18:28:14 -03001231
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001232 /* start up the AGC */
1233 state->agc_state = 0;
1234 do {
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -03001235 time = dib7000m_agc_startup(fe);
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001236 if (time != -1)
1237 msleep(time);
1238 } while (time != -1);
1239
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -03001240 if (fep->transmission_mode == TRANSMISSION_MODE_AUTO ||
1241 fep->guard_interval == GUARD_INTERVAL_AUTO ||
1242 fep->modulation == QAM_AUTO ||
1243 fep->code_rate_HP == FEC_AUTO) {
Patrick Boettcher69ea31e2006-10-17 18:28:14 -03001244 int i = 800, found;
1245
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -03001246 dib7000m_autosearch_start(fe);
Patrick Boettcher69ea31e2006-10-17 18:28:14 -03001247 do {
1248 msleep(1);
1249 found = dib7000m_autosearch_is_irq(fe);
1250 } while (found == 0 && i--);
1251
Mauro Carvalho Chehab75702272016-10-14 08:57:27 -03001252 dprintk("autosearch returns: %d\n", found);
Patrick Boettcher69ea31e2006-10-17 18:28:14 -03001253 if (found == 0 || found == 1)
1254 return 0; // no channel found
1255
Mauro Carvalho Chehab7e3e68b2016-02-04 12:58:30 -02001256 dib7000m_get_frontend(fe, fep);
Patrick Boettcher69ea31e2006-10-17 18:28:14 -03001257 }
1258
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -03001259 ret = dib7000m_tune(fe);
Soeren Moch853ea132008-01-25 06:27:06 -03001260
Patrick Boettcher69ea31e2006-10-17 18:28:14 -03001261 /* make this a config parameter */
1262 dib7000m_set_output_mode(state, OUTMODE_MPEG2_FIFO);
Soeren Moch853ea132008-01-25 06:27:06 -03001263 return ret;
Patrick Boettcher91bb9be2006-12-02 21:15:51 -02001264}
1265
Mauro Carvalho Chehab0df289a2015-06-07 14:53:52 -03001266static int dib7000m_read_status(struct dvb_frontend *fe, enum fe_status *stat)
Patrick Boettcher91bb9be2006-12-02 21:15:51 -02001267{
1268 struct dib7000m_state *state = fe->demodulator_priv;
Patrick Boettcher69ea31e2006-10-17 18:28:14 -03001269 u16 lock = dib7000m_read_word(state, 535);
Patrick Boettcher91bb9be2006-12-02 21:15:51 -02001270
1271 *stat = 0;
1272
1273 if (lock & 0x8000)
1274 *stat |= FE_HAS_SIGNAL;
1275 if (lock & 0x3000)
1276 *stat |= FE_HAS_CARRIER;
1277 if (lock & 0x0100)
1278 *stat |= FE_HAS_VITERBI;
1279 if (lock & 0x0010)
1280 *stat |= FE_HAS_SYNC;
1281 if (lock & 0x0008)
1282 *stat |= FE_HAS_LOCK;
1283
1284 return 0;
1285}
1286
1287static int dib7000m_read_ber(struct dvb_frontend *fe, u32 *ber)
1288{
1289 struct dib7000m_state *state = fe->demodulator_priv;
1290 *ber = (dib7000m_read_word(state, 526) << 16) | dib7000m_read_word(state, 527);
1291 return 0;
1292}
1293
1294static int dib7000m_read_unc_blocks(struct dvb_frontend *fe, u32 *unc)
1295{
1296 struct dib7000m_state *state = fe->demodulator_priv;
1297 *unc = dib7000m_read_word(state, 534);
1298 return 0;
1299}
1300
1301static int dib7000m_read_signal_strength(struct dvb_frontend *fe, u16 *strength)
1302{
1303 struct dib7000m_state *state = fe->demodulator_priv;
1304 u16 val = dib7000m_read_word(state, 390);
1305 *strength = 65535 - val;
1306 return 0;
1307}
1308
1309static int dib7000m_read_snr(struct dvb_frontend* fe, u16 *snr)
1310{
1311 *snr = 0x0000;
1312 return 0;
1313}
1314
1315static int dib7000m_fe_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings *tune)
1316{
1317 tune->min_delay_ms = 1000;
1318 return 0;
1319}
1320
Patrick Boettcher69ea31e2006-10-17 18:28:14 -03001321static void dib7000m_release(struct dvb_frontend *demod)
Patrick Boettcher91bb9be2006-12-02 21:15:51 -02001322{
Patrick Boettcher69ea31e2006-10-17 18:28:14 -03001323 struct dib7000m_state *st = demod->demodulator_priv;
1324 dibx000_exit_i2c_master(&st->i2c_master);
1325 kfree(st);
Patrick Boettcher91bb9be2006-12-02 21:15:51 -02001326}
1327
Patrick Boettcher69ea31e2006-10-17 18:28:14 -03001328struct i2c_adapter * dib7000m_get_i2c_master(struct dvb_frontend *demod, enum dibx000_i2c_interface intf, int gating)
Patrick Boettcher91bb9be2006-12-02 21:15:51 -02001329{
Patrick Boettcher69ea31e2006-10-17 18:28:14 -03001330 struct dib7000m_state *st = demod->demodulator_priv;
1331 return dibx000_get_i2c_adapter(&st->i2c_master, intf, gating);
1332}
1333EXPORT_SYMBOL(dib7000m_get_i2c_master);
1334
Olivier Greniee192a7c2011-01-14 13:58:59 -03001335int dib7000m_pid_filter_ctrl(struct dvb_frontend *fe, u8 onoff)
1336{
1337 struct dib7000m_state *state = fe->demodulator_priv;
1338 u16 val = dib7000m_read_word(state, 294 + state->reg_offs) & 0xffef;
1339 val |= (onoff & 0x1) << 4;
Mauro Carvalho Chehab75702272016-10-14 08:57:27 -03001340 dprintk("PID filter enabled %d\n", onoff);
Olivier Greniee192a7c2011-01-14 13:58:59 -03001341 return dib7000m_write_word(state, 294 + state->reg_offs, val);
1342}
1343EXPORT_SYMBOL(dib7000m_pid_filter_ctrl);
1344
1345int dib7000m_pid_filter(struct dvb_frontend *fe, u8 id, u16 pid, u8 onoff)
1346{
1347 struct dib7000m_state *state = fe->demodulator_priv;
Mauro Carvalho Chehab75702272016-10-14 08:57:27 -03001348 dprintk("PID filter: index %x, PID %d, OnOff %d\n", id, pid, onoff);
Olivier Greniee192a7c2011-01-14 13:58:59 -03001349 return dib7000m_write_word(state, 300 + state->reg_offs + id,
1350 onoff ? (1 << 13) | pid : 0);
1351}
1352EXPORT_SYMBOL(dib7000m_pid_filter);
1353
Hans Verkuil942648a2008-09-07 08:38:50 -03001354#if 0
1355/* used with some prototype boards */
1356int dib7000m_i2c_enumeration(struct i2c_adapter *i2c, int no_of_demods,
Hans Verkuild45b9b82008-09-04 03:33:43 -03001357 u8 default_addr, struct dib7000m_config cfg[])
Patrick Boettcher69ea31e2006-10-17 18:28:14 -03001358{
1359 struct dib7000m_state st = { .i2c_adap = i2c };
1360 int k = 0;
1361 u8 new_addr = 0;
1362
1363 for (k = no_of_demods-1; k >= 0; k--) {
1364 st.cfg = cfg[k];
1365
1366 /* designated i2c address */
1367 new_addr = (0x40 + k) << 1;
1368 st.i2c_addr = new_addr;
1369 if (dib7000m_identify(&st) != 0) {
1370 st.i2c_addr = default_addr;
1371 if (dib7000m_identify(&st) != 0) {
Mauro Carvalho Chehab75702272016-10-14 08:57:27 -03001372 dprintk("DiB7000M #%d: not identified\n", k);
Patrick Boettcher69ea31e2006-10-17 18:28:14 -03001373 return -EIO;
1374 }
1375 }
1376
1377 /* start diversity to pull_down div_str - just for i2c-enumeration */
1378 dib7000m_set_output_mode(&st, OUTMODE_DIVERSITY);
1379
1380 dib7000m_write_word(&st, 1796, 0x0); // select DVB-T output
1381
1382 /* set new i2c address and force divstart */
1383 dib7000m_write_word(&st, 1794, (new_addr << 2) | 0x2);
1384
Mauro Carvalho Chehab75702272016-10-14 08:57:27 -03001385 dprintk("IC %d initialized (to i2c_address 0x%x)\n", k, new_addr);
Patrick Boettcher69ea31e2006-10-17 18:28:14 -03001386 }
1387
1388 for (k = 0; k < no_of_demods; k++) {
1389 st.cfg = cfg[k];
1390 st.i2c_addr = (0x40 + k) << 1;
1391
1392 // unforce divstr
1393 dib7000m_write_word(&st,1794, st.i2c_addr << 2);
1394
1395 /* deactivate div - it was just for i2c-enumeration */
1396 dib7000m_set_output_mode(&st, OUTMODE_HIGH_Z);
1397 }
1398
Patrick Boettcher91bb9be2006-12-02 21:15:51 -02001399 return 0;
1400}
Patrick Boettcher69ea31e2006-10-17 18:28:14 -03001401EXPORT_SYMBOL(dib7000m_i2c_enumeration);
Hans Verkuil942648a2008-09-07 08:38:50 -03001402#endif
Patrick Boettcher91bb9be2006-12-02 21:15:51 -02001403
Max Kellermannbd336e62016-08-09 18:32:21 -03001404static const struct dvb_frontend_ops dib7000m_ops;
Patrick Boettcher69ea31e2006-10-17 18:28:14 -03001405struct dvb_frontend * dib7000m_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr, struct dib7000m_config *cfg)
1406{
1407 struct dvb_frontend *demod;
1408 struct dib7000m_state *st;
1409 st = kzalloc(sizeof(struct dib7000m_state), GFP_KERNEL);
1410 if (st == NULL)
1411 return NULL;
1412
1413 memcpy(&st->cfg, cfg, sizeof(struct dib7000m_config));
1414 st->i2c_adap = i2c_adap;
1415 st->i2c_addr = i2c_addr;
1416
1417 demod = &st->demod;
1418 demod->demodulator_priv = st;
1419 memcpy(&st->demod.ops, &dib7000m_ops, sizeof(struct dvb_frontend_ops));
Patrick Boettcher79fcce32011-08-03 12:08:21 -03001420 mutex_init(&st->i2c_buffer_lock);
Patrick Boettcher69ea31e2006-10-17 18:28:14 -03001421
Patrick Boettcher3db78e52007-07-31 08:19:28 -03001422 st->timf_default = cfg->bw->timf;
1423
Patrick Boettcher69ea31e2006-10-17 18:28:14 -03001424 if (dib7000m_identify(st) != 0)
1425 goto error;
1426
1427 if (st->revision == 0x4000)
1428 dibx000_init_i2c_master(&st->i2c_master, DIB7000, st->i2c_adap, st->i2c_addr);
1429 else
1430 dibx000_init_i2c_master(&st->i2c_master, DIB7000MC, st->i2c_adap, st->i2c_addr);
1431
1432 dib7000m_demod_reset(st);
1433
1434 return demod;
1435
1436error:
1437 kfree(st);
1438 return NULL;
1439}
1440EXPORT_SYMBOL(dib7000m_attach);
Patrick Boettcher91bb9be2006-12-02 21:15:51 -02001441
Max Kellermannbd336e62016-08-09 18:32:21 -03001442static const struct dvb_frontend_ops dib7000m_ops = {
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -03001443 .delsys = { SYS_DVBT },
Patrick Boettcher91bb9be2006-12-02 21:15:51 -02001444 .info = {
1445 .name = "DiBcom 7000MA/MB/PA/PB/MC",
Mauro Carvalho Chehabf1b1eab2018-07-05 18:59:36 -04001446 .frequency_min_hz = 44250 * kHz,
1447 .frequency_max_hz = 867250 * kHz,
1448 .frequency_stepsize_hz = 62500,
Patrick Boettcher91bb9be2006-12-02 21:15:51 -02001449 .caps = FE_CAN_INVERSION_AUTO |
1450 FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
1451 FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
1452 FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO |
1453 FE_CAN_TRANSMISSION_MODE_AUTO |
1454 FE_CAN_GUARD_INTERVAL_AUTO |
1455 FE_CAN_RECOVER |
1456 FE_CAN_HIERARCHY_AUTO,
1457 },
1458
1459 .release = dib7000m_release,
1460
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001461 .init = dib7000m_wakeup,
Patrick Boettcher91bb9be2006-12-02 21:15:51 -02001462 .sleep = dib7000m_sleep,
1463
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -03001464 .set_frontend = dib7000m_set_frontend,
Patrick Boettcher91bb9be2006-12-02 21:15:51 -02001465 .get_tune_settings = dib7000m_fe_get_tune_settings,
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -03001466 .get_frontend = dib7000m_get_frontend,
Patrick Boettcher91bb9be2006-12-02 21:15:51 -02001467
1468 .read_status = dib7000m_read_status,
1469 .read_ber = dib7000m_read_ber,
1470 .read_signal_strength = dib7000m_read_signal_strength,
1471 .read_snr = dib7000m_read_snr,
1472 .read_ucblocks = dib7000m_read_unc_blocks,
1473};
1474
Patrick Boettcher99e44da2016-01-24 12:56:58 -02001475MODULE_AUTHOR("Patrick Boettcher <patrick.boettcher@posteo.de>");
Patrick Boettcher91bb9be2006-12-02 21:15:51 -02001476MODULE_DESCRIPTION("Driver for the DiBcom 7000MA/MB/PA/PB/MC COFDM demodulator");
1477MODULE_LICENSE("GPL");