blob: d869029ca87d140f68998c40668406309182b56f [file] [log] [blame]
Patrick Boettchera75763f2006-10-18 08:34:16 -03001/*
2 * Linux-DVB Driver for DiBcom's second generation DiB7000P (PC).
3 *
Patrick Boettcherb6884a12007-07-27 10:08:51 -03004 * Copyright (C) 2005-7 DiBcom (http://www.dibcom.fr/)
Patrick Boettchera75763f2006-10-18 08:34:16 -03005 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License as
8 * published by the Free Software Foundation, version 2.
9 */
Mauro Carvalho Chehab5a0e2a42016-10-14 09:35:33 -030010
11#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
12
Patrick Boettchera75763f2006-10-18 08:34:16 -030013#include <linux/kernel.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090014#include <linux/slab.h>
Patrick Boettchera75763f2006-10-18 08:34:16 -030015#include <linux/i2c.h>
Patrick Boettcher79fcce32011-08-03 12:08:21 -030016#include <linux/mutex.h>
Mauro Carvalho Chehab041ad442014-05-29 14:44:56 -030017#include <asm/div64.h>
Patrick Boettchera75763f2006-10-18 08:34:16 -030018
Mauro Carvalho Chehabfada1932017-12-28 13:03:51 -050019#include <media/dvb_math.h>
20#include <media/dvb_frontend.h>
Patrick Boettchera75763f2006-10-18 08:34:16 -030021
22#include "dib7000p.h"
23
24static int debug;
25module_param(debug, int, 0644);
26MODULE_PARM_DESC(debug, "turn on debugging (default: 0)");
27
Matt Doran8f6956c2007-07-31 07:09:30 -030028static int buggy_sfn_workaround;
29module_param(buggy_sfn_workaround, int, 0644);
Patrick Boettcher8d999962007-07-31 10:36:06 -030030MODULE_PARM_DESC(buggy_sfn_workaround, "Enable work-around for buggy SFNs (default: 0)");
Matt Doran8f6956c2007-07-31 07:09:30 -030031
Mauro Carvalho Chehab5a0e2a42016-10-14 09:35:33 -030032#define dprintk(fmt, arg...) do { \
33 if (debug) \
34 printk(KERN_DEBUG pr_fmt("%s: " fmt), \
35 __func__, ##arg); \
36} while (0)
Patrick Boettchera75763f2006-10-18 08:34:16 -030037
Olivier Grenie713d54a2011-01-04 04:54:31 -030038struct i2c_device {
39 struct i2c_adapter *i2c_adap;
40 u8 i2c_addr;
41};
42
Patrick Boettchera75763f2006-10-18 08:34:16 -030043struct dib7000p_state {
44 struct dvb_frontend demod;
Olivier Grenie713d54a2011-01-04 04:54:31 -030045 struct dib7000p_config cfg;
Patrick Boettchera75763f2006-10-18 08:34:16 -030046
47 u8 i2c_addr;
Olivier Grenie713d54a2011-01-04 04:54:31 -030048 struct i2c_adapter *i2c_adap;
Patrick Boettchera75763f2006-10-18 08:34:16 -030049
50 struct dibx000_i2c_master i2c_master;
51
52 u16 wbd_ref;
53
Olivier Grenie713d54a2011-01-04 04:54:31 -030054 u8 current_band;
Patrick Boettcher904a82e2008-01-25 07:31:58 -030055 u32 current_bandwidth;
Patrick Boettchera75763f2006-10-18 08:34:16 -030056 struct dibx000_agc_config *current_agc;
57 u32 timf;
58
Olivier Grenie713d54a2011-01-04 04:54:31 -030059 u8 div_force_off:1;
60 u8 div_state:1;
Patrick Boettcher01373a52007-07-30 12:49:04 -030061 u16 div_sync_wait;
Patrick Boettcherb6884a12007-07-27 10:08:51 -030062
63 u8 agc_state;
64
Patrick Boettchera75763f2006-10-18 08:34:16 -030065 u16 gpio_dir;
66 u16 gpio_val;
Matt Doran8f6956c2007-07-31 07:09:30 -030067
Olivier Grenie713d54a2011-01-04 04:54:31 -030068 u8 sfn_workaround_active:1;
69
70#define SOC7090 0x7090
71 u16 version;
72
73 u16 tuner_enable;
74 struct i2c_adapter dib7090_tuner_adap;
Olivier Grenie5a0deee2011-05-03 12:27:33 -030075
76 /* for the I2C transfer */
77 struct i2c_msg msg[2];
78 u8 i2c_write_buffer[4];
79 u8 i2c_read_buffer[2];
Patrick Boettcher79fcce32011-08-03 12:08:21 -030080 struct mutex i2c_buffer_lock;
Olivier Grenie2e802862011-08-05 10:39:15 -030081
82 u8 input_mode_mpeg;
Mauro Carvalho Chehab041ad442014-05-29 14:44:56 -030083
84 /* for DVBv5 stats */
85 s64 old_ucb;
86 unsigned long per_jiffies_stats;
87 unsigned long ber_jiffies_stats;
88 unsigned long get_stats_time;
Patrick Boettchera75763f2006-10-18 08:34:16 -030089};
90
91enum dib7000p_power_mode {
92 DIB7000P_POWER_ALL = 0,
Patrick Boettcherb6884a12007-07-27 10:08:51 -030093 DIB7000P_POWER_ANALOG_ADC,
Patrick Boettchera75763f2006-10-18 08:34:16 -030094 DIB7000P_POWER_INTERFACE_ONLY,
95};
96
Mauro Carvalho Chehab868c9a12019-02-18 14:28:55 -050097/* dib7090 specific functions */
Olivier Grenie713d54a2011-01-04 04:54:31 -030098static int dib7090_set_output_mode(struct dvb_frontend *fe, int mode);
99static int dib7090_set_diversity_in(struct dvb_frontend *fe, int onoff);
Olivier Grenie2e802862011-08-05 10:39:15 -0300100static void dib7090_setDibTxMux(struct dib7000p_state *state, int mode);
101static void dib7090_setHostBusMux(struct dib7000p_state *state, int mode);
Olivier Grenie713d54a2011-01-04 04:54:31 -0300102
Patrick Boettchera75763f2006-10-18 08:34:16 -0300103static u16 dib7000p_read_word(struct dib7000p_state *state, u16 reg)
104{
Patrick Boettcher79fcce32011-08-03 12:08:21 -0300105 u16 ret;
106
107 if (mutex_lock_interruptible(&state->i2c_buffer_lock) < 0) {
Mauro Carvalho Chehab5a0e2a42016-10-14 09:35:33 -0300108 dprintk("could not acquire lock\n");
Patrick Boettcher79fcce32011-08-03 12:08:21 -0300109 return 0;
110 }
111
Olivier Grenie5a0deee2011-05-03 12:27:33 -0300112 state->i2c_write_buffer[0] = reg >> 8;
113 state->i2c_write_buffer[1] = reg & 0xff;
Patrick Boettchera75763f2006-10-18 08:34:16 -0300114
Olivier Grenie5a0deee2011-05-03 12:27:33 -0300115 memset(state->msg, 0, 2 * sizeof(struct i2c_msg));
116 state->msg[0].addr = state->i2c_addr >> 1;
117 state->msg[0].flags = 0;
118 state->msg[0].buf = state->i2c_write_buffer;
119 state->msg[0].len = 2;
120 state->msg[1].addr = state->i2c_addr >> 1;
121 state->msg[1].flags = I2C_M_RD;
122 state->msg[1].buf = state->i2c_read_buffer;
123 state->msg[1].len = 2;
124
125 if (i2c_transfer(state->i2c_adap, state->msg, 2) != 2)
Mauro Carvalho Chehab5a0e2a42016-10-14 09:35:33 -0300126 dprintk("i2c read error on %d\n", reg);
Patrick Boettchera75763f2006-10-18 08:34:16 -0300127
Patrick Boettcher79fcce32011-08-03 12:08:21 -0300128 ret = (state->i2c_read_buffer[0] << 8) | state->i2c_read_buffer[1];
129 mutex_unlock(&state->i2c_buffer_lock);
130 return ret;
Patrick Boettchera75763f2006-10-18 08:34:16 -0300131}
132
133static int dib7000p_write_word(struct dib7000p_state *state, u16 reg, u16 val)
134{
Patrick Boettcher79fcce32011-08-03 12:08:21 -0300135 int ret;
136
137 if (mutex_lock_interruptible(&state->i2c_buffer_lock) < 0) {
Mauro Carvalho Chehab5a0e2a42016-10-14 09:35:33 -0300138 dprintk("could not acquire lock\n");
Patrick Boettcher79fcce32011-08-03 12:08:21 -0300139 return -EINVAL;
140 }
141
Olivier Grenie5a0deee2011-05-03 12:27:33 -0300142 state->i2c_write_buffer[0] = (reg >> 8) & 0xff;
143 state->i2c_write_buffer[1] = reg & 0xff;
144 state->i2c_write_buffer[2] = (val >> 8) & 0xff;
145 state->i2c_write_buffer[3] = val & 0xff;
146
147 memset(&state->msg[0], 0, sizeof(struct i2c_msg));
148 state->msg[0].addr = state->i2c_addr >> 1;
149 state->msg[0].flags = 0;
150 state->msg[0].buf = state->i2c_write_buffer;
151 state->msg[0].len = 4;
152
Patrick Boettcher79fcce32011-08-03 12:08:21 -0300153 ret = (i2c_transfer(state->i2c_adap, state->msg, 1) != 1 ?
154 -EREMOTEIO : 0);
155 mutex_unlock(&state->i2c_buffer_lock);
156 return ret;
Patrick Boettchera75763f2006-10-18 08:34:16 -0300157}
Olivier Grenie713d54a2011-01-04 04:54:31 -0300158
159static void dib7000p_write_tab(struct dib7000p_state *state, u16 * buf)
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300160{
161 u16 l = 0, r, *n;
162 n = buf;
163 l = *n++;
164 while (l) {
165 r = *n++;
166
167 do {
168 dib7000p_write_word(state, r, *n++);
169 r++;
170 } while (--l);
171 l = *n++;
172 }
173}
174
Patrick Boettchera75763f2006-10-18 08:34:16 -0300175static int dib7000p_set_output_mode(struct dib7000p_state *state, int mode)
176{
Olivier Grenie713d54a2011-01-04 04:54:31 -0300177 int ret = 0;
Patrick Boettchera75763f2006-10-18 08:34:16 -0300178 u16 outreg, fifo_threshold, smo_mode;
179
180 outreg = 0;
181 fifo_threshold = 1792;
Olivier Grenieeac1fe12009-09-23 13:41:27 -0300182 smo_mode = (dib7000p_read_word(state, 235) & 0x0050) | (1 << 1);
Patrick Boettchera75763f2006-10-18 08:34:16 -0300183
Mauro Carvalho Chehab5a0e2a42016-10-14 09:35:33 -0300184 dprintk("setting output mode for demod %p to %d\n", &state->demod, mode);
Patrick Boettchera75763f2006-10-18 08:34:16 -0300185
186 switch (mode) {
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300187 case OUTMODE_MPEG2_PAR_GATED_CLK:
Olivier Grenie713d54a2011-01-04 04:54:31 -0300188 outreg = (1 << 10); /* 0x0400 */
189 break;
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300190 case OUTMODE_MPEG2_PAR_CONT_CLK:
Olivier Grenie713d54a2011-01-04 04:54:31 -0300191 outreg = (1 << 10) | (1 << 6); /* 0x0440 */
192 break;
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300193 case OUTMODE_MPEG2_SERIAL:
Olivier Grenie713d54a2011-01-04 04:54:31 -0300194 outreg = (1 << 10) | (2 << 6) | (0 << 1); /* 0x0480 */
195 break;
196 case OUTMODE_DIVERSITY:
197 if (state->cfg.hostbus_diversity)
198 outreg = (1 << 10) | (4 << 6); /* 0x0500 */
199 else
200 outreg = (1 << 11);
201 break;
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300202 case OUTMODE_MPEG2_FIFO:
Olivier Grenie713d54a2011-01-04 04:54:31 -0300203 smo_mode |= (3 << 1);
204 fifo_threshold = 512;
205 outreg = (1 << 10) | (5 << 6);
206 break;
207 case OUTMODE_ANALOG_ADC:
208 outreg = (1 << 10) | (3 << 6);
209 break;
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300210 case OUTMODE_HIGH_Z:
Olivier Grenie713d54a2011-01-04 04:54:31 -0300211 outreg = 0;
212 break;
213 default:
Mauro Carvalho Chehab5a0e2a42016-10-14 09:35:33 -0300214 dprintk("Unhandled output_mode passed to be set for demod %p\n", &state->demod);
Olivier Grenie713d54a2011-01-04 04:54:31 -0300215 break;
Patrick Boettchera75763f2006-10-18 08:34:16 -0300216 }
217
218 if (state->cfg.output_mpeg2_in_188_bytes)
Olivier Grenie713d54a2011-01-04 04:54:31 -0300219 smo_mode |= (1 << 5);
Patrick Boettchera75763f2006-10-18 08:34:16 -0300220
Olivier Grenie713d54a2011-01-04 04:54:31 -0300221 ret |= dib7000p_write_word(state, 235, smo_mode);
222 ret |= dib7000p_write_word(state, 236, fifo_threshold); /* synchronous fread */
223 if (state->version != SOC7090)
224 ret |= dib7000p_write_word(state, 1286, outreg); /* P_Div_active */
Patrick Boettchera75763f2006-10-18 08:34:16 -0300225
226 return ret;
227}
228
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300229static int dib7000p_set_diversity_in(struct dvb_frontend *demod, int onoff)
230{
231 struct dib7000p_state *state = demod->demodulator_priv;
232
233 if (state->div_force_off) {
Mauro Carvalho Chehab5a0e2a42016-10-14 09:35:33 -0300234 dprintk("diversity combination deactivated - forced by COFDM parameters\n");
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300235 onoff = 0;
Olivier Grenieeac1fe12009-09-23 13:41:27 -0300236 dib7000p_write_word(state, 207, 0);
237 } else
238 dib7000p_write_word(state, 207, (state->div_sync_wait << 4) | (1 << 2) | (2 << 0));
239
Olivier Grenie713d54a2011-01-04 04:54:31 -0300240 state->div_state = (u8) onoff;
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300241
242 if (onoff) {
243 dib7000p_write_word(state, 204, 6);
244 dib7000p_write_word(state, 205, 16);
245 /* P_dvsy_sync_mode = 0, P_dvsy_sync_enable=1, P_dvcb_comb_mode=2 */
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300246 } else {
247 dib7000p_write_word(state, 204, 1);
248 dib7000p_write_word(state, 205, 0);
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300249 }
250
251 return 0;
252}
253
Patrick Boettchera75763f2006-10-18 08:34:16 -0300254static int dib7000p_set_power_mode(struct dib7000p_state *state, enum dib7000p_power_mode mode)
255{
256 /* by default everything is powered off */
Olivier Grenie713d54a2011-01-04 04:54:31 -0300257 u16 reg_774 = 0x3fff, reg_775 = 0xffff, reg_776 = 0x0007, reg_899 = 0x0003, reg_1280 = (0xfe00) | (dib7000p_read_word(state, 1280) & 0x01ff);
Patrick Boettchera75763f2006-10-18 08:34:16 -0300258
259 /* now, depending on the requested mode, we power on */
260 switch (mode) {
261 /* power up everything in the demod */
Olivier Grenie713d54a2011-01-04 04:54:31 -0300262 case DIB7000P_POWER_ALL:
263 reg_774 = 0x0000;
264 reg_775 = 0x0000;
265 reg_776 = 0x0;
266 reg_899 = 0x0;
267 if (state->version == SOC7090)
268 reg_1280 &= 0x001f;
269 else
270 reg_1280 &= 0x01ff;
271 break;
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300272
Olivier Grenie713d54a2011-01-04 04:54:31 -0300273 case DIB7000P_POWER_ANALOG_ADC:
274 /* dem, cfg, iqc, sad, agc */
275 reg_774 &= ~((1 << 15) | (1 << 14) | (1 << 11) | (1 << 10) | (1 << 9));
276 /* nud */
277 reg_776 &= ~((1 << 0));
278 /* Dout */
279 if (state->version != SOC7090)
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300280 reg_1280 &= ~((1 << 11));
Olivier Grenie713d54a2011-01-04 04:54:31 -0300281 reg_1280 &= ~(1 << 6);
Mauro Carvalho Chehab06eeefe2017-05-18 08:13:28 -0300282 /* fall-through */
283 case DIB7000P_POWER_INTERFACE_ONLY:
Patrick Boettchera75763f2006-10-18 08:34:16 -0300284 /* just leave power on the control-interfaces: GPIO and (I2C or SDIO) */
Mauro Carvalho Chehab06eeefe2017-05-18 08:13:28 -0300285 /* TODO power up either SDIO or I2C */
Olivier Grenie713d54a2011-01-04 04:54:31 -0300286 if (state->version == SOC7090)
287 reg_1280 &= ~((1 << 7) | (1 << 5));
288 else
Patrick Boettchera75763f2006-10-18 08:34:16 -0300289 reg_1280 &= ~((1 << 14) | (1 << 13) | (1 << 12) | (1 << 10));
Olivier Grenie713d54a2011-01-04 04:54:31 -0300290 break;
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300291
Patrick Boettchera75763f2006-10-18 08:34:16 -0300292/* TODO following stuff is just converted from the dib7000-driver - check when is used what */
293 }
294
Olivier Grenie713d54a2011-01-04 04:54:31 -0300295 dib7000p_write_word(state, 774, reg_774);
296 dib7000p_write_word(state, 775, reg_775);
297 dib7000p_write_word(state, 776, reg_776);
Patrick Boettchera75763f2006-10-18 08:34:16 -0300298 dib7000p_write_word(state, 1280, reg_1280);
Olivier Grenie2e802862011-08-05 10:39:15 -0300299 if (state->version != SOC7090)
300 dib7000p_write_word(state, 899, reg_899);
Patrick Boettchera75763f2006-10-18 08:34:16 -0300301
302 return 0;
303}
304
305static void dib7000p_set_adc_state(struct dib7000p_state *state, enum dibx000_adc_states no)
306{
Olivier Grenie2e802862011-08-05 10:39:15 -0300307 u16 reg_908 = 0, reg_909 = 0;
Olivier Grenie713d54a2011-01-04 04:54:31 -0300308 u16 reg;
Patrick Boettchera75763f2006-10-18 08:34:16 -0300309
Olivier Grenie2e802862011-08-05 10:39:15 -0300310 if (state->version != SOC7090) {
311 reg_908 = dib7000p_read_word(state, 908);
312 reg_909 = dib7000p_read_word(state, 909);
313 }
314
Patrick Boettchera75763f2006-10-18 08:34:16 -0300315 switch (no) {
Olivier Grenie713d54a2011-01-04 04:54:31 -0300316 case DIBX000_SLOW_ADC_ON:
317 if (state->version == SOC7090) {
318 reg = dib7000p_read_word(state, 1925);
319
320 dib7000p_write_word(state, 1925, reg | (1 << 4) | (1 << 2)); /* en_slowAdc = 1 & reset_sladc = 1 */
321
Mauro Carvalho Chehab868c9a12019-02-18 14:28:55 -0500322 reg = dib7000p_read_word(state, 1925); /* read access to make it works... strange ... */
Olivier Grenie713d54a2011-01-04 04:54:31 -0300323 msleep(200);
324 dib7000p_write_word(state, 1925, reg & ~(1 << 4)); /* en_slowAdc = 1 & reset_sladc = 0 */
325
326 reg = dib7000p_read_word(state, 72) & ~((0x3 << 14) | (0x3 << 12));
327 dib7000p_write_word(state, 72, reg | (1 << 14) | (3 << 12) | 524); /* ref = Vin1 => Vbg ; sel = Vin0 or Vin3 ; (Vin2 = Vcm) */
328 } else {
Patrick Boettchera75763f2006-10-18 08:34:16 -0300329 reg_909 |= (1 << 1) | (1 << 0);
330 dib7000p_write_word(state, 909, reg_909);
331 reg_909 &= ~(1 << 1);
Olivier Grenie713d54a2011-01-04 04:54:31 -0300332 }
333 break;
Patrick Boettchera75763f2006-10-18 08:34:16 -0300334
Olivier Grenie713d54a2011-01-04 04:54:31 -0300335 case DIBX000_SLOW_ADC_OFF:
336 if (state->version == SOC7090) {
337 reg = dib7000p_read_word(state, 1925);
338 dib7000p_write_word(state, 1925, (reg & ~(1 << 2)) | (1 << 4)); /* reset_sladc = 1 en_slowAdc = 0 */
339 } else
340 reg_909 |= (1 << 1) | (1 << 0);
341 break;
Patrick Boettchera75763f2006-10-18 08:34:16 -0300342
Olivier Grenie713d54a2011-01-04 04:54:31 -0300343 case DIBX000_ADC_ON:
344 reg_908 &= 0x0fff;
345 reg_909 &= 0x0003;
346 break;
Patrick Boettchera75763f2006-10-18 08:34:16 -0300347
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300348 case DIBX000_ADC_OFF:
Olivier Grenie713d54a2011-01-04 04:54:31 -0300349 reg_908 |= (1 << 14) | (1 << 13) | (1 << 12);
350 reg_909 |= (1 << 5) | (1 << 4) | (1 << 3) | (1 << 2);
351 break;
Patrick Boettchera75763f2006-10-18 08:34:16 -0300352
Olivier Grenie713d54a2011-01-04 04:54:31 -0300353 case DIBX000_VBG_ENABLE:
354 reg_908 &= ~(1 << 15);
355 break;
Patrick Boettchera75763f2006-10-18 08:34:16 -0300356
Olivier Grenie713d54a2011-01-04 04:54:31 -0300357 case DIBX000_VBG_DISABLE:
358 reg_908 |= (1 << 15);
359 break;
Patrick Boettchera75763f2006-10-18 08:34:16 -0300360
Olivier Grenie713d54a2011-01-04 04:54:31 -0300361 default:
362 break;
Patrick Boettchera75763f2006-10-18 08:34:16 -0300363 }
364
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300365// dprintk( "908: %x, 909: %x\n", reg_908, reg_909);
Patrick Boettchera75763f2006-10-18 08:34:16 -0300366
Olivier Grenie970d14c2010-09-07 12:50:46 -0300367 reg_909 |= (state->cfg.disable_sample_and_hold & 1) << 4;
Olivier Grenie90e12ce2010-09-07 12:50:45 -0300368 reg_908 |= (state->cfg.enable_current_mirror & 1) << 7;
369
Olivier Grenie2e802862011-08-05 10:39:15 -0300370 if (state->version != SOC7090) {
371 dib7000p_write_word(state, 908, reg_908);
372 dib7000p_write_word(state, 909, reg_909);
373 }
Patrick Boettchera75763f2006-10-18 08:34:16 -0300374}
375
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300376static int dib7000p_set_bandwidth(struct dib7000p_state *state, u32 bw)
Patrick Boettchera75763f2006-10-18 08:34:16 -0300377{
Patrick Boettchera75763f2006-10-18 08:34:16 -0300378 u32 timf;
379
380 // store the current bandwidth for later use
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300381 state->current_bandwidth = bw;
Patrick Boettchera75763f2006-10-18 08:34:16 -0300382
383 if (state->timf == 0) {
Mauro Carvalho Chehab5a0e2a42016-10-14 09:35:33 -0300384 dprintk("using default timf\n");
Patrick Boettchera75763f2006-10-18 08:34:16 -0300385 timf = state->cfg.bw->timf;
386 } else {
Mauro Carvalho Chehab5a0e2a42016-10-14 09:35:33 -0300387 dprintk("using updated timf\n");
Patrick Boettchera75763f2006-10-18 08:34:16 -0300388 timf = state->timf;
389 }
390
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300391 timf = timf * (bw / 50) / 160;
Patrick Boettchera75763f2006-10-18 08:34:16 -0300392
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300393 dib7000p_write_word(state, 23, (u16) ((timf >> 16) & 0xffff));
Olivier Grenie713d54a2011-01-04 04:54:31 -0300394 dib7000p_write_word(state, 24, (u16) ((timf) & 0xffff));
Patrick Boettchera75763f2006-10-18 08:34:16 -0300395
396 return 0;
397}
398
399static int dib7000p_sad_calib(struct dib7000p_state *state)
400{
401/* internal */
Patrick Boettchera75763f2006-10-18 08:34:16 -0300402 dib7000p_write_word(state, 73, (0 << 1) | (0 << 0));
Olivier Grenie713d54a2011-01-04 04:54:31 -0300403
404 if (state->version == SOC7090)
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300405 dib7000p_write_word(state, 74, 2048);
Olivier Grenie713d54a2011-01-04 04:54:31 -0300406 else
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300407 dib7000p_write_word(state, 74, 776);
Patrick Boettchera75763f2006-10-18 08:34:16 -0300408
409 /* do the calibration */
410 dib7000p_write_word(state, 73, (1 << 0));
411 dib7000p_write_word(state, 73, (0 << 0));
412
413 msleep(1);
414
415 return 0;
416}
417
Mauro Carvalho Chehab8abe4a02014-05-29 09:20:15 -0300418static int dib7000p_set_wbd_ref(struct dvb_frontend *demod, u16 value)
Patrick Boettcher01373a52007-07-30 12:49:04 -0300419{
420 struct dib7000p_state *state = demod->demodulator_priv;
421 if (value > 4095)
422 value = 4095;
423 state->wbd_ref = value;
424 return dib7000p_write_word(state, 105, (dib7000p_read_word(state, 105) & 0xf000) | value);
425}
Olivier Grenie713d54a2011-01-04 04:54:31 -0300426
Mauro Carvalho Chehab8abe4a02014-05-29 09:20:15 -0300427static int dib7000p_get_agc_values(struct dvb_frontend *fe,
Olivier Grenie6724a2f2011-08-05 13:49:33 -0300428 u16 *agc_global, u16 *agc1, u16 *agc2, u16 *wbd)
429{
430 struct dib7000p_state *state = fe->demodulator_priv;
431
432 if (agc_global != NULL)
433 *agc_global = dib7000p_read_word(state, 394);
434 if (agc1 != NULL)
435 *agc1 = dib7000p_read_word(state, 392);
436 if (agc2 != NULL)
437 *agc2 = dib7000p_read_word(state, 393);
438 if (wbd != NULL)
439 *wbd = dib7000p_read_word(state, 397);
440
441 return 0;
442}
Olivier Grenie6724a2f2011-08-05 13:49:33 -0300443
Mauro Carvalho Chehab8abe4a02014-05-29 09:20:15 -0300444static int dib7000p_set_agc1_min(struct dvb_frontend *fe, u16 v)
Olivier Grenie6fe10992012-12-31 09:23:26 -0300445{
446 struct dib7000p_state *state = fe->demodulator_priv;
447 return dib7000p_write_word(state, 108, v);
448}
Olivier Grenie6fe10992012-12-31 09:23:26 -0300449
Patrick Boettchera75763f2006-10-18 08:34:16 -0300450static void dib7000p_reset_pll(struct dib7000p_state *state)
451{
452 struct dibx000_bandwidth_config *bw = &state->cfg.bw[0];
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300453 u16 clk_cfg0;
Patrick Boettchera75763f2006-10-18 08:34:16 -0300454
Olivier Grenie713d54a2011-01-04 04:54:31 -0300455 if (state->version == SOC7090) {
456 dib7000p_write_word(state, 1856, (!bw->pll_reset << 13) | (bw->pll_range << 12) | (bw->pll_ratio << 6) | (bw->pll_prediv));
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300457
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300458 while (((dib7000p_read_word(state, 1856) >> 15) & 0x1) != 1)
459 ;
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300460
Olivier Grenie713d54a2011-01-04 04:54:31 -0300461 dib7000p_write_word(state, 1857, dib7000p_read_word(state, 1857) | (!bw->pll_bypass << 15));
462 } else {
463 /* force PLL bypass */
464 clk_cfg0 = (1 << 15) | ((bw->pll_ratio & 0x3f) << 9) |
465 (bw->modulo << 7) | (bw->ADClkSrc << 6) | (bw->IO_CLK_en_core << 5) | (bw->bypclk_div << 2) | (bw->enable_refdiv << 1) | (0 << 0);
Patrick Boettchera75763f2006-10-18 08:34:16 -0300466
Olivier Grenie713d54a2011-01-04 04:54:31 -0300467 dib7000p_write_word(state, 900, clk_cfg0);
468
469 /* P_pll_cfg */
470 dib7000p_write_word(state, 903, (bw->pll_prediv << 5) | (((bw->pll_ratio >> 6) & 0x3) << 3) | (bw->pll_range << 1) | bw->pll_reset);
471 clk_cfg0 = (bw->pll_bypass << 15) | (clk_cfg0 & 0x7fff);
472 dib7000p_write_word(state, 900, clk_cfg0);
473 }
474
475 dib7000p_write_word(state, 18, (u16) (((bw->internal * 1000) >> 16) & 0xffff));
476 dib7000p_write_word(state, 19, (u16) ((bw->internal * 1000) & 0xffff));
477 dib7000p_write_word(state, 21, (u16) ((bw->ifreq >> 16) & 0xffff));
478 dib7000p_write_word(state, 22, (u16) ((bw->ifreq) & 0xffff));
Patrick Boettchera75763f2006-10-18 08:34:16 -0300479
480 dib7000p_write_word(state, 72, bw->sad_cfg);
481}
482
Olivier Grenie713d54a2011-01-04 04:54:31 -0300483static u32 dib7000p_get_internal_freq(struct dib7000p_state *state)
484{
485 u32 internal = (u32) dib7000p_read_word(state, 18) << 16;
486 internal |= (u32) dib7000p_read_word(state, 19);
487 internal /= 1000;
488
489 return internal;
490}
491
Mauro Carvalho Chehab8abe4a02014-05-29 09:20:15 -0300492static int dib7000p_update_pll(struct dvb_frontend *fe, struct dibx000_bandwidth_config *bw)
Olivier Grenie713d54a2011-01-04 04:54:31 -0300493{
494 struct dib7000p_state *state = fe->demodulator_priv;
495 u16 reg_1857, reg_1856 = dib7000p_read_word(state, 1856);
496 u8 loopdiv, prediv;
497 u32 internal, xtal;
498
499 /* get back old values */
500 prediv = reg_1856 & 0x3f;
501 loopdiv = (reg_1856 >> 6) & 0x3f;
502
503 if ((bw != NULL) && (bw->pll_prediv != prediv || bw->pll_ratio != loopdiv)) {
Mauro Carvalho Chehab5a0e2a42016-10-14 09:35:33 -0300504 dprintk("Updating pll (prediv: old = %d new = %d ; loopdiv : old = %d new = %d)\n", prediv, bw->pll_prediv, loopdiv, bw->pll_ratio);
Olivier Grenie713d54a2011-01-04 04:54:31 -0300505 reg_1856 &= 0xf000;
506 reg_1857 = dib7000p_read_word(state, 1857);
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300507 dib7000p_write_word(state, 1857, reg_1857 & ~(1 << 15));
Olivier Grenie713d54a2011-01-04 04:54:31 -0300508
509 dib7000p_write_word(state, 1856, reg_1856 | ((bw->pll_ratio & 0x3f) << 6) | (bw->pll_prediv & 0x3f));
510
511 /* write new system clk into P_sec_len */
512 internal = dib7000p_get_internal_freq(state);
513 xtal = (internal / loopdiv) * prediv;
514 internal = 1000 * (xtal / bw->pll_prediv) * bw->pll_ratio; /* new internal */
515 dib7000p_write_word(state, 18, (u16) ((internal >> 16) & 0xffff));
516 dib7000p_write_word(state, 19, (u16) (internal & 0xffff));
517
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300518 dib7000p_write_word(state, 1857, reg_1857 | (1 << 15));
Olivier Grenie713d54a2011-01-04 04:54:31 -0300519
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300520 while (((dib7000p_read_word(state, 1856) >> 15) & 0x1) != 1)
Mauro Carvalho Chehab5a0e2a42016-10-14 09:35:33 -0300521 dprintk("Waiting for PLL to lock\n");
Olivier Grenie713d54a2011-01-04 04:54:31 -0300522
523 return 0;
524 }
525 return -EIO;
526}
Olivier Grenie713d54a2011-01-04 04:54:31 -0300527
Patrick Boettchera75763f2006-10-18 08:34:16 -0300528static int dib7000p_reset_gpio(struct dib7000p_state *st)
529{
530 /* reset the GPIOs */
Mauro Carvalho Chehab5a0e2a42016-10-14 09:35:33 -0300531 dprintk("gpio dir: %x: val: %x, pwm_pos: %x\n", st->gpio_dir, st->gpio_val, st->cfg.gpio_pwm_pos);
Patrick Boettchera75763f2006-10-18 08:34:16 -0300532
533 dib7000p_write_word(st, 1029, st->gpio_dir);
534 dib7000p_write_word(st, 1030, st->gpio_val);
535
536 /* TODO 1031 is P_gpio_od */
537
538 dib7000p_write_word(st, 1032, st->cfg.gpio_pwm_pos);
539
540 dib7000p_write_word(st, 1037, st->cfg.pwm_freq_div);
541 return 0;
542}
543
Patrick Boettcher01373a52007-07-30 12:49:04 -0300544static int dib7000p_cfg_gpio(struct dib7000p_state *st, u8 num, u8 dir, u8 val)
545{
546 st->gpio_dir = dib7000p_read_word(st, 1029);
Olivier Grenie713d54a2011-01-04 04:54:31 -0300547 st->gpio_dir &= ~(1 << num); /* reset the direction bit */
548 st->gpio_dir |= (dir & 0x1) << num; /* set the new direction */
Patrick Boettcher01373a52007-07-30 12:49:04 -0300549 dib7000p_write_word(st, 1029, st->gpio_dir);
550
551 st->gpio_val = dib7000p_read_word(st, 1030);
Olivier Grenie713d54a2011-01-04 04:54:31 -0300552 st->gpio_val &= ~(1 << num); /* reset the direction bit */
553 st->gpio_val |= (val & 0x01) << num; /* set the new value */
Patrick Boettcher01373a52007-07-30 12:49:04 -0300554 dib7000p_write_word(st, 1030, st->gpio_val);
555
556 return 0;
557}
558
Mauro Carvalho Chehab8abe4a02014-05-29 09:20:15 -0300559static int dib7000p_set_gpio(struct dvb_frontend *demod, u8 num, u8 dir, u8 val)
Patrick Boettcher01373a52007-07-30 12:49:04 -0300560{
561 struct dib7000p_state *state = demod->demodulator_priv;
562 return dib7000p_cfg_gpio(state, num, dir, val);
563}
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300564
Olivier Grenie713d54a2011-01-04 04:54:31 -0300565static u16 dib7000p_defaults[] = {
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300566 // auto search configuration
567 3, 2,
Olivier Grenie713d54a2011-01-04 04:54:31 -0300568 0x0004,
Olivier Grenie2e802862011-08-05 10:39:15 -0300569 (1<<3)|(1<<11)|(1<<12)|(1<<13),
Olivier Grenie713d54a2011-01-04 04:54:31 -0300570 0x0814, /* Equal Lock */
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300571
572 12, 6,
Olivier Grenie713d54a2011-01-04 04:54:31 -0300573 0x001b,
574 0x7740,
575 0x005b,
576 0x8d80,
577 0x01c9,
578 0xc380,
579 0x0000,
580 0x0080,
581 0x0000,
582 0x0090,
583 0x0001,
584 0xd4c0,
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300585
586 1, 26,
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300587 0x6680,
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300588
589 /* set ADC level to -16 */
590 11, 79,
Olivier Grenie713d54a2011-01-04 04:54:31 -0300591 (1 << 13) - 825 - 117,
592 (1 << 13) - 837 - 117,
593 (1 << 13) - 811 - 117,
594 (1 << 13) - 766 - 117,
595 (1 << 13) - 737 - 117,
596 (1 << 13) - 693 - 117,
597 (1 << 13) - 648 - 117,
598 (1 << 13) - 619 - 117,
599 (1 << 13) - 575 - 117,
600 (1 << 13) - 531 - 117,
601 (1 << 13) - 501 - 117,
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300602
603 1, 142,
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300604 0x0410,
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300605
606 /* disable power smoothing */
607 8, 145,
Olivier Grenie713d54a2011-01-04 04:54:31 -0300608 0,
609 0,
610 0,
611 0,
612 0,
613 0,
614 0,
615 0,
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300616
617 1, 154,
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300618 1 << 13,
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300619
620 1, 168,
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300621 0x0ccd,
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300622
623 1, 183,
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300624 0x200f,
Olivier Grenie713d54a2011-01-04 04:54:31 -0300625
626 1, 212,
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300627 0x169,
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300628
629 5, 187,
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300630 0x023d,
631 0x00a4,
632 0x00a4,
633 0x7ff0,
634 0x3ccc,
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300635
636 1, 198,
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300637 0x800,
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300638
639 1, 222,
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300640 0x0010,
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300641
642 1, 235,
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300643 0x0062,
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300644
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300645 0,
646};
647
Mauro Carvalho Chehab041ad442014-05-29 14:44:56 -0300648static void dib7000p_reset_stats(struct dvb_frontend *fe);
649
Patrick Boettchera75763f2006-10-18 08:34:16 -0300650static int dib7000p_demod_reset(struct dib7000p_state *state)
651{
652 dib7000p_set_power_mode(state, DIB7000P_POWER_ALL);
653
Olivier Grenie713d54a2011-01-04 04:54:31 -0300654 if (state->version == SOC7090)
655 dibx000_reset_i2c_master(&state->i2c_master);
656
Patrick Boettchera75763f2006-10-18 08:34:16 -0300657 dib7000p_set_adc_state(state, DIBX000_VBG_ENABLE);
658
659 /* restart all parts */
Olivier Grenie713d54a2011-01-04 04:54:31 -0300660 dib7000p_write_word(state, 770, 0xffff);
661 dib7000p_write_word(state, 771, 0xffff);
662 dib7000p_write_word(state, 772, 0x001f);
Olivier Grenie713d54a2011-01-04 04:54:31 -0300663 dib7000p_write_word(state, 1280, 0x001f - ((1 << 4) | (1 << 3)));
Patrick Boettchera75763f2006-10-18 08:34:16 -0300664
Olivier Grenie713d54a2011-01-04 04:54:31 -0300665 dib7000p_write_word(state, 770, 0);
666 dib7000p_write_word(state, 771, 0);
667 dib7000p_write_word(state, 772, 0);
Patrick Boettchera75763f2006-10-18 08:34:16 -0300668 dib7000p_write_word(state, 1280, 0);
669
Olivier Grenie2e802862011-08-05 10:39:15 -0300670 if (state->version != SOC7090) {
671 dib7000p_write_word(state, 898, 0x0003);
672 dib7000p_write_word(state, 898, 0);
673 }
674
Patrick Boettchera75763f2006-10-18 08:34:16 -0300675 /* default */
676 dib7000p_reset_pll(state);
677
678 if (dib7000p_reset_gpio(state) != 0)
Mauro Carvalho Chehab5a0e2a42016-10-14 09:35:33 -0300679 dprintk("GPIO reset was not successful.\n");
Patrick Boettchera75763f2006-10-18 08:34:16 -0300680
Olivier Grenie713d54a2011-01-04 04:54:31 -0300681 if (state->version == SOC7090) {
682 dib7000p_write_word(state, 899, 0);
683
684 /* impulse noise */
685 dib7000p_write_word(state, 42, (1<<5) | 3); /* P_iqc_thsat_ipc = 1 ; P_iqc_win2 = 3 */
686 dib7000p_write_word(state, 43, 0x2d4); /*-300 fag P_iqc_dect_min = -280 */
687 dib7000p_write_word(state, 44, 300); /* 300 fag P_iqc_dect_min = +280 */
Olivier Grenie2e802862011-08-05 10:39:15 -0300688 dib7000p_write_word(state, 273, (0<<6) | 30);
Olivier Grenie713d54a2011-01-04 04:54:31 -0300689 }
Patrick Boettchera75763f2006-10-18 08:34:16 -0300690 if (dib7000p_set_output_mode(state, OUTMODE_HIGH_Z) != 0)
Mauro Carvalho Chehab5a0e2a42016-10-14 09:35:33 -0300691 dprintk("OUTPUT_MODE could not be reset.\n");
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300692
693 dib7000p_set_adc_state(state, DIBX000_SLOW_ADC_ON);
694 dib7000p_sad_calib(state);
695 dib7000p_set_adc_state(state, DIBX000_SLOW_ADC_OFF);
696
Olivier Grenie713d54a2011-01-04 04:54:31 -0300697 /* unforce divstr regardless whether i2c enumeration was done or not */
698 dib7000p_write_word(state, 1285, dib7000p_read_word(state, 1285) & ~(1 << 1));
699
700 dib7000p_set_bandwidth(state, 8000);
701
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300702 if (state->version == SOC7090) {
Olivier Grenie2e802862011-08-05 10:39:15 -0300703 dib7000p_write_word(state, 36, 0x0755);/* P_iqc_impnc_on =1 & P_iqc_corr_inh = 1 for impulsive noise */
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300704 } else {
Olivier Grenie713d54a2011-01-04 04:54:31 -0300705 if (state->cfg.tuner_is_baseband)
706 dib7000p_write_word(state, 36, 0x0755);
707 else
708 dib7000p_write_word(state, 36, 0x1f55);
709 }
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300710
711 dib7000p_write_tab(state, dib7000p_defaults);
Olivier Grenie2e802862011-08-05 10:39:15 -0300712 if (state->version != SOC7090) {
713 dib7000p_write_word(state, 901, 0x0006);
714 dib7000p_write_word(state, 902, (3 << 10) | (1 << 6));
715 dib7000p_write_word(state, 905, 0x2c8e);
716 }
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300717
Patrick Boettchera75763f2006-10-18 08:34:16 -0300718 dib7000p_set_power_mode(state, DIB7000P_POWER_INTERFACE_ONLY);
719
720 return 0;
721}
722
Patrick Boettchera75763f2006-10-18 08:34:16 -0300723static void dib7000p_pll_clk_cfg(struct dib7000p_state *state)
724{
725 u16 tmp = 0;
726 tmp = dib7000p_read_word(state, 903);
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300727 dib7000p_write_word(state, 903, (tmp | 0x1));
Patrick Boettchera75763f2006-10-18 08:34:16 -0300728 tmp = dib7000p_read_word(state, 900);
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300729 dib7000p_write_word(state, 900, (tmp & 0x7fff) | (1 << 6));
Patrick Boettchera75763f2006-10-18 08:34:16 -0300730}
731
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300732static void dib7000p_restart_agc(struct dib7000p_state *state)
Patrick Boettchera75763f2006-10-18 08:34:16 -0300733{
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300734 // P_restart_iqc & P_restart_agc
735 dib7000p_write_word(state, 770, (1 << 11) | (1 << 9));
736 dib7000p_write_word(state, 770, 0x0000);
Patrick Boettchera75763f2006-10-18 08:34:16 -0300737}
738
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300739static int dib7000p_update_lna(struct dib7000p_state *state)
Patrick Boettchera75763f2006-10-18 08:34:16 -0300740{
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300741 u16 dyn_gain;
742
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300743 if (state->cfg.update_lna) {
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300744 dyn_gain = dib7000p_read_word(state, 394);
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300745 if (state->cfg.update_lna(&state->demod, dyn_gain)) {
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300746 dib7000p_restart_agc(state);
747 return 1;
748 }
749 }
750
751 return 0;
752}
753
754static int dib7000p_set_agc_config(struct dib7000p_state *state, u8 band)
755{
756 struct dibx000_agc_config *agc = NULL;
757 int i;
758 if (state->current_band == band && state->current_agc != NULL)
759 return 0;
760 state->current_band = band;
761
762 for (i = 0; i < state->cfg.agc_config_count; i++)
763 if (state->cfg.agc[i].band_caps & band) {
764 agc = &state->cfg.agc[i];
765 break;
766 }
767
768 if (agc == NULL) {
Mauro Carvalho Chehab5a0e2a42016-10-14 09:35:33 -0300769 dprintk("no valid AGC configuration found for band 0x%02x\n", band);
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300770 return -EINVAL;
771 }
772
773 state->current_agc = agc;
774
775 /* AGC */
Olivier Grenie713d54a2011-01-04 04:54:31 -0300776 dib7000p_write_word(state, 75, agc->setup);
777 dib7000p_write_word(state, 76, agc->inv_gain);
778 dib7000p_write_word(state, 77, agc->time_stabiliz);
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300779 dib7000p_write_word(state, 100, (agc->alpha_level << 12) | agc->thlock);
780
781 // Demod AGC loop configuration
782 dib7000p_write_word(state, 101, (agc->alpha_mant << 5) | agc->alpha_exp);
Olivier Grenie713d54a2011-01-04 04:54:31 -0300783 dib7000p_write_word(state, 102, (agc->beta_mant << 6) | agc->beta_exp);
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300784
785 /* AGC continued */
Mauro Carvalho Chehab5a0e2a42016-10-14 09:35:33 -0300786 dprintk("WBD: ref: %d, sel: %d, active: %d, alpha: %d\n",
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300787 state->wbd_ref != 0 ? state->wbd_ref : agc->wbd_ref, agc->wbd_sel, !agc->perform_agc_softsplit, agc->wbd_sel);
788
789 if (state->wbd_ref != 0)
790 dib7000p_write_word(state, 105, (agc->wbd_inv << 12) | state->wbd_ref);
791 else
792 dib7000p_write_word(state, 105, (agc->wbd_inv << 12) | agc->wbd_ref);
793
794 dib7000p_write_word(state, 106, (agc->wbd_sel << 13) | (agc->wbd_alpha << 9) | (agc->perform_agc_softsplit << 8));
795
Olivier Grenie713d54a2011-01-04 04:54:31 -0300796 dib7000p_write_word(state, 107, agc->agc1_max);
797 dib7000p_write_word(state, 108, agc->agc1_min);
798 dib7000p_write_word(state, 109, agc->agc2_max);
799 dib7000p_write_word(state, 110, agc->agc2_min);
800 dib7000p_write_word(state, 111, (agc->agc1_pt1 << 8) | agc->agc1_pt2);
801 dib7000p_write_word(state, 112, agc->agc1_pt3);
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300802 dib7000p_write_word(state, 113, (agc->agc1_slope1 << 8) | agc->agc1_slope2);
Olivier Grenie713d54a2011-01-04 04:54:31 -0300803 dib7000p_write_word(state, 114, (agc->agc2_pt1 << 8) | agc->agc2_pt2);
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300804 dib7000p_write_word(state, 115, (agc->agc2_slope1 << 8) | agc->agc2_slope2);
805 return 0;
806}
807
Martin Wache5332b622016-12-13 18:21:41 -0200808static int dib7000p_set_dds(struct dib7000p_state *state, s32 offset_khz)
Olivier Grenie713d54a2011-01-04 04:54:31 -0300809{
810 u32 internal = dib7000p_get_internal_freq(state);
Martin Wache5332b622016-12-13 18:21:41 -0200811 s32 unit_khz_dds_val;
Dan Gopstein7aa92c42017-12-25 16:16:14 -0500812 u32 abs_offset_khz = abs(offset_khz);
Olivier Grenie713d54a2011-01-04 04:54:31 -0300813 u32 dds = state->cfg.bw->ifreq & 0x1ffffff;
814 u8 invert = !!(state->cfg.bw->ifreq & (1 << 25));
Martin Wache5332b622016-12-13 18:21:41 -0200815 if (internal == 0) {
816 pr_warn("DIB7000P: dib7000p_get_internal_freq returned 0\n");
817 return -1;
818 }
819 /* 2**26 / Fsampling is the unit 1KHz offset */
820 unit_khz_dds_val = 67108864 / (internal);
Olivier Grenie713d54a2011-01-04 04:54:31 -0300821
Mauro Carvalho Chehab5a0e2a42016-10-14 09:35:33 -0300822 dprintk("setting a frequency offset of %dkHz internal freq = %d invert = %d\n", offset_khz, internal, invert);
Olivier Grenie713d54a2011-01-04 04:54:31 -0300823
824 if (offset_khz < 0)
825 unit_khz_dds_val *= -1;
826
827 /* IF tuner */
828 if (invert)
829 dds -= (abs_offset_khz * unit_khz_dds_val); /* /100 because of /100 on the unit_khz_dds_val line calc for better accuracy */
830 else
831 dds += (abs_offset_khz * unit_khz_dds_val);
832
833 if (abs_offset_khz <= (internal / 2)) { /* Max dds offset is the half of the demod freq */
834 dib7000p_write_word(state, 21, (u16) (((dds >> 16) & 0x1ff) | (0 << 10) | (invert << 9)));
835 dib7000p_write_word(state, 22, (u16) (dds & 0xffff));
836 }
Martin Wache5332b622016-12-13 18:21:41 -0200837 return 0;
Olivier Grenie713d54a2011-01-04 04:54:31 -0300838}
839
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -0300840static int dib7000p_agc_startup(struct dvb_frontend *demod)
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300841{
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -0300842 struct dtv_frontend_properties *ch = &demod->dtv_property_cache;
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300843 struct dib7000p_state *state = demod->demodulator_priv;
844 int ret = -1;
845 u8 *agc_state = &state->agc_state;
846 u8 agc_split;
Olivier Grenie713d54a2011-01-04 04:54:31 -0300847 u16 reg;
848 u32 upd_demod_gain_period = 0x1000;
Olivier Grenie6fe10992012-12-31 09:23:26 -0300849 s32 frequency_offset = 0;
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300850
851 switch (state->agc_state) {
Olivier Grenie713d54a2011-01-04 04:54:31 -0300852 case 0:
Olivier Grenie713d54a2011-01-04 04:54:31 -0300853 dib7000p_set_power_mode(state, DIB7000P_POWER_ALL);
854 if (state->version == SOC7090) {
855 reg = dib7000p_read_word(state, 0x79b) & 0xff00;
856 dib7000p_write_word(state, 0x79a, upd_demod_gain_period & 0xFFFF); /* lsb */
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300857 dib7000p_write_word(state, 0x79b, reg | (1 << 14) | ((upd_demod_gain_period >> 16) & 0xFF));
Olivier Grenie713d54a2011-01-04 04:54:31 -0300858
859 /* enable adc i & q */
860 reg = dib7000p_read_word(state, 0x780);
861 dib7000p_write_word(state, 0x780, (reg | (0x3)) & (~(1 << 7)));
862 } else {
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300863 dib7000p_set_adc_state(state, DIBX000_ADC_ON);
864 dib7000p_pll_clk_cfg(state);
Olivier Grenie713d54a2011-01-04 04:54:31 -0300865 }
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300866
Olivier Grenie713d54a2011-01-04 04:54:31 -0300867 if (dib7000p_set_agc_config(state, BAND_OF_FREQUENCY(ch->frequency / 1000)) != 0)
868 return -1;
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300869
Olivier Grenie6fe10992012-12-31 09:23:26 -0300870 if (demod->ops.tuner_ops.get_frequency) {
871 u32 frequency_tuner;
872
873 demod->ops.tuner_ops.get_frequency(demod, &frequency_tuner);
874 frequency_offset = (s32)frequency_tuner / 1000 - ch->frequency / 1000;
875 }
876
Martin Wache5332b622016-12-13 18:21:41 -0200877 if (dib7000p_set_dds(state, frequency_offset) < 0)
878 return -1;
879
Olivier Grenie713d54a2011-01-04 04:54:31 -0300880 ret = 7;
881 (*agc_state)++;
882 break;
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300883
Olivier Grenie713d54a2011-01-04 04:54:31 -0300884 case 1:
Olivier Grenie713d54a2011-01-04 04:54:31 -0300885 if (state->cfg.agc_control)
886 state->cfg.agc_control(&state->demod, 1);
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300887
Olivier Grenie713d54a2011-01-04 04:54:31 -0300888 dib7000p_write_word(state, 78, 32768);
889 if (!state->current_agc->perform_agc_softsplit) {
890 /* we are using the wbd - so slow AGC startup */
891 /* force 0 split on WBD and restart AGC */
892 dib7000p_write_word(state, 106, (state->current_agc->wbd_sel << 13) | (state->current_agc->wbd_alpha << 9) | (1 << 8));
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300893 (*agc_state)++;
894 ret = 5;
Olivier Grenie713d54a2011-01-04 04:54:31 -0300895 } else {
896 /* default AGC startup */
897 (*agc_state) = 4;
898 /* wait AGC rough lock time */
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300899 ret = 7;
Olivier Grenie713d54a2011-01-04 04:54:31 -0300900 }
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300901
Olivier Grenie713d54a2011-01-04 04:54:31 -0300902 dib7000p_restart_agc(state);
903 break;
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300904
Olivier Grenie713d54a2011-01-04 04:54:31 -0300905 case 2: /* fast split search path after 5sec */
906 dib7000p_write_word(state, 75, state->current_agc->setup | (1 << 4)); /* freeze AGC loop */
907 dib7000p_write_word(state, 106, (state->current_agc->wbd_sel << 13) | (2 << 9) | (0 << 8)); /* fast split search 0.25kHz */
908 (*agc_state)++;
909 ret = 14;
910 break;
911
912 case 3: /* split search ended */
913 agc_split = (u8) dib7000p_read_word(state, 396); /* store the split value for the next time */
914 dib7000p_write_word(state, 78, dib7000p_read_word(state, 394)); /* set AGC gain start value */
915
916 dib7000p_write_word(state, 75, state->current_agc->setup); /* std AGC loop */
917 dib7000p_write_word(state, 106, (state->current_agc->wbd_sel << 13) | (state->current_agc->wbd_alpha << 9) | agc_split); /* standard split search */
918
919 dib7000p_restart_agc(state);
920
Mauro Carvalho Chehab5a0e2a42016-10-14 09:35:33 -0300921 dprintk("SPLIT %p: %hd\n", demod, agc_split);
Olivier Grenie713d54a2011-01-04 04:54:31 -0300922
923 (*agc_state)++;
924 ret = 5;
925 break;
926
927 case 4: /* LNA startup */
Olivier Grenie713d54a2011-01-04 04:54:31 -0300928 ret = 7;
929
930 if (dib7000p_update_lna(state))
Olivier Grenie713d54a2011-01-04 04:54:31 -0300931 ret = 5;
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300932 else
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300933 (*agc_state)++;
Olivier Grenie713d54a2011-01-04 04:54:31 -0300934 break;
935
936 case 5:
937 if (state->cfg.agc_control)
938 state->cfg.agc_control(&state->demod, 0);
939 (*agc_state)++;
940 break;
941 default:
942 break;
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300943 }
944 return ret;
945}
946
947static void dib7000p_update_timf(struct dib7000p_state *state)
948{
949 u32 timf = (dib7000p_read_word(state, 427) << 16) | dib7000p_read_word(state, 428);
950 state->timf = timf * 160 / (state->current_bandwidth / 50);
951 dib7000p_write_word(state, 23, (u16) (timf >> 16));
952 dib7000p_write_word(state, 24, (u16) (timf & 0xffff));
Mauro Carvalho Chehab5a0e2a42016-10-14 09:35:33 -0300953 dprintk("updated timf_frequency: %d (default: %d)\n", state->timf, state->cfg.bw->timf);
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300954
955}
956
Mauro Carvalho Chehab8abe4a02014-05-29 09:20:15 -0300957static u32 dib7000p_ctrl_timf(struct dvb_frontend *fe, u8 op, u32 timf)
Olivier Grenie713d54a2011-01-04 04:54:31 -0300958{
959 struct dib7000p_state *state = fe->demodulator_priv;
960 switch (op) {
961 case DEMOD_TIMF_SET:
962 state->timf = timf;
963 break;
964 case DEMOD_TIMF_UPDATE:
965 dib7000p_update_timf(state);
966 break;
967 case DEMOD_TIMF_GET:
968 break;
969 }
970 dib7000p_set_bandwidth(state, state->current_bandwidth);
971 return state->timf;
972}
Olivier Grenie713d54a2011-01-04 04:54:31 -0300973
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -0300974static void dib7000p_set_channel(struct dib7000p_state *state,
975 struct dtv_frontend_properties *ch, u8 seq)
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300976{
977 u16 value, est[4];
978
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -0300979 dib7000p_set_bandwidth(state, BANDWIDTH_TO_KHZ(ch->bandwidth_hz));
Patrick Boettchera75763f2006-10-18 08:34:16 -0300980
981 /* nfft, guard, qam, alpha */
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300982 value = 0;
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -0300983 switch (ch->transmission_mode) {
Olivier Grenie713d54a2011-01-04 04:54:31 -0300984 case TRANSMISSION_MODE_2K:
985 value |= (0 << 7);
986 break;
Mauro Carvalho Chehab46f72962011-01-16 13:01:20 -0200987 case TRANSMISSION_MODE_4K:
Olivier Grenie713d54a2011-01-04 04:54:31 -0300988 value |= (2 << 7);
989 break;
990 default:
991 case TRANSMISSION_MODE_8K:
992 value |= (1 << 7);
993 break;
Patrick Boettcherb6884a12007-07-27 10:08:51 -0300994 }
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -0300995 switch (ch->guard_interval) {
Olivier Grenie713d54a2011-01-04 04:54:31 -0300996 case GUARD_INTERVAL_1_32:
997 value |= (0 << 5);
998 break;
999 case GUARD_INTERVAL_1_16:
1000 value |= (1 << 5);
1001 break;
1002 case GUARD_INTERVAL_1_4:
1003 value |= (3 << 5);
1004 break;
1005 default:
1006 case GUARD_INTERVAL_1_8:
1007 value |= (2 << 5);
1008 break;
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001009 }
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -03001010 switch (ch->modulation) {
Olivier Grenie713d54a2011-01-04 04:54:31 -03001011 case QPSK:
1012 value |= (0 << 3);
1013 break;
1014 case QAM_16:
1015 value |= (1 << 3);
1016 break;
1017 default:
1018 case QAM_64:
1019 value |= (2 << 3);
1020 break;
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001021 }
1022 switch (HIERARCHY_1) {
Olivier Grenie713d54a2011-01-04 04:54:31 -03001023 case HIERARCHY_2:
1024 value |= 2;
1025 break;
1026 case HIERARCHY_4:
1027 value |= 4;
1028 break;
1029 default:
1030 case HIERARCHY_1:
1031 value |= 1;
1032 break;
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001033 }
1034 dib7000p_write_word(state, 0, value);
Olivier Grenie713d54a2011-01-04 04:54:31 -03001035 dib7000p_write_word(state, 5, (seq << 4) | 1); /* do not force tps, search list 0 */
Patrick Boettchera75763f2006-10-18 08:34:16 -03001036
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001037 /* P_dintl_native, P_dintlv_inv, P_hrch, P_code_rate, P_select_hp */
1038 value = 0;
1039 if (1 != 0)
1040 value |= (1 << 6);
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -03001041 if (ch->hierarchy == 1)
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001042 value |= (1 << 4);
1043 if (1 == 1)
1044 value |= 1;
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -03001045 switch ((ch->hierarchy == 0 || 1 == 1) ? ch->code_rate_HP : ch->code_rate_LP) {
Olivier Grenie713d54a2011-01-04 04:54:31 -03001046 case FEC_2_3:
1047 value |= (2 << 1);
1048 break;
1049 case FEC_3_4:
1050 value |= (3 << 1);
1051 break;
1052 case FEC_5_6:
1053 value |= (5 << 1);
1054 break;
1055 case FEC_7_8:
1056 value |= (7 << 1);
1057 break;
1058 default:
1059 case FEC_1_2:
1060 value |= (1 << 1);
1061 break;
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001062 }
1063 dib7000p_write_word(state, 208, value);
1064
1065 /* offset loop parameters */
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001066 dib7000p_write_word(state, 26, 0x6680);
1067 dib7000p_write_word(state, 32, 0x0003);
1068 dib7000p_write_word(state, 29, 0x1273);
1069 dib7000p_write_word(state, 33, 0x0005);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001070
1071 /* P_dvsy_sync_wait */
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -03001072 switch (ch->transmission_mode) {
Olivier Grenie713d54a2011-01-04 04:54:31 -03001073 case TRANSMISSION_MODE_8K:
1074 value = 256;
1075 break;
1076 case TRANSMISSION_MODE_4K:
1077 value = 128;
1078 break;
1079 case TRANSMISSION_MODE_2K:
1080 default:
1081 value = 64;
1082 break;
Patrick Boettchera75763f2006-10-18 08:34:16 -03001083 }
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -03001084 switch (ch->guard_interval) {
Olivier Grenie713d54a2011-01-04 04:54:31 -03001085 case GUARD_INTERVAL_1_16:
1086 value *= 2;
1087 break;
1088 case GUARD_INTERVAL_1_8:
1089 value *= 4;
1090 break;
1091 case GUARD_INTERVAL_1_4:
1092 value *= 8;
1093 break;
1094 default:
1095 case GUARD_INTERVAL_1_32:
1096 value *= 1;
1097 break;
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001098 }
Olivier Grenie970d14c2010-09-07 12:50:46 -03001099 if (state->cfg.diversity_delay == 0)
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001100 state->div_sync_wait = (value * 3) / 2 + 48;
Olivier Grenie970d14c2010-09-07 12:50:46 -03001101 else
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001102 state->div_sync_wait = (value * 3) / 2 + state->cfg.diversity_delay;
Patrick Boettchera75763f2006-10-18 08:34:16 -03001103
Mauro Carvalho Chehab868c9a12019-02-18 14:28:55 -05001104 /* deactivate the possibility of diversity reception if extended interleaver */
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -03001105 state->div_force_off = !1 && ch->transmission_mode != TRANSMISSION_MODE_8K;
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001106 dib7000p_set_diversity_in(&state->demod, state->div_state);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001107
1108 /* channel estimation fine configuration */
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -03001109 switch (ch->modulation) {
Olivier Grenie713d54a2011-01-04 04:54:31 -03001110 case QAM_64:
1111 est[0] = 0x0148; /* P_adp_regul_cnt 0.04 */
1112 est[1] = 0xfff0; /* P_adp_noise_cnt -0.002 */
1113 est[2] = 0x00a4; /* P_adp_regul_ext 0.02 */
1114 est[3] = 0xfff8; /* P_adp_noise_ext -0.001 */
1115 break;
1116 case QAM_16:
1117 est[0] = 0x023d; /* P_adp_regul_cnt 0.07 */
1118 est[1] = 0xffdf; /* P_adp_noise_cnt -0.004 */
1119 est[2] = 0x00a4; /* P_adp_regul_ext 0.02 */
1120 est[3] = 0xfff0; /* P_adp_noise_ext -0.002 */
1121 break;
1122 default:
1123 est[0] = 0x099a; /* P_adp_regul_cnt 0.3 */
1124 est[1] = 0xffae; /* P_adp_noise_cnt -0.01 */
1125 est[2] = 0x0333; /* P_adp_regul_ext 0.1 */
1126 est[3] = 0xfff8; /* P_adp_noise_ext -0.002 */
1127 break;
Patrick Boettchera75763f2006-10-18 08:34:16 -03001128 }
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001129 for (value = 0; value < 4; value++)
1130 dib7000p_write_word(state, 187 + value, est[value]);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001131}
1132
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -03001133static int dib7000p_autosearch_start(struct dvb_frontend *demod)
Patrick Boettchera75763f2006-10-18 08:34:16 -03001134{
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -03001135 struct dtv_frontend_properties *ch = &demod->dtv_property_cache;
Patrick Boettchera75763f2006-10-18 08:34:16 -03001136 struct dib7000p_state *state = demod->demodulator_priv;
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -03001137 struct dtv_frontend_properties schan;
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001138 u32 value, factor;
Olivier Grenie713d54a2011-01-04 04:54:31 -03001139 u32 internal = dib7000p_get_internal_freq(state);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001140
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001141 schan = *ch;
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -03001142 schan.modulation = QAM_64;
1143 schan.guard_interval = GUARD_INTERVAL_1_32;
1144 schan.transmission_mode = TRANSMISSION_MODE_8K;
1145 schan.code_rate_HP = FEC_2_3;
1146 schan.code_rate_LP = FEC_3_4;
1147 schan.hierarchy = 0;
Patrick Boettchera75763f2006-10-18 08:34:16 -03001148
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001149 dib7000p_set_channel(state, &schan, 7);
1150
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -03001151 factor = BANDWIDTH_TO_KHZ(ch->bandwidth_hz);
Olivier Grenie2e802862011-08-05 10:39:15 -03001152 if (factor >= 5000) {
1153 if (state->version == SOC7090)
1154 factor = 2;
1155 else
1156 factor = 1;
1157 } else
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001158 factor = 6;
Patrick Boettchera75763f2006-10-18 08:34:16 -03001159
Olivier Grenie713d54a2011-01-04 04:54:31 -03001160 value = 30 * internal * factor;
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001161 dib7000p_write_word(state, 6, (u16) ((value >> 16) & 0xffff));
1162 dib7000p_write_word(state, 7, (u16) (value & 0xffff));
Olivier Grenie713d54a2011-01-04 04:54:31 -03001163 value = 100 * internal * factor;
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001164 dib7000p_write_word(state, 8, (u16) ((value >> 16) & 0xffff));
1165 dib7000p_write_word(state, 9, (u16) (value & 0xffff));
Olivier Grenie713d54a2011-01-04 04:54:31 -03001166 value = 500 * internal * factor;
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001167 dib7000p_write_word(state, 10, (u16) ((value >> 16) & 0xffff));
1168 dib7000p_write_word(state, 11, (u16) (value & 0xffff));
Patrick Boettchera75763f2006-10-18 08:34:16 -03001169
1170 value = dib7000p_read_word(state, 0);
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001171 dib7000p_write_word(state, 0, (u16) ((1 << 9) | value));
Patrick Boettchera75763f2006-10-18 08:34:16 -03001172 dib7000p_read_word(state, 1284);
1173 dib7000p_write_word(state, 0, (u16) value);
1174
1175 return 0;
1176}
1177
1178static int dib7000p_autosearch_is_irq(struct dvb_frontend *demod)
1179{
1180 struct dib7000p_state *state = demod->demodulator_priv;
1181 u16 irq_pending = dib7000p_read_word(state, 1284);
1182
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001183 if (irq_pending & 0x1)
Patrick Boettchera75763f2006-10-18 08:34:16 -03001184 return 1;
1185
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001186 if (irq_pending & 0x2)
Patrick Boettchera75763f2006-10-18 08:34:16 -03001187 return 2;
1188
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001189 return 0;
Patrick Boettchera75763f2006-10-18 08:34:16 -03001190}
1191
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001192static void dib7000p_spur_protect(struct dib7000p_state *state, u32 rf_khz, u32 bw)
1193{
Olivier Grenie713d54a2011-01-04 04:54:31 -03001194 static s16 notch[] = { 16143, 14402, 12238, 9713, 6902, 3888, 759, -2392 };
1195 static u8 sine[] = { 0, 2, 3, 5, 6, 8, 9, 11, 13, 14, 16, 17, 19, 20, 22,
1196 24, 25, 27, 28, 30, 31, 33, 34, 36, 38, 39, 41, 42, 44, 45, 47, 48, 50, 51,
1197 53, 55, 56, 58, 59, 61, 62, 64, 65, 67, 68, 70, 71, 73, 74, 76, 77, 79, 80,
1198 82, 83, 85, 86, 88, 89, 91, 92, 94, 95, 97, 98, 99, 101, 102, 104, 105,
1199 107, 108, 109, 111, 112, 114, 115, 117, 118, 119, 121, 122, 123, 125, 126,
1200 128, 129, 130, 132, 133, 134, 136, 137, 138, 140, 141, 142, 144, 145, 146,
1201 147, 149, 150, 151, 152, 154, 155, 156, 157, 159, 160, 161, 162, 164, 165,
1202 166, 167, 168, 170, 171, 172, 173, 174, 175, 177, 178, 179, 180, 181, 182,
1203 183, 184, 185, 186, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198,
1204 199, 200, 201, 202, 203, 204, 205, 206, 207, 207, 208, 209, 210, 211, 212,
1205 213, 214, 215, 215, 216, 217, 218, 219, 220, 220, 221, 222, 223, 224, 224,
1206 225, 226, 227, 227, 228, 229, 229, 230, 231, 231, 232, 233, 233, 234, 235,
1207 235, 236, 237, 237, 238, 238, 239, 239, 240, 241, 241, 242, 242, 243, 243,
1208 244, 244, 245, 245, 245, 246, 246, 247, 247, 248, 248, 248, 249, 249, 249,
1209 250, 250, 250, 251, 251, 251, 252, 252, 252, 252, 253, 253, 253, 253, 254,
1210 254, 254, 254, 254, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
1211 255, 255, 255, 255, 255, 255
1212 };
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001213
1214 u32 xtal = state->cfg.bw->xtal_hz / 1000;
Julia Lawall75b697f2009-08-01 16:48:41 -03001215 int f_rel = DIV_ROUND_CLOSEST(rf_khz, xtal) * xtal - rf_khz;
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001216 int k;
Olivier Grenie713d54a2011-01-04 04:54:31 -03001217 int coef_re[8], coef_im[8];
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001218 int bw_khz = bw;
1219 u32 pha;
1220
Mauro Carvalho Chehab5a0e2a42016-10-14 09:35:33 -03001221 dprintk("relative position of the Spur: %dk (RF: %dk, XTAL: %dk)\n", f_rel, rf_khz, xtal);
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001222
Olivier Grenie713d54a2011-01-04 04:54:31 -03001223 if (f_rel < -bw_khz / 2 || f_rel > bw_khz / 2)
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001224 return;
1225
1226 bw_khz /= 100;
1227
Olivier Grenie713d54a2011-01-04 04:54:31 -03001228 dib7000p_write_word(state, 142, 0x0610);
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001229
1230 for (k = 0; k < 8; k++) {
Olivier Grenie713d54a2011-01-04 04:54:31 -03001231 pha = ((f_rel * (k + 1) * 112 * 80 / bw_khz) / 1000) & 0x3ff;
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001232
Olivier Grenie713d54a2011-01-04 04:54:31 -03001233 if (pha == 0) {
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001234 coef_re[k] = 256;
1235 coef_im[k] = 0;
Olivier Grenie713d54a2011-01-04 04:54:31 -03001236 } else if (pha < 256) {
1237 coef_re[k] = sine[256 - (pha & 0xff)];
1238 coef_im[k] = sine[pha & 0xff];
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001239 } else if (pha == 256) {
1240 coef_re[k] = 0;
1241 coef_im[k] = 256;
1242 } else if (pha < 512) {
Olivier Grenie713d54a2011-01-04 04:54:31 -03001243 coef_re[k] = -sine[pha & 0xff];
1244 coef_im[k] = sine[256 - (pha & 0xff)];
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001245 } else if (pha == 512) {
1246 coef_re[k] = -256;
1247 coef_im[k] = 0;
1248 } else if (pha < 768) {
Olivier Grenie713d54a2011-01-04 04:54:31 -03001249 coef_re[k] = -sine[256 - (pha & 0xff)];
1250 coef_im[k] = -sine[pha & 0xff];
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001251 } else if (pha == 768) {
1252 coef_re[k] = 0;
1253 coef_im[k] = -256;
1254 } else {
Olivier Grenie713d54a2011-01-04 04:54:31 -03001255 coef_re[k] = sine[pha & 0xff];
1256 coef_im[k] = -sine[256 - (pha & 0xff)];
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001257 }
1258
1259 coef_re[k] *= notch[k];
Olivier Grenie713d54a2011-01-04 04:54:31 -03001260 coef_re[k] += (1 << 14);
1261 if (coef_re[k] >= (1 << 24))
1262 coef_re[k] = (1 << 24) - 1;
1263 coef_re[k] /= (1 << 15);
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001264
1265 coef_im[k] *= notch[k];
Olivier Grenie713d54a2011-01-04 04:54:31 -03001266 coef_im[k] += (1 << 14);
1267 if (coef_im[k] >= (1 << 24))
1268 coef_im[k] = (1 << 24) - 1;
1269 coef_im[k] /= (1 << 15);
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001270
Mauro Carvalho Chehab5a0e2a42016-10-14 09:35:33 -03001271 dprintk("PALF COEF: %d re: %d im: %d\n", k, coef_re[k], coef_im[k]);
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001272
1273 dib7000p_write_word(state, 143, (0 << 14) | (k << 10) | (coef_re[k] & 0x3ff));
1274 dib7000p_write_word(state, 144, coef_im[k] & 0x3ff);
1275 dib7000p_write_word(state, 143, (1 << 14) | (k << 10) | (coef_re[k] & 0x3ff));
1276 }
Olivier Grenie713d54a2011-01-04 04:54:31 -03001277 dib7000p_write_word(state, 143, 0);
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001278}
1279
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -03001280static int dib7000p_tune(struct dvb_frontend *demod)
Patrick Boettchera75763f2006-10-18 08:34:16 -03001281{
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -03001282 struct dtv_frontend_properties *ch = &demod->dtv_property_cache;
Patrick Boettchera75763f2006-10-18 08:34:16 -03001283 struct dib7000p_state *state = demod->demodulator_priv;
1284 u16 tmp = 0;
1285
1286 if (ch != NULL)
1287 dib7000p_set_channel(state, ch, 0);
1288 else
1289 return -EINVAL;
1290
1291 // restart demod
1292 dib7000p_write_word(state, 770, 0x4000);
1293 dib7000p_write_word(state, 770, 0x0000);
1294 msleep(45);
1295
1296 /* P_ctrl_inh_cor=0, P_ctrl_alpha_cor=4, P_ctrl_inh_isi=0, P_ctrl_alpha_isi=3, P_ctrl_inh_cor4=1, P_ctrl_alpha_cor4=3 */
Matt Doran8f6956c2007-07-31 07:09:30 -03001297 tmp = (0 << 14) | (4 << 10) | (0 << 9) | (3 << 5) | (1 << 4) | (0x3);
1298 if (state->sfn_workaround_active) {
Mauro Carvalho Chehab5a0e2a42016-10-14 09:35:33 -03001299 dprintk("SFN workaround is active\n");
Matt Doran8f6956c2007-07-31 07:09:30 -03001300 tmp |= (1 << 9);
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001301 dib7000p_write_word(state, 166, 0x4000);
Matt Doran8f6956c2007-07-31 07:09:30 -03001302 } else {
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001303 dib7000p_write_word(state, 166, 0x0000);
Matt Doran8f6956c2007-07-31 07:09:30 -03001304 }
1305 dib7000p_write_word(state, 29, tmp);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001306
1307 // never achieved a lock with that bandwidth so far - wait for osc-freq to update
1308 if (state->timf == 0)
1309 msleep(200);
1310
1311 /* offset loop parameters */
1312
1313 /* P_timf_alpha, P_corm_alpha=6, P_corm_thres=0x80 */
1314 tmp = (6 << 8) | 0x80;
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -03001315 switch (ch->transmission_mode) {
Olivier Grenie713d54a2011-01-04 04:54:31 -03001316 case TRANSMISSION_MODE_2K:
1317 tmp |= (2 << 12);
1318 break;
Mauro Carvalho Chehab46f72962011-01-16 13:01:20 -02001319 case TRANSMISSION_MODE_4K:
Olivier Grenie713d54a2011-01-04 04:54:31 -03001320 tmp |= (3 << 12);
1321 break;
1322 default:
1323 case TRANSMISSION_MODE_8K:
1324 tmp |= (4 << 12);
1325 break;
Patrick Boettchera75763f2006-10-18 08:34:16 -03001326 }
Olivier Grenie713d54a2011-01-04 04:54:31 -03001327 dib7000p_write_word(state, 26, tmp); /* timf_a(6xxx) */
Patrick Boettchera75763f2006-10-18 08:34:16 -03001328
1329 /* P_ctrl_freeze_pha_shift=0, P_ctrl_pha_off_max */
1330 tmp = (0 << 4);
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -03001331 switch (ch->transmission_mode) {
Olivier Grenie713d54a2011-01-04 04:54:31 -03001332 case TRANSMISSION_MODE_2K:
1333 tmp |= 0x6;
1334 break;
Mauro Carvalho Chehab46f72962011-01-16 13:01:20 -02001335 case TRANSMISSION_MODE_4K:
Olivier Grenie713d54a2011-01-04 04:54:31 -03001336 tmp |= 0x7;
1337 break;
1338 default:
1339 case TRANSMISSION_MODE_8K:
1340 tmp |= 0x8;
1341 break;
Patrick Boettchera75763f2006-10-18 08:34:16 -03001342 }
Olivier Grenie713d54a2011-01-04 04:54:31 -03001343 dib7000p_write_word(state, 32, tmp);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001344
1345 /* P_ctrl_sfreq_inh=0, P_ctrl_sfreq_step */
1346 tmp = (0 << 4);
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -03001347 switch (ch->transmission_mode) {
Olivier Grenie713d54a2011-01-04 04:54:31 -03001348 case TRANSMISSION_MODE_2K:
1349 tmp |= 0x6;
1350 break;
1351 case TRANSMISSION_MODE_4K:
1352 tmp |= 0x7;
1353 break;
1354 default:
1355 case TRANSMISSION_MODE_8K:
1356 tmp |= 0x8;
1357 break;
Patrick Boettchera75763f2006-10-18 08:34:16 -03001358 }
Olivier Grenie713d54a2011-01-04 04:54:31 -03001359 dib7000p_write_word(state, 33, tmp);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001360
Olivier Grenie713d54a2011-01-04 04:54:31 -03001361 tmp = dib7000p_read_word(state, 509);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001362 if (!((tmp >> 6) & 0x1)) {
1363 /* restart the fec */
Olivier Grenie713d54a2011-01-04 04:54:31 -03001364 tmp = dib7000p_read_word(state, 771);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001365 dib7000p_write_word(state, 771, tmp | (1 << 1));
1366 dib7000p_write_word(state, 771, tmp);
Olivier Grenie713d54a2011-01-04 04:54:31 -03001367 msleep(40);
1368 tmp = dib7000p_read_word(state, 509);
1369 }
1370 // we achieved a lock - it's time to update the osc freq
1371 if ((tmp >> 6) & 0x1) {
1372 dib7000p_update_timf(state);
1373 /* P_timf_alpha += 2 */
1374 tmp = dib7000p_read_word(state, 26);
1375 dib7000p_write_word(state, 26, (tmp & ~(0xf << 12)) | ((((tmp >> 12) & 0xf) + 5) << 12));
Patrick Boettchera75763f2006-10-18 08:34:16 -03001376 }
1377
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001378 if (state->cfg.spur_protect)
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -03001379 dib7000p_spur_protect(state, ch->frequency / 1000, BANDWIDTH_TO_KHZ(ch->bandwidth_hz));
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001380
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -03001381 dib7000p_set_bandwidth(state, BANDWIDTH_TO_KHZ(ch->bandwidth_hz));
Mauro Carvalho Chehab041ad442014-05-29 14:44:56 -03001382
1383 dib7000p_reset_stats(demod);
1384
Patrick Boettchera75763f2006-10-18 08:34:16 -03001385 return 0;
1386}
1387
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001388static int dib7000p_wakeup(struct dvb_frontend *demod)
Patrick Boettchera75763f2006-10-18 08:34:16 -03001389{
Patrick Boettchera75763f2006-10-18 08:34:16 -03001390 struct dib7000p_state *state = demod->demodulator_priv;
Patrick Boettchera75763f2006-10-18 08:34:16 -03001391 dib7000p_set_power_mode(state, DIB7000P_POWER_ALL);
1392 dib7000p_set_adc_state(state, DIBX000_SLOW_ADC_ON);
Olivier Grenie713d54a2011-01-04 04:54:31 -03001393 if (state->version == SOC7090)
1394 dib7000p_sad_calib(state);
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001395 return 0;
Patrick Boettchera75763f2006-10-18 08:34:16 -03001396}
1397
1398static int dib7000p_sleep(struct dvb_frontend *demod)
1399{
1400 struct dib7000p_state *state = demod->demodulator_priv;
Olivier Grenie713d54a2011-01-04 04:54:31 -03001401 if (state->version == SOC7090)
Olivier Grenie2e802862011-08-05 10:39:15 -03001402 return dib7000p_set_power_mode(state, DIB7000P_POWER_INTERFACE_ONLY);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001403 return dib7000p_set_output_mode(state, OUTMODE_HIGH_Z) | dib7000p_set_power_mode(state, DIB7000P_POWER_INTERFACE_ONLY);
1404}
1405
1406static int dib7000p_identify(struct dib7000p_state *st)
1407{
1408 u16 value;
Mauro Carvalho Chehab5a0e2a42016-10-14 09:35:33 -03001409 dprintk("checking demod on I2C address: %d (%x)\n", st->i2c_addr, st->i2c_addr);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001410
1411 if ((value = dib7000p_read_word(st, 768)) != 0x01b3) {
Mauro Carvalho Chehab5a0e2a42016-10-14 09:35:33 -03001412 dprintk("wrong Vendor ID (read=0x%x)\n", value);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001413 return -EREMOTEIO;
1414 }
1415
1416 if ((value = dib7000p_read_word(st, 769)) != 0x4000) {
Mauro Carvalho Chehab5a0e2a42016-10-14 09:35:33 -03001417 dprintk("wrong Device ID (%x)\n", value);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001418 return -EREMOTEIO;
1419 }
1420
1421 return 0;
1422}
1423
Mauro Carvalho Chehab7e3e68b2016-02-04 12:58:30 -02001424static int dib7000p_get_frontend(struct dvb_frontend *fe,
1425 struct dtv_frontend_properties *fep)
Patrick Boettchera75763f2006-10-18 08:34:16 -03001426{
1427 struct dib7000p_state *state = fe->demodulator_priv;
Olivier Grenie713d54a2011-01-04 04:54:31 -03001428 u16 tps = dib7000p_read_word(state, 463);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001429
1430 fep->inversion = INVERSION_AUTO;
1431
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -03001432 fep->bandwidth_hz = BANDWIDTH_TO_HZ(state->current_bandwidth);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001433
1434 switch ((tps >> 8) & 0x3) {
Olivier Grenie713d54a2011-01-04 04:54:31 -03001435 case 0:
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -03001436 fep->transmission_mode = TRANSMISSION_MODE_2K;
Olivier Grenie713d54a2011-01-04 04:54:31 -03001437 break;
1438 case 1:
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -03001439 fep->transmission_mode = TRANSMISSION_MODE_8K;
Olivier Grenie713d54a2011-01-04 04:54:31 -03001440 break;
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -03001441 /* case 2: fep->transmission_mode = TRANSMISSION_MODE_4K; break; */
Patrick Boettchera75763f2006-10-18 08:34:16 -03001442 }
1443
1444 switch (tps & 0x3) {
Olivier Grenie713d54a2011-01-04 04:54:31 -03001445 case 0:
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -03001446 fep->guard_interval = GUARD_INTERVAL_1_32;
Olivier Grenie713d54a2011-01-04 04:54:31 -03001447 break;
1448 case 1:
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -03001449 fep->guard_interval = GUARD_INTERVAL_1_16;
Olivier Grenie713d54a2011-01-04 04:54:31 -03001450 break;
1451 case 2:
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -03001452 fep->guard_interval = GUARD_INTERVAL_1_8;
Olivier Grenie713d54a2011-01-04 04:54:31 -03001453 break;
1454 case 3:
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -03001455 fep->guard_interval = GUARD_INTERVAL_1_4;
Olivier Grenie713d54a2011-01-04 04:54:31 -03001456 break;
Patrick Boettchera75763f2006-10-18 08:34:16 -03001457 }
1458
1459 switch ((tps >> 14) & 0x3) {
Olivier Grenie713d54a2011-01-04 04:54:31 -03001460 case 0:
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -03001461 fep->modulation = QPSK;
Olivier Grenie713d54a2011-01-04 04:54:31 -03001462 break;
1463 case 1:
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -03001464 fep->modulation = QAM_16;
Olivier Grenie713d54a2011-01-04 04:54:31 -03001465 break;
1466 case 2:
1467 default:
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -03001468 fep->modulation = QAM_64;
Olivier Grenie713d54a2011-01-04 04:54:31 -03001469 break;
Patrick Boettchera75763f2006-10-18 08:34:16 -03001470 }
1471
1472 /* as long as the frontend_param structure is fixed for hierarchical transmission I refuse to use it */
1473 /* (tps >> 13) & 0x1 == hrch is used, (tps >> 10) & 0x7 == alpha */
1474
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -03001475 fep->hierarchy = HIERARCHY_NONE;
Patrick Boettchera75763f2006-10-18 08:34:16 -03001476 switch ((tps >> 5) & 0x7) {
Olivier Grenie713d54a2011-01-04 04:54:31 -03001477 case 1:
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -03001478 fep->code_rate_HP = FEC_1_2;
Olivier Grenie713d54a2011-01-04 04:54:31 -03001479 break;
1480 case 2:
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -03001481 fep->code_rate_HP = FEC_2_3;
Olivier Grenie713d54a2011-01-04 04:54:31 -03001482 break;
1483 case 3:
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -03001484 fep->code_rate_HP = FEC_3_4;
Olivier Grenie713d54a2011-01-04 04:54:31 -03001485 break;
1486 case 5:
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -03001487 fep->code_rate_HP = FEC_5_6;
Olivier Grenie713d54a2011-01-04 04:54:31 -03001488 break;
1489 case 7:
1490 default:
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -03001491 fep->code_rate_HP = FEC_7_8;
Olivier Grenie713d54a2011-01-04 04:54:31 -03001492 break;
Patrick Boettchera75763f2006-10-18 08:34:16 -03001493
1494 }
1495
1496 switch ((tps >> 2) & 0x7) {
Olivier Grenie713d54a2011-01-04 04:54:31 -03001497 case 1:
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -03001498 fep->code_rate_LP = FEC_1_2;
Olivier Grenie713d54a2011-01-04 04:54:31 -03001499 break;
1500 case 2:
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -03001501 fep->code_rate_LP = FEC_2_3;
Olivier Grenie713d54a2011-01-04 04:54:31 -03001502 break;
1503 case 3:
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -03001504 fep->code_rate_LP = FEC_3_4;
Olivier Grenie713d54a2011-01-04 04:54:31 -03001505 break;
1506 case 5:
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -03001507 fep->code_rate_LP = FEC_5_6;
Olivier Grenie713d54a2011-01-04 04:54:31 -03001508 break;
1509 case 7:
1510 default:
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -03001511 fep->code_rate_LP = FEC_7_8;
Olivier Grenie713d54a2011-01-04 04:54:31 -03001512 break;
Patrick Boettchera75763f2006-10-18 08:34:16 -03001513 }
1514
1515 /* native interleaver: (dib7000p_read_word(state, 464) >> 5) & 0x1 */
1516
1517 return 0;
1518}
1519
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -03001520static int dib7000p_set_frontend(struct dvb_frontend *fe)
Patrick Boettchera75763f2006-10-18 08:34:16 -03001521{
Mauro Carvalho Chehab7c61d802011-12-30 11:30:21 -03001522 struct dtv_frontend_properties *fep = &fe->dtv_property_cache;
Patrick Boettchera75763f2006-10-18 08:34:16 -03001523 struct dib7000p_state *state = fe->demodulator_priv;
Soeren Moch853ea132008-01-25 06:27:06 -03001524 int time, ret;
Patrick Boettchera75763f2006-10-18 08:34:16 -03001525
Olivier Grenie2e802862011-08-05 10:39:15 -03001526 if (state->version == SOC7090)
Olivier Grenie713d54a2011-01-04 04:54:31 -03001527 dib7090_set_diversity_in(fe, 0);
Olivier Grenie2e802862011-08-05 10:39:15 -03001528 else
Olivier Grenie713d54a2011-01-04 04:54:31 -03001529 dib7000p_set_output_mode(state, OUTMODE_HIGH_Z);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001530
Olivier Grenie713d54a2011-01-04 04:54:31 -03001531 /* maybe the parameter has been changed */
Matt Doran8f6956c2007-07-31 07:09:30 -03001532 state->sfn_workaround_active = buggy_sfn_workaround;
1533
Patrick Boettchera75763f2006-10-18 08:34:16 -03001534 if (fe->ops.tuner_ops.set_params)
Mauro Carvalho Chehab14d24d12011-12-24 12:24:33 -03001535 fe->ops.tuner_ops.set_params(fe);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001536
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001537 /* start up the AGC */
1538 state->agc_state = 0;
1539 do {
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -03001540 time = dib7000p_agc_startup(fe);
Patrick Boettcherb6884a12007-07-27 10:08:51 -03001541 if (time != -1)
1542 msleep(time);
1543 } while (time != -1);
1544
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -03001545 if (fep->transmission_mode == TRANSMISSION_MODE_AUTO ||
1546 fep->guard_interval == GUARD_INTERVAL_AUTO || fep->modulation == QAM_AUTO || fep->code_rate_HP == FEC_AUTO) {
Patrick Boettchera75763f2006-10-18 08:34:16 -03001547 int i = 800, found;
1548
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -03001549 dib7000p_autosearch_start(fe);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001550 do {
1551 msleep(1);
1552 found = dib7000p_autosearch_is_irq(fe);
1553 } while (found == 0 && i--);
1554
Mauro Carvalho Chehab5a0e2a42016-10-14 09:35:33 -03001555 dprintk("autosearch returns: %d\n", found);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001556 if (found == 0 || found == 1)
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001557 return 0;
Patrick Boettchera75763f2006-10-18 08:34:16 -03001558
Mauro Carvalho Chehab7e3e68b2016-02-04 12:58:30 -02001559 dib7000p_get_frontend(fe, fep);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001560 }
1561
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -03001562 ret = dib7000p_tune(fe);
Soeren Moch853ea132008-01-25 06:27:06 -03001563
Patrick Boettchera75763f2006-10-18 08:34:16 -03001564 /* make this a config parameter */
Olivier Grenie2e802862011-08-05 10:39:15 -03001565 if (state->version == SOC7090) {
Olivier Grenie713d54a2011-01-04 04:54:31 -03001566 dib7090_set_output_mode(fe, state->cfg.output_mode);
Olivier Grenie2e802862011-08-05 10:39:15 -03001567 if (state->cfg.enMpegOutput == 0) {
1568 dib7090_setDibTxMux(state, MPEG_ON_DIBTX);
1569 dib7090_setHostBusMux(state, DIBTX_ON_HOSTBUS);
1570 }
1571 } else
Olivier Grenie713d54a2011-01-04 04:54:31 -03001572 dib7000p_set_output_mode(state, state->cfg.output_mode);
1573
1574 return ret;
Patrick Boettchera75763f2006-10-18 08:34:16 -03001575}
1576
Mauro Carvalho Chehab0df289a2015-06-07 14:53:52 -03001577static int dib7000p_get_stats(struct dvb_frontend *fe, enum fe_status stat);
Mauro Carvalho Chehab041ad442014-05-29 14:44:56 -03001578
Mauro Carvalho Chehab0df289a2015-06-07 14:53:52 -03001579static int dib7000p_read_status(struct dvb_frontend *fe, enum fe_status *stat)
Patrick Boettchera75763f2006-10-18 08:34:16 -03001580{
1581 struct dib7000p_state *state = fe->demodulator_priv;
1582 u16 lock = dib7000p_read_word(state, 509);
1583
1584 *stat = 0;
1585
1586 if (lock & 0x8000)
1587 *stat |= FE_HAS_SIGNAL;
1588 if (lock & 0x3000)
1589 *stat |= FE_HAS_CARRIER;
1590 if (lock & 0x0100)
1591 *stat |= FE_HAS_VITERBI;
1592 if (lock & 0x0010)
1593 *stat |= FE_HAS_SYNC;
Olivier Grenie713d54a2011-01-04 04:54:31 -03001594 if ((lock & 0x0038) == 0x38)
Patrick Boettchera75763f2006-10-18 08:34:16 -03001595 *stat |= FE_HAS_LOCK;
1596
Mauro Carvalho Chehab041ad442014-05-29 14:44:56 -03001597 dib7000p_get_stats(fe, *stat);
1598
Patrick Boettchera75763f2006-10-18 08:34:16 -03001599 return 0;
1600}
1601
Olivier Grenie713d54a2011-01-04 04:54:31 -03001602static int dib7000p_read_ber(struct dvb_frontend *fe, u32 * ber)
Patrick Boettchera75763f2006-10-18 08:34:16 -03001603{
1604 struct dib7000p_state *state = fe->demodulator_priv;
1605 *ber = (dib7000p_read_word(state, 500) << 16) | dib7000p_read_word(state, 501);
1606 return 0;
1607}
1608
Olivier Grenie713d54a2011-01-04 04:54:31 -03001609static int dib7000p_read_unc_blocks(struct dvb_frontend *fe, u32 * unc)
Patrick Boettchera75763f2006-10-18 08:34:16 -03001610{
1611 struct dib7000p_state *state = fe->demodulator_priv;
1612 *unc = dib7000p_read_word(state, 506);
1613 return 0;
1614}
1615
Olivier Grenie713d54a2011-01-04 04:54:31 -03001616static int dib7000p_read_signal_strength(struct dvb_frontend *fe, u16 * strength)
Patrick Boettchera75763f2006-10-18 08:34:16 -03001617{
1618 struct dib7000p_state *state = fe->demodulator_priv;
1619 u16 val = dib7000p_read_word(state, 394);
1620 *strength = 65535 - val;
1621 return 0;
1622}
1623
Mauro Carvalho Chehab041ad442014-05-29 14:44:56 -03001624static u32 dib7000p_get_snr(struct dvb_frontend *fe)
Patrick Boettchera75763f2006-10-18 08:34:16 -03001625{
Olivier Grenieef801962009-09-15 06:46:52 -03001626 struct dib7000p_state *state = fe->demodulator_priv;
1627 u16 val;
1628 s32 signal_mant, signal_exp, noise_mant, noise_exp;
1629 u32 result = 0;
1630
1631 val = dib7000p_read_word(state, 479);
1632 noise_mant = (val >> 4) & 0xff;
1633 noise_exp = ((val & 0xf) << 2);
1634 val = dib7000p_read_word(state, 480);
1635 noise_exp += ((val >> 14) & 0x3);
1636 if ((noise_exp & 0x20) != 0)
1637 noise_exp -= 0x40;
1638
1639 signal_mant = (val >> 6) & 0xFF;
Olivier Grenie713d54a2011-01-04 04:54:31 -03001640 signal_exp = (val & 0x3F);
Olivier Grenieef801962009-09-15 06:46:52 -03001641 if ((signal_exp & 0x20) != 0)
1642 signal_exp -= 0x40;
1643
1644 if (signal_mant != 0)
Olivier Grenie713d54a2011-01-04 04:54:31 -03001645 result = intlog10(2) * 10 * signal_exp + 10 * intlog10(signal_mant);
Olivier Grenieef801962009-09-15 06:46:52 -03001646 else
1647 result = intlog10(2) * 10 * signal_exp - 100;
1648
1649 if (noise_mant != 0)
Olivier Grenie713d54a2011-01-04 04:54:31 -03001650 result -= intlog10(2) * 10 * noise_exp + 10 * intlog10(noise_mant);
Olivier Grenieef801962009-09-15 06:46:52 -03001651 else
1652 result -= intlog10(2) * 10 * noise_exp - 100;
1653
Mauro Carvalho Chehab041ad442014-05-29 14:44:56 -03001654 return result;
1655}
1656
1657static int dib7000p_read_snr(struct dvb_frontend *fe, u16 *snr)
1658{
1659 u32 result;
1660
1661 result = dib7000p_get_snr(fe);
1662
Olivier Grenieef801962009-09-15 06:46:52 -03001663 *snr = result / ((1 << 24) / 10);
Patrick Boettchera75763f2006-10-18 08:34:16 -03001664 return 0;
1665}
1666
Mauro Carvalho Chehab041ad442014-05-29 14:44:56 -03001667static void dib7000p_reset_stats(struct dvb_frontend *demod)
1668{
1669 struct dib7000p_state *state = demod->demodulator_priv;
1670 struct dtv_frontend_properties *c = &demod->dtv_property_cache;
1671 u32 ucb;
1672
1673 memset(&c->strength, 0, sizeof(c->strength));
1674 memset(&c->cnr, 0, sizeof(c->cnr));
1675 memset(&c->post_bit_error, 0, sizeof(c->post_bit_error));
1676 memset(&c->post_bit_count, 0, sizeof(c->post_bit_count));
1677 memset(&c->block_error, 0, sizeof(c->block_error));
1678
1679 c->strength.len = 1;
1680 c->cnr.len = 1;
1681 c->block_error.len = 1;
1682 c->block_count.len = 1;
1683 c->post_bit_error.len = 1;
1684 c->post_bit_count.len = 1;
1685
1686 c->strength.stat[0].scale = FE_SCALE_DECIBEL;
1687 c->strength.stat[0].uvalue = 0;
1688
1689 c->cnr.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
1690 c->block_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
1691 c->block_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
1692 c->post_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
1693 c->post_bit_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
1694
1695 dib7000p_read_unc_blocks(demod, &ucb);
1696
1697 state->old_ucb = ucb;
1698 state->ber_jiffies_stats = 0;
1699 state->per_jiffies_stats = 0;
1700}
1701
1702struct linear_segments {
1703 unsigned x;
1704 signed y;
1705};
1706
1707/*
1708 * Table to estimate signal strength in dBm.
1709 * This table should be empirically determinated by measuring the signal
1710 * strength generated by a RF generator directly connected into
1711 * a device.
Mauro Carvalho Chehab3926d912014-05-29 14:44:57 -03001712 * This table was determinated by measuring the signal strength generated
1713 * by a DTA-2111 RF generator directly connected into a dib7000p device
1714 * (a Hauppauge Nova-TD stick), using a good quality 3 meters length
1715 * RC6 cable and good RC6 connectors, connected directly to antenna 1.
1716 * As the minimum output power of DTA-2111 is -31dBm, a 16 dBm attenuator
1717 * were used, for the lower power values.
1718 * The real value can actually be on other devices, or even at the
1719 * second antena input, depending on several factors, like if LNA
1720 * is enabled or not, if diversity is enabled, type of connectors, etc.
1721 * Yet, it is better to use this measure in dB than a random non-linear
1722 * percentage value, especially for antenna adjustments.
1723 * On my tests, the precision of the measure using this table is about
1724 * 0.5 dB, with sounds reasonable enough to adjust antennas.
Mauro Carvalho Chehab041ad442014-05-29 14:44:56 -03001725 */
Mauro Carvalho Chehab3926d912014-05-29 14:44:57 -03001726#define DB_OFFSET 131000
Mauro Carvalho Chehab041ad442014-05-29 14:44:56 -03001727
1728static struct linear_segments strength_to_db_table[] = {
Mauro Carvalho Chehab3926d912014-05-29 14:44:57 -03001729 { 63630, DB_OFFSET - 20500},
1730 { 62273, DB_OFFSET - 21000},
1731 { 60162, DB_OFFSET - 22000},
1732 { 58730, DB_OFFSET - 23000},
1733 { 58294, DB_OFFSET - 24000},
1734 { 57778, DB_OFFSET - 25000},
1735 { 57320, DB_OFFSET - 26000},
1736 { 56779, DB_OFFSET - 27000},
1737 { 56293, DB_OFFSET - 28000},
1738 { 55724, DB_OFFSET - 29000},
1739 { 55145, DB_OFFSET - 30000},
1740 { 54680, DB_OFFSET - 31000},
1741 { 54293, DB_OFFSET - 32000},
1742 { 53813, DB_OFFSET - 33000},
1743 { 53427, DB_OFFSET - 34000},
1744 { 52981, DB_OFFSET - 35000},
1745
1746 { 52636, DB_OFFSET - 36000},
1747 { 52014, DB_OFFSET - 37000},
1748 { 51674, DB_OFFSET - 38000},
1749 { 50692, DB_OFFSET - 39000},
1750 { 49824, DB_OFFSET - 40000},
1751 { 49052, DB_OFFSET - 41000},
1752 { 48436, DB_OFFSET - 42000},
1753 { 47836, DB_OFFSET - 43000},
1754 { 47368, DB_OFFSET - 44000},
1755 { 46468, DB_OFFSET - 45000},
1756 { 45597, DB_OFFSET - 46000},
1757 { 44586, DB_OFFSET - 47000},
1758 { 43667, DB_OFFSET - 48000},
1759 { 42673, DB_OFFSET - 49000},
1760 { 41816, DB_OFFSET - 50000},
1761 { 40876, DB_OFFSET - 51000},
Mauro Carvalho Chehab041ad442014-05-29 14:44:56 -03001762 { 0, 0},
1763};
1764
1765static u32 interpolate_value(u32 value, struct linear_segments *segments,
1766 unsigned len)
1767{
1768 u64 tmp64;
1769 u32 dx;
1770 s32 dy;
1771 int i, ret;
1772
1773 if (value >= segments[0].x)
1774 return segments[0].y;
1775 if (value < segments[len-1].x)
1776 return segments[len-1].y;
1777
1778 for (i = 1; i < len - 1; i++) {
1779 /* If value is identical, no need to interpolate */
1780 if (value == segments[i].x)
1781 return segments[i].y;
1782 if (value > segments[i].x)
1783 break;
1784 }
1785
1786 /* Linear interpolation between the two (x,y) points */
1787 dy = segments[i - 1].y - segments[i].y;
1788 dx = segments[i - 1].x - segments[i].x;
1789
1790 tmp64 = value - segments[i].x;
1791 tmp64 *= dy;
1792 do_div(tmp64, dx);
1793 ret = segments[i].y + tmp64;
1794
1795 return ret;
1796}
1797
1798/* FIXME: may require changes - this one was borrowed from dib8000 */
Mauro Carvalho Chehab986f1682014-10-09 10:29:35 -03001799static u32 dib7000p_get_time_us(struct dvb_frontend *demod)
Mauro Carvalho Chehab041ad442014-05-29 14:44:56 -03001800{
1801 struct dtv_frontend_properties *c = &demod->dtv_property_cache;
1802 u64 time_us, tmp64;
1803 u32 tmp, denom;
1804 int guard, rate_num, rate_denum = 1, bits_per_symbol;
1805 int interleaving = 0, fft_div;
1806
1807 switch (c->guard_interval) {
1808 case GUARD_INTERVAL_1_4:
1809 guard = 4;
1810 break;
1811 case GUARD_INTERVAL_1_8:
1812 guard = 8;
1813 break;
1814 case GUARD_INTERVAL_1_16:
1815 guard = 16;
1816 break;
1817 default:
1818 case GUARD_INTERVAL_1_32:
1819 guard = 32;
1820 break;
1821 }
1822
1823 switch (c->transmission_mode) {
1824 case TRANSMISSION_MODE_2K:
1825 fft_div = 4;
1826 break;
1827 case TRANSMISSION_MODE_4K:
1828 fft_div = 2;
1829 break;
1830 default:
1831 case TRANSMISSION_MODE_8K:
1832 fft_div = 1;
1833 break;
1834 }
1835
1836 switch (c->modulation) {
1837 case DQPSK:
1838 case QPSK:
1839 bits_per_symbol = 2;
1840 break;
1841 case QAM_16:
1842 bits_per_symbol = 4;
1843 break;
1844 default:
1845 case QAM_64:
1846 bits_per_symbol = 6;
1847 break;
1848 }
1849
1850 switch ((c->hierarchy == 0 || 1 == 1) ? c->code_rate_HP : c->code_rate_LP) {
1851 case FEC_1_2:
1852 rate_num = 1;
1853 rate_denum = 2;
1854 break;
1855 case FEC_2_3:
1856 rate_num = 2;
1857 rate_denum = 3;
1858 break;
1859 case FEC_3_4:
1860 rate_num = 3;
1861 rate_denum = 4;
1862 break;
1863 case FEC_5_6:
1864 rate_num = 5;
1865 rate_denum = 6;
1866 break;
1867 default:
1868 case FEC_7_8:
1869 rate_num = 7;
1870 rate_denum = 8;
1871 break;
1872 }
1873
Mauro Carvalho Chehab041ad442014-05-29 14:44:56 -03001874 denom = bits_per_symbol * rate_num * fft_div * 384;
1875
Sean Youngd95947c2018-12-04 04:59:10 -05001876 /*
1877 * FIXME: check if the math makes sense. If so, fill the
1878 * interleaving var.
1879 */
1880
Mauro Carvalho Chehab041ad442014-05-29 14:44:56 -03001881 /* If calculus gets wrong, wait for 1s for the next stats */
1882 if (!denom)
1883 return 0;
1884
1885 /* Estimate the period for the total bit rate */
1886 time_us = rate_denum * (1008 * 1562500L);
1887 tmp64 = time_us;
1888 do_div(tmp64, guard);
1889 time_us = time_us + tmp64;
1890 time_us += denom / 2;
1891 do_div(time_us, denom);
1892
1893 tmp = 1008 * 96 * interleaving;
1894 time_us += tmp + tmp / guard;
1895
1896 return time_us;
1897}
1898
Mauro Carvalho Chehab0df289a2015-06-07 14:53:52 -03001899static int dib7000p_get_stats(struct dvb_frontend *demod, enum fe_status stat)
Mauro Carvalho Chehab041ad442014-05-29 14:44:56 -03001900{
1901 struct dib7000p_state *state = demod->demodulator_priv;
1902 struct dtv_frontend_properties *c = &demod->dtv_property_cache;
Mauro Carvalho Chehab041ad442014-05-29 14:44:56 -03001903 int show_per_stats = 0;
1904 u32 time_us = 0, val, snr;
1905 u64 blocks, ucb;
1906 s32 db;
1907 u16 strength;
1908
1909 /* Get Signal strength */
1910 dib7000p_read_signal_strength(demod, &strength);
1911 val = strength;
1912 db = interpolate_value(val,
1913 strength_to_db_table,
1914 ARRAY_SIZE(strength_to_db_table)) - DB_OFFSET;
1915 c->strength.stat[0].svalue = db;
1916
Mauro Carvalho Chehab041ad442014-05-29 14:44:56 -03001917 /* UCB/BER/CNR measures require lock */
1918 if (!(stat & FE_HAS_LOCK)) {
1919 c->cnr.len = 1;
1920 c->block_count.len = 1;
1921 c->block_error.len = 1;
1922 c->post_bit_error.len = 1;
1923 c->post_bit_count.len = 1;
1924 c->cnr.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
1925 c->post_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
1926 c->post_bit_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
1927 c->block_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
1928 c->block_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
1929 return 0;
1930 }
1931
1932 /* Check if time for stats was elapsed */
1933 if (time_after(jiffies, state->per_jiffies_stats)) {
1934 state->per_jiffies_stats = jiffies + msecs_to_jiffies(1000);
1935
1936 /* Get SNR */
1937 snr = dib7000p_get_snr(demod);
1938 if (snr)
1939 snr = (1000L * snr) >> 24;
1940 else
1941 snr = 0;
1942 c->cnr.stat[0].svalue = snr;
1943 c->cnr.stat[0].scale = FE_SCALE_DECIBEL;
1944
1945 /* Get UCB measures */
1946 dib7000p_read_unc_blocks(demod, &val);
1947 ucb = val - state->old_ucb;
1948 if (val < state->old_ucb)
1949 ucb += 0x100000000LL;
1950
1951 c->block_error.stat[0].scale = FE_SCALE_COUNTER;
1952 c->block_error.stat[0].uvalue = ucb;
1953
1954 /* Estimate the number of packets based on bitrate */
1955 if (!time_us)
Mauro Carvalho Chehab986f1682014-10-09 10:29:35 -03001956 time_us = dib7000p_get_time_us(demod);
Mauro Carvalho Chehab041ad442014-05-29 14:44:56 -03001957
1958 if (time_us) {
1959 blocks = 1250000ULL * 1000000ULL;
1960 do_div(blocks, time_us * 8 * 204);
1961 c->block_count.stat[0].scale = FE_SCALE_COUNTER;
1962 c->block_count.stat[0].uvalue += blocks;
1963 }
1964
1965 show_per_stats = 1;
1966 }
1967
1968 /* Get post-BER measures */
1969 if (time_after(jiffies, state->ber_jiffies_stats)) {
Mauro Carvalho Chehab986f1682014-10-09 10:29:35 -03001970 time_us = dib7000p_get_time_us(demod);
Mauro Carvalho Chehab041ad442014-05-29 14:44:56 -03001971 state->ber_jiffies_stats = jiffies + msecs_to_jiffies((time_us + 500) / 1000);
1972
Mauro Carvalho Chehab5a0e2a42016-10-14 09:35:33 -03001973 dprintk("Next all layers stats available in %u us.\n", time_us);
Mauro Carvalho Chehab041ad442014-05-29 14:44:56 -03001974
1975 dib7000p_read_ber(demod, &val);
1976 c->post_bit_error.stat[0].scale = FE_SCALE_COUNTER;
1977 c->post_bit_error.stat[0].uvalue += val;
1978
1979 c->post_bit_count.stat[0].scale = FE_SCALE_COUNTER;
1980 c->post_bit_count.stat[0].uvalue += 100000000;
1981 }
1982
1983 /* Get PER measures */
1984 if (show_per_stats) {
1985 dib7000p_read_unc_blocks(demod, &val);
1986
1987 c->block_error.stat[0].scale = FE_SCALE_COUNTER;
1988 c->block_error.stat[0].uvalue += val;
1989
Mauro Carvalho Chehab986f1682014-10-09 10:29:35 -03001990 time_us = dib7000p_get_time_us(demod);
Mauro Carvalho Chehab041ad442014-05-29 14:44:56 -03001991 if (time_us) {
1992 blocks = 1250000ULL * 1000000ULL;
1993 do_div(blocks, time_us * 8 * 204);
1994 c->block_count.stat[0].scale = FE_SCALE_COUNTER;
1995 c->block_count.stat[0].uvalue += blocks;
1996 }
1997 }
1998 return 0;
1999}
2000
Olivier Grenie713d54a2011-01-04 04:54:31 -03002001static int dib7000p_fe_get_tune_settings(struct dvb_frontend *fe, struct dvb_frontend_tune_settings *tune)
Patrick Boettchera75763f2006-10-18 08:34:16 -03002002{
2003 tune->min_delay_ms = 1000;
2004 return 0;
2005}
2006
2007static void dib7000p_release(struct dvb_frontend *demod)
2008{
2009 struct dib7000p_state *st = demod->demodulator_priv;
2010 dibx000_exit_i2c_master(&st->i2c_master);
Olivier Grenie713d54a2011-01-04 04:54:31 -03002011 i2c_del_adapter(&st->dib7090_tuner_adap);
Patrick Boettchera75763f2006-10-18 08:34:16 -03002012 kfree(st);
2013}
2014
Mauro Carvalho Chehab8abe4a02014-05-29 09:20:15 -03002015static int dib7000pc_detection(struct i2c_adapter *i2c_adap)
Patrick Boettchera75763f2006-10-18 08:34:16 -03002016{
Olivier Grenie5a0deee2011-05-03 12:27:33 -03002017 u8 *tx, *rx;
Patrick Boettchera75763f2006-10-18 08:34:16 -03002018 struct i2c_msg msg[2] = {
Olivier Grenie5a0deee2011-05-03 12:27:33 -03002019 {.addr = 18 >> 1, .flags = 0, .len = 2},
2020 {.addr = 18 >> 1, .flags = I2C_M_RD, .len = 2},
Patrick Boettchera75763f2006-10-18 08:34:16 -03002021 };
Olivier Grenie5a0deee2011-05-03 12:27:33 -03002022 int ret = 0;
2023
Kees Cook6396bb22018-06-12 14:03:40 -07002024 tx = kzalloc(2, GFP_KERNEL);
Olivier Grenie5a0deee2011-05-03 12:27:33 -03002025 if (!tx)
2026 return -ENOMEM;
Kees Cook6396bb22018-06-12 14:03:40 -07002027 rx = kzalloc(2, GFP_KERNEL);
Olivier Grenie5a0deee2011-05-03 12:27:33 -03002028 if (!rx) {
Olivier Grenie5a0deee2011-05-03 12:27:33 -03002029 ret = -ENOMEM;
Dan Carpenter0c61cc3b2011-08-06 05:00:34 -03002030 goto rx_memory_error;
Olivier Grenie5a0deee2011-05-03 12:27:33 -03002031 }
2032
2033 msg[0].buf = tx;
2034 msg[1].buf = rx;
Patrick Boettchera75763f2006-10-18 08:34:16 -03002035
2036 tx[0] = 0x03;
2037 tx[1] = 0x00;
2038
2039 if (i2c_transfer(i2c_adap, msg, 2) == 2)
2040 if (rx[0] == 0x01 && rx[1] == 0xb3) {
Mauro Carvalho Chehab5a0e2a42016-10-14 09:35:33 -03002041 dprintk("-D- DiB7000PC detected\n");
Patrick Boettchera75763f2006-10-18 08:34:16 -03002042 return 1;
2043 }
2044
2045 msg[0].addr = msg[1].addr = 0x40;
2046
2047 if (i2c_transfer(i2c_adap, msg, 2) == 2)
2048 if (rx[0] == 0x01 && rx[1] == 0xb3) {
Mauro Carvalho Chehab5a0e2a42016-10-14 09:35:33 -03002049 dprintk("-D- DiB7000PC detected\n");
Patrick Boettchera75763f2006-10-18 08:34:16 -03002050 return 1;
2051 }
2052
Mauro Carvalho Chehab5a0e2a42016-10-14 09:35:33 -03002053 dprintk("-D- DiB7000PC not detected\n");
Olivier Grenie5a0deee2011-05-03 12:27:33 -03002054
2055 kfree(rx);
2056rx_memory_error:
2057 kfree(tx);
2058 return ret;
Patrick Boettchera75763f2006-10-18 08:34:16 -03002059}
Patrick Boettchera75763f2006-10-18 08:34:16 -03002060
Mauro Carvalho Chehab8abe4a02014-05-29 09:20:15 -03002061static struct i2c_adapter *dib7000p_get_i2c_master(struct dvb_frontend *demod, enum dibx000_i2c_interface intf, int gating)
Patrick Boettchera75763f2006-10-18 08:34:16 -03002062{
2063 struct dib7000p_state *st = demod->demodulator_priv;
2064 return dibx000_get_i2c_adapter(&st->i2c_master, intf, gating);
2065}
Patrick Boettchera75763f2006-10-18 08:34:16 -03002066
Mauro Carvalho Chehab8abe4a02014-05-29 09:20:15 -03002067static int dib7000p_pid_filter_ctrl(struct dvb_frontend *fe, u8 onoff)
Olivier Grenief8731f42009-09-18 04:08:43 -03002068{
Olivier Grenie713d54a2011-01-04 04:54:31 -03002069 struct dib7000p_state *state = fe->demodulator_priv;
2070 u16 val = dib7000p_read_word(state, 235) & 0xffef;
2071 val |= (onoff & 0x1) << 4;
Mauro Carvalho Chehab5a0e2a42016-10-14 09:35:33 -03002072 dprintk("PID filter enabled %d\n", onoff);
Olivier Grenie713d54a2011-01-04 04:54:31 -03002073 return dib7000p_write_word(state, 235, val);
Olivier Grenief8731f42009-09-18 04:08:43 -03002074}
Olivier Grenief8731f42009-09-18 04:08:43 -03002075
Mauro Carvalho Chehab8abe4a02014-05-29 09:20:15 -03002076static int dib7000p_pid_filter(struct dvb_frontend *fe, u8 id, u16 pid, u8 onoff)
Olivier Grenief8731f42009-09-18 04:08:43 -03002077{
Olivier Grenie713d54a2011-01-04 04:54:31 -03002078 struct dib7000p_state *state = fe->demodulator_priv;
Mauro Carvalho Chehab5a0e2a42016-10-14 09:35:33 -03002079 dprintk("PID filter: index %x, PID %d, OnOff %d\n", id, pid, onoff);
Olivier Grenie713d54a2011-01-04 04:54:31 -03002080 return dib7000p_write_word(state, 241 + id, onoff ? (1 << 13) | pid : 0);
Olivier Grenief8731f42009-09-18 04:08:43 -03002081}
Olivier Grenief8731f42009-09-18 04:08:43 -03002082
Mauro Carvalho Chehab8abe4a02014-05-29 09:20:15 -03002083static int dib7000p_i2c_enumeration(struct i2c_adapter *i2c, int no_of_demods, u8 default_addr, struct dib7000p_config cfg[])
Patrick Boettchera75763f2006-10-18 08:34:16 -03002084{
Randy Dunlap30d81bb2010-02-08 20:30:44 -03002085 struct dib7000p_state *dpst;
Patrick Boettchera75763f2006-10-18 08:34:16 -03002086 int k = 0;
2087 u8 new_addr = 0;
2088
Randy Dunlap30d81bb2010-02-08 20:30:44 -03002089 dpst = kzalloc(sizeof(struct dib7000p_state), GFP_KERNEL);
2090 if (!dpst)
Andrew Morton0b427602010-04-27 19:09:45 -03002091 return -ENOMEM;
Randy Dunlap30d81bb2010-02-08 20:30:44 -03002092
2093 dpst->i2c_adap = i2c;
Patrick Boettcher79fcce32011-08-03 12:08:21 -03002094 mutex_init(&dpst->i2c_buffer_lock);
Randy Dunlap30d81bb2010-02-08 20:30:44 -03002095
Olivier Grenie713d54a2011-01-04 04:54:31 -03002096 for (k = no_of_demods - 1; k >= 0; k--) {
Randy Dunlap30d81bb2010-02-08 20:30:44 -03002097 dpst->cfg = cfg[k];
Patrick Boettchera75763f2006-10-18 08:34:16 -03002098
2099 /* designated i2c address */
Olivier Grenie713d54a2011-01-04 04:54:31 -03002100 if (cfg[k].default_i2c_addr != 0)
2101 new_addr = cfg[k].default_i2c_addr + (k << 1);
2102 else
2103 new_addr = (0x40 + k) << 1;
Randy Dunlap30d81bb2010-02-08 20:30:44 -03002104 dpst->i2c_addr = new_addr;
Olivier Grenie713d54a2011-01-04 04:54:31 -03002105 dib7000p_write_word(dpst, 1287, 0x0003); /* sram lead in, rdy */
Randy Dunlap30d81bb2010-02-08 20:30:44 -03002106 if (dib7000p_identify(dpst) != 0) {
2107 dpst->i2c_addr = default_addr;
Olivier Grenie713d54a2011-01-04 04:54:31 -03002108 dib7000p_write_word(dpst, 1287, 0x0003); /* sram lead in, rdy */
Randy Dunlap30d81bb2010-02-08 20:30:44 -03002109 if (dib7000p_identify(dpst) != 0) {
Patrick Boettchera75763f2006-10-18 08:34:16 -03002110 dprintk("DiB7000P #%d: not identified\n", k);
Randy Dunlap30d81bb2010-02-08 20:30:44 -03002111 kfree(dpst);
Patrick Boettchera75763f2006-10-18 08:34:16 -03002112 return -EIO;
2113 }
2114 }
2115
2116 /* start diversity to pull_down div_str - just for i2c-enumeration */
Randy Dunlap30d81bb2010-02-08 20:30:44 -03002117 dib7000p_set_output_mode(dpst, OUTMODE_DIVERSITY);
Patrick Boettchera75763f2006-10-18 08:34:16 -03002118
2119 /* set new i2c address and force divstart */
Randy Dunlap30d81bb2010-02-08 20:30:44 -03002120 dib7000p_write_word(dpst, 1285, (new_addr << 2) | 0x2);
Patrick Boettchera75763f2006-10-18 08:34:16 -03002121
Mauro Carvalho Chehab5a0e2a42016-10-14 09:35:33 -03002122 dprintk("IC %d initialized (to i2c_address 0x%x)\n", k, new_addr);
Patrick Boettchera75763f2006-10-18 08:34:16 -03002123 }
2124
2125 for (k = 0; k < no_of_demods; k++) {
Randy Dunlap30d81bb2010-02-08 20:30:44 -03002126 dpst->cfg = cfg[k];
Olivier Grenie713d54a2011-01-04 04:54:31 -03002127 if (cfg[k].default_i2c_addr != 0)
2128 dpst->i2c_addr = (cfg[k].default_i2c_addr + k) << 1;
2129 else
2130 dpst->i2c_addr = (0x40 + k) << 1;
Patrick Boettchera75763f2006-10-18 08:34:16 -03002131
2132 // unforce divstr
Randy Dunlap30d81bb2010-02-08 20:30:44 -03002133 dib7000p_write_word(dpst, 1285, dpst->i2c_addr << 2);
Patrick Boettchera75763f2006-10-18 08:34:16 -03002134
2135 /* deactivate div - it was just for i2c-enumeration */
Randy Dunlap30d81bb2010-02-08 20:30:44 -03002136 dib7000p_set_output_mode(dpst, OUTMODE_HIGH_Z);
Patrick Boettchera75763f2006-10-18 08:34:16 -03002137 }
2138
Randy Dunlap30d81bb2010-02-08 20:30:44 -03002139 kfree(dpst);
Patrick Boettchera75763f2006-10-18 08:34:16 -03002140 return 0;
2141}
Patrick Boettchera75763f2006-10-18 08:34:16 -03002142
Olivier Grenie713d54a2011-01-04 04:54:31 -03002143static const s32 lut_1000ln_mant[] = {
2144 6908, 6956, 7003, 7047, 7090, 7131, 7170, 7208, 7244, 7279, 7313, 7346, 7377, 7408, 7438, 7467, 7495, 7523, 7549, 7575, 7600
2145};
2146
2147static s32 dib7000p_get_adc_power(struct dvb_frontend *fe)
2148{
2149 struct dib7000p_state *state = fe->demodulator_priv;
2150 u32 tmp_val = 0, exp = 0, mant = 0;
2151 s32 pow_i;
2152 u16 buf[2];
2153 u8 ix = 0;
2154
2155 buf[0] = dib7000p_read_word(state, 0x184);
2156 buf[1] = dib7000p_read_word(state, 0x185);
2157 pow_i = (buf[0] << 16) | buf[1];
Mauro Carvalho Chehab5a0e2a42016-10-14 09:35:33 -03002158 dprintk("raw pow_i = %d\n", pow_i);
Olivier Grenie713d54a2011-01-04 04:54:31 -03002159
2160 tmp_val = pow_i;
2161 while (tmp_val >>= 1)
2162 exp++;
2163
2164 mant = (pow_i * 1000 / (1 << exp));
Mauro Carvalho Chehab5a0e2a42016-10-14 09:35:33 -03002165 dprintk(" mant = %d exp = %d\n", mant / 1000, exp);
Olivier Grenie713d54a2011-01-04 04:54:31 -03002166
2167 ix = (u8) ((mant - 1000) / 100); /* index of the LUT */
Mauro Carvalho Chehab5a0e2a42016-10-14 09:35:33 -03002168 dprintk(" ix = %d\n", ix);
Olivier Grenie713d54a2011-01-04 04:54:31 -03002169
2170 pow_i = (lut_1000ln_mant[ix] + 693 * (exp - 20) - 6908);
2171 pow_i = (pow_i << 8) / 1000;
Mauro Carvalho Chehab5a0e2a42016-10-14 09:35:33 -03002172 dprintk(" pow_i = %d\n", pow_i);
Olivier Grenie713d54a2011-01-04 04:54:31 -03002173
2174 return pow_i;
2175}
2176
2177static int map_addr_to_serpar_number(struct i2c_msg *msg)
2178{
2179 if ((msg->buf[0] <= 15))
2180 msg->buf[0] -= 1;
2181 else if (msg->buf[0] == 17)
2182 msg->buf[0] = 15;
2183 else if (msg->buf[0] == 16)
2184 msg->buf[0] = 17;
2185 else if (msg->buf[0] == 19)
2186 msg->buf[0] = 16;
2187 else if (msg->buf[0] >= 21 && msg->buf[0] <= 25)
2188 msg->buf[0] -= 3;
2189 else if (msg->buf[0] == 28)
2190 msg->buf[0] = 23;
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002191 else
Olivier Grenie713d54a2011-01-04 04:54:31 -03002192 return -EINVAL;
Olivier Grenie713d54a2011-01-04 04:54:31 -03002193 return 0;
2194}
2195
2196static int w7090p_tuner_write_serpar(struct i2c_adapter *i2c_adap, struct i2c_msg msg[], int num)
2197{
2198 struct dib7000p_state *state = i2c_get_adapdata(i2c_adap);
2199 u8 n_overflow = 1;
2200 u16 i = 1000;
2201 u16 serpar_num = msg[0].buf[0];
2202
2203 while (n_overflow == 1 && i) {
2204 n_overflow = (dib7000p_read_word(state, 1984) >> 1) & 0x1;
2205 i--;
2206 if (i == 0)
Mauro Carvalho Chehab5a0e2a42016-10-14 09:35:33 -03002207 dprintk("Tuner ITF: write busy (overflow)\n");
Olivier Grenie713d54a2011-01-04 04:54:31 -03002208 }
2209 dib7000p_write_word(state, 1985, (1 << 6) | (serpar_num & 0x3f));
2210 dib7000p_write_word(state, 1986, (msg[0].buf[1] << 8) | msg[0].buf[2]);
2211
2212 return num;
2213}
2214
2215static int w7090p_tuner_read_serpar(struct i2c_adapter *i2c_adap, struct i2c_msg msg[], int num)
2216{
2217 struct dib7000p_state *state = i2c_get_adapdata(i2c_adap);
2218 u8 n_overflow = 1, n_empty = 1;
2219 u16 i = 1000;
2220 u16 serpar_num = msg[0].buf[0];
2221 u16 read_word;
2222
2223 while (n_overflow == 1 && i) {
2224 n_overflow = (dib7000p_read_word(state, 1984) >> 1) & 0x1;
2225 i--;
2226 if (i == 0)
Mauro Carvalho Chehab5a0e2a42016-10-14 09:35:33 -03002227 dprintk("TunerITF: read busy (overflow)\n");
Olivier Grenie713d54a2011-01-04 04:54:31 -03002228 }
2229 dib7000p_write_word(state, 1985, (0 << 6) | (serpar_num & 0x3f));
2230
2231 i = 1000;
2232 while (n_empty == 1 && i) {
2233 n_empty = dib7000p_read_word(state, 1984) & 0x1;
2234 i--;
2235 if (i == 0)
Mauro Carvalho Chehab5a0e2a42016-10-14 09:35:33 -03002236 dprintk("TunerITF: read busy (empty)\n");
Olivier Grenie713d54a2011-01-04 04:54:31 -03002237 }
2238 read_word = dib7000p_read_word(state, 1987);
2239 msg[1].buf[0] = (read_word >> 8) & 0xff;
2240 msg[1].buf[1] = (read_word) & 0xff;
2241
2242 return num;
2243}
2244
2245static int w7090p_tuner_rw_serpar(struct i2c_adapter *i2c_adap, struct i2c_msg msg[], int num)
2246{
2247 if (map_addr_to_serpar_number(&msg[0]) == 0) { /* else = Tuner regs to ignore : DIG_CFG, CTRL_RF_LT, PLL_CFG, PWM1_REG, ADCCLK, DIG_CFG_3; SLEEP_EN... */
2248 if (num == 1) { /* write */
2249 return w7090p_tuner_write_serpar(i2c_adap, msg, 1);
2250 } else { /* read */
2251 return w7090p_tuner_read_serpar(i2c_adap, msg, 2);
2252 }
2253 }
2254 return num;
2255}
2256
Olivier Greniea685dbb2011-08-05 14:10:40 -03002257static int dib7090p_rw_on_apb(struct i2c_adapter *i2c_adap,
2258 struct i2c_msg msg[], int num, u16 apb_address)
Olivier Grenie713d54a2011-01-04 04:54:31 -03002259{
2260 struct dib7000p_state *state = i2c_get_adapdata(i2c_adap);
2261 u16 word;
2262
2263 if (num == 1) { /* write */
2264 dib7000p_write_word(state, apb_address, ((msg[0].buf[1] << 8) | (msg[0].buf[2])));
2265 } else {
2266 word = dib7000p_read_word(state, apb_address);
2267 msg[1].buf[0] = (word >> 8) & 0xff;
2268 msg[1].buf[1] = (word) & 0xff;
2269 }
2270
2271 return num;
2272}
2273
2274static int dib7090_tuner_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg msg[], int num)
2275{
2276 struct dib7000p_state *state = i2c_get_adapdata(i2c_adap);
2277
2278 u16 apb_address = 0, word;
2279 int i = 0;
2280 switch (msg[0].buf[0]) {
2281 case 0x12:
2282 apb_address = 1920;
2283 break;
2284 case 0x14:
2285 apb_address = 1921;
2286 break;
2287 case 0x24:
2288 apb_address = 1922;
2289 break;
2290 case 0x1a:
2291 apb_address = 1923;
2292 break;
2293 case 0x22:
2294 apb_address = 1924;
2295 break;
2296 case 0x33:
2297 apb_address = 1926;
2298 break;
2299 case 0x34:
2300 apb_address = 1927;
2301 break;
2302 case 0x35:
2303 apb_address = 1928;
2304 break;
2305 case 0x36:
2306 apb_address = 1929;
2307 break;
2308 case 0x37:
2309 apb_address = 1930;
2310 break;
2311 case 0x38:
2312 apb_address = 1931;
2313 break;
2314 case 0x39:
2315 apb_address = 1932;
2316 break;
2317 case 0x2a:
2318 apb_address = 1935;
2319 break;
2320 case 0x2b:
2321 apb_address = 1936;
2322 break;
2323 case 0x2c:
2324 apb_address = 1937;
2325 break;
2326 case 0x2d:
2327 apb_address = 1938;
2328 break;
2329 case 0x2e:
2330 apb_address = 1939;
2331 break;
2332 case 0x2f:
2333 apb_address = 1940;
2334 break;
2335 case 0x30:
2336 apb_address = 1941;
2337 break;
2338 case 0x31:
2339 apb_address = 1942;
2340 break;
2341 case 0x32:
2342 apb_address = 1943;
2343 break;
2344 case 0x3e:
2345 apb_address = 1944;
2346 break;
2347 case 0x3f:
2348 apb_address = 1945;
2349 break;
2350 case 0x40:
2351 apb_address = 1948;
2352 break;
2353 case 0x25:
2354 apb_address = 914;
2355 break;
2356 case 0x26:
2357 apb_address = 915;
2358 break;
2359 case 0x27:
Olivier Grenie2e802862011-08-05 10:39:15 -03002360 apb_address = 917;
Olivier Grenie713d54a2011-01-04 04:54:31 -03002361 break;
2362 case 0x28:
Olivier Grenie2e802862011-08-05 10:39:15 -03002363 apb_address = 916;
Olivier Grenie713d54a2011-01-04 04:54:31 -03002364 break;
2365 case 0x1d:
2366 i = ((dib7000p_read_word(state, 72) >> 12) & 0x3);
2367 word = dib7000p_read_word(state, 384 + i);
2368 msg[1].buf[0] = (word >> 8) & 0xff;
2369 msg[1].buf[1] = (word) & 0xff;
2370 return num;
2371 case 0x1f:
2372 if (num == 1) { /* write */
2373 word = (u16) ((msg[0].buf[1] << 8) | msg[0].buf[2]);
2374 word &= 0x3;
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002375 word = (dib7000p_read_word(state, 72) & ~(3 << 12)) | (word << 12);
Olivier Grenie713d54a2011-01-04 04:54:31 -03002376 dib7000p_write_word(state, 72, word); /* Set the proper input */
2377 return num;
2378 }
2379 }
2380
Mauro Carvalho Chehab868c9a12019-02-18 14:28:55 -05002381 if (apb_address != 0) /* R/W access via APB */
Olivier Grenie713d54a2011-01-04 04:54:31 -03002382 return dib7090p_rw_on_apb(i2c_adap, msg, num, apb_address);
2383 else /* R/W access via SERPAR */
2384 return w7090p_tuner_rw_serpar(i2c_adap, msg, num);
2385
2386 return 0;
2387}
2388
2389static u32 dib7000p_i2c_func(struct i2c_adapter *adapter)
2390{
2391 return I2C_FUNC_I2C;
2392}
2393
Gustavo A. R. Silvaa76f0942017-07-09 18:18:15 -04002394static const struct i2c_algorithm dib7090_tuner_xfer_algo = {
Olivier Grenie713d54a2011-01-04 04:54:31 -03002395 .master_xfer = dib7090_tuner_xfer,
2396 .functionality = dib7000p_i2c_func,
2397};
2398
Mauro Carvalho Chehab8abe4a02014-05-29 09:20:15 -03002399static struct i2c_adapter *dib7090_get_i2c_tuner(struct dvb_frontend *fe)
Olivier Grenie713d54a2011-01-04 04:54:31 -03002400{
2401 struct dib7000p_state *st = fe->demodulator_priv;
2402 return &st->dib7090_tuner_adap;
2403}
Olivier Grenie713d54a2011-01-04 04:54:31 -03002404
2405static int dib7090_host_bus_drive(struct dib7000p_state *state, u8 drive)
2406{
2407 u16 reg;
2408
2409 /* drive host bus 2, 3, 4 */
2410 reg = dib7000p_read_word(state, 1798) & ~((0x7) | (0x7 << 6) | (0x7 << 12));
2411 reg |= (drive << 12) | (drive << 6) | drive;
2412 dib7000p_write_word(state, 1798, reg);
2413
2414 /* drive host bus 5,6 */
2415 reg = dib7000p_read_word(state, 1799) & ~((0x7 << 2) | (0x7 << 8));
2416 reg |= (drive << 8) | (drive << 2);
2417 dib7000p_write_word(state, 1799, reg);
2418
2419 /* drive host bus 7, 8, 9 */
2420 reg = dib7000p_read_word(state, 1800) & ~((0x7) | (0x7 << 6) | (0x7 << 12));
2421 reg |= (drive << 12) | (drive << 6) | drive;
2422 dib7000p_write_word(state, 1800, reg);
2423
2424 /* drive host bus 10, 11 */
2425 reg = dib7000p_read_word(state, 1801) & ~((0x7 << 2) | (0x7 << 8));
2426 reg |= (drive << 8) | (drive << 2);
2427 dib7000p_write_word(state, 1801, reg);
2428
2429 /* drive host bus 12, 13, 14 */
2430 reg = dib7000p_read_word(state, 1802) & ~((0x7) | (0x7 << 6) | (0x7 << 12));
2431 reg |= (drive << 12) | (drive << 6) | drive;
2432 dib7000p_write_word(state, 1802, reg);
2433
2434 return 0;
2435}
2436
2437static u32 dib7090_calcSyncFreq(u32 P_Kin, u32 P_Kout, u32 insertExtSynchro, u32 syncSize)
2438{
2439 u32 quantif = 3;
2440 u32 nom = (insertExtSynchro * P_Kin + syncSize);
2441 u32 denom = P_Kout;
2442 u32 syncFreq = ((nom << quantif) / denom);
2443
2444 if ((syncFreq & ((1 << quantif) - 1)) != 0)
2445 syncFreq = (syncFreq >> quantif) + 1;
2446 else
2447 syncFreq = (syncFreq >> quantif);
2448
2449 if (syncFreq != 0)
2450 syncFreq = syncFreq - 1;
2451
2452 return syncFreq;
2453}
2454
2455static int dib7090_cfg_DibTx(struct dib7000p_state *state, u32 P_Kin, u32 P_Kout, u32 insertExtSynchro, u32 synchroMode, u32 syncWord, u32 syncSize)
2456{
Mauro Carvalho Chehab5a0e2a42016-10-14 09:35:33 -03002457 dprintk("Configure DibStream Tx\n");
Olivier Grenie713d54a2011-01-04 04:54:31 -03002458
2459 dib7000p_write_word(state, 1615, 1);
2460 dib7000p_write_word(state, 1603, P_Kin);
2461 dib7000p_write_word(state, 1605, P_Kout);
2462 dib7000p_write_word(state, 1606, insertExtSynchro);
2463 dib7000p_write_word(state, 1608, synchroMode);
2464 dib7000p_write_word(state, 1609, (syncWord >> 16) & 0xffff);
2465 dib7000p_write_word(state, 1610, syncWord & 0xffff);
2466 dib7000p_write_word(state, 1612, syncSize);
2467 dib7000p_write_word(state, 1615, 0);
2468
Olivier Grenie713d54a2011-01-04 04:54:31 -03002469 return 0;
2470}
2471
2472static int dib7090_cfg_DibRx(struct dib7000p_state *state, u32 P_Kin, u32 P_Kout, u32 synchroMode, u32 insertExtSynchro, u32 syncWord, u32 syncSize,
2473 u32 dataOutRate)
2474{
2475 u32 syncFreq;
2476
Mauro Carvalho Chehab5a0e2a42016-10-14 09:35:33 -03002477 dprintk("Configure DibStream Rx\n");
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002478 if ((P_Kin != 0) && (P_Kout != 0)) {
Olivier Grenie713d54a2011-01-04 04:54:31 -03002479 syncFreq = dib7090_calcSyncFreq(P_Kin, P_Kout, insertExtSynchro, syncSize);
2480 dib7000p_write_word(state, 1542, syncFreq);
2481 }
2482 dib7000p_write_word(state, 1554, 1);
2483 dib7000p_write_word(state, 1536, P_Kin);
2484 dib7000p_write_word(state, 1537, P_Kout);
2485 dib7000p_write_word(state, 1539, synchroMode);
2486 dib7000p_write_word(state, 1540, (syncWord >> 16) & 0xffff);
2487 dib7000p_write_word(state, 1541, syncWord & 0xffff);
2488 dib7000p_write_word(state, 1543, syncSize);
2489 dib7000p_write_word(state, 1544, dataOutRate);
2490 dib7000p_write_word(state, 1554, 0);
2491
2492 return 0;
2493}
2494
Olivier Grenie2e802862011-08-05 10:39:15 -03002495static void dib7090_enMpegMux(struct dib7000p_state *state, int onoff)
Olivier Grenie713d54a2011-01-04 04:54:31 -03002496{
Olivier Grenie2e802862011-08-05 10:39:15 -03002497 u16 reg_1287 = dib7000p_read_word(state, 1287);
Olivier Grenie713d54a2011-01-04 04:54:31 -03002498
Olivier Grenie2e802862011-08-05 10:39:15 -03002499 switch (onoff) {
2500 case 1:
2501 reg_1287 &= ~(1<<7);
2502 break;
2503 case 0:
2504 reg_1287 |= (1<<7);
2505 break;
2506 }
Olivier Grenie713d54a2011-01-04 04:54:31 -03002507
Olivier Grenie2e802862011-08-05 10:39:15 -03002508 dib7000p_write_word(state, 1287, reg_1287);
Olivier Grenie713d54a2011-01-04 04:54:31 -03002509}
2510
Olivier Grenie2e802862011-08-05 10:39:15 -03002511static void dib7090_configMpegMux(struct dib7000p_state *state,
2512 u16 pulseWidth, u16 enSerialMode, u16 enSerialClkDiv2)
Olivier Grenie713d54a2011-01-04 04:54:31 -03002513{
Mauro Carvalho Chehab5a0e2a42016-10-14 09:35:33 -03002514 dprintk("Enable Mpeg mux\n");
Olivier Grenie713d54a2011-01-04 04:54:31 -03002515
Olivier Grenie2e802862011-08-05 10:39:15 -03002516 dib7090_enMpegMux(state, 0);
Olivier Grenie713d54a2011-01-04 04:54:31 -03002517
Olivier Grenie2e802862011-08-05 10:39:15 -03002518 /* If the input mode is MPEG do not divide the serial clock */
2519 if ((enSerialMode == 1) && (state->input_mode_mpeg == 1))
2520 enSerialClkDiv2 = 0;
Olivier Grenie713d54a2011-01-04 04:54:31 -03002521
Olivier Grenie2e802862011-08-05 10:39:15 -03002522 dib7000p_write_word(state, 1287, ((pulseWidth & 0x1f) << 2)
2523 | ((enSerialMode & 0x1) << 1)
2524 | (enSerialClkDiv2 & 0x1));
2525
2526 dib7090_enMpegMux(state, 1);
Olivier Grenie713d54a2011-01-04 04:54:31 -03002527}
2528
Olivier Grenie2e802862011-08-05 10:39:15 -03002529static void dib7090_setDibTxMux(struct dib7000p_state *state, int mode)
Olivier Grenie713d54a2011-01-04 04:54:31 -03002530{
Olivier Grenie2e802862011-08-05 10:39:15 -03002531 u16 reg_1288 = dib7000p_read_word(state, 1288) & ~(0x7 << 7);
Olivier Grenie713d54a2011-01-04 04:54:31 -03002532
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002533 switch (mode) {
Olivier Grenie2e802862011-08-05 10:39:15 -03002534 case MPEG_ON_DIBTX:
Mauro Carvalho Chehab5a0e2a42016-10-14 09:35:33 -03002535 dprintk("SET MPEG ON DIBSTREAM TX\n");
Olivier Grenie2e802862011-08-05 10:39:15 -03002536 dib7090_cfg_DibTx(state, 8, 5, 0, 0, 0, 0);
2537 reg_1288 |= (1<<9);
Olivier Grenie713d54a2011-01-04 04:54:31 -03002538 break;
Olivier Grenie2e802862011-08-05 10:39:15 -03002539 case DIV_ON_DIBTX:
Mauro Carvalho Chehab5a0e2a42016-10-14 09:35:33 -03002540 dprintk("SET DIV_OUT ON DIBSTREAM TX\n");
Olivier Grenie2e802862011-08-05 10:39:15 -03002541 dib7090_cfg_DibTx(state, 5, 5, 0, 0, 0, 0);
2542 reg_1288 |= (1<<8);
Olivier Grenie713d54a2011-01-04 04:54:31 -03002543 break;
Olivier Grenie2e802862011-08-05 10:39:15 -03002544 case ADC_ON_DIBTX:
Mauro Carvalho Chehab5a0e2a42016-10-14 09:35:33 -03002545 dprintk("SET ADC_OUT ON DIBSTREAM TX\n");
Olivier Grenie2e802862011-08-05 10:39:15 -03002546 dib7090_cfg_DibTx(state, 20, 5, 10, 0, 0, 0);
2547 reg_1288 |= (1<<7);
2548 break;
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002549 default:
Olivier Grenie713d54a2011-01-04 04:54:31 -03002550 break;
2551 }
Olivier Grenie2e802862011-08-05 10:39:15 -03002552 dib7000p_write_word(state, 1288, reg_1288);
Olivier Grenie713d54a2011-01-04 04:54:31 -03002553}
2554
Olivier Grenie2e802862011-08-05 10:39:15 -03002555static void dib7090_setHostBusMux(struct dib7000p_state *state, int mode)
Olivier Grenie713d54a2011-01-04 04:54:31 -03002556{
Olivier Grenie2e802862011-08-05 10:39:15 -03002557 u16 reg_1288 = dib7000p_read_word(state, 1288) & ~(0x7 << 4);
2558
2559 switch (mode) {
2560 case DEMOUT_ON_HOSTBUS:
Mauro Carvalho Chehab5a0e2a42016-10-14 09:35:33 -03002561 dprintk("SET DEM OUT OLD INTERF ON HOST BUS\n");
Olivier Grenie2e802862011-08-05 10:39:15 -03002562 dib7090_enMpegMux(state, 0);
2563 reg_1288 |= (1<<6);
2564 break;
2565 case DIBTX_ON_HOSTBUS:
Mauro Carvalho Chehab5a0e2a42016-10-14 09:35:33 -03002566 dprintk("SET DIBSTREAM TX ON HOST BUS\n");
Olivier Grenie2e802862011-08-05 10:39:15 -03002567 dib7090_enMpegMux(state, 0);
2568 reg_1288 |= (1<<5);
2569 break;
2570 case MPEG_ON_HOSTBUS:
Mauro Carvalho Chehab5a0e2a42016-10-14 09:35:33 -03002571 dprintk("SET MPEG MUX ON HOST BUS\n");
Olivier Grenie2e802862011-08-05 10:39:15 -03002572 reg_1288 |= (1<<4);
2573 break;
2574 default:
2575 break;
2576 }
2577 dib7000p_write_word(state, 1288, reg_1288);
2578}
2579
Hans Verkuil18ef20d2014-08-20 16:58:35 -03002580static int dib7090_set_diversity_in(struct dvb_frontend *fe, int onoff)
Olivier Grenie2e802862011-08-05 10:39:15 -03002581{
2582 struct dib7000p_state *state = fe->demodulator_priv;
2583 u16 reg_1287;
2584
Olivier Grenie713d54a2011-01-04 04:54:31 -03002585 switch (onoff) {
Olivier Grenie2e802862011-08-05 10:39:15 -03002586 case 0: /* only use the internal way - not the diversity input */
Mauro Carvalho Chehab5a0e2a42016-10-14 09:35:33 -03002587 dprintk("%s mode OFF : by default Enable Mpeg INPUT\n", __func__);
Olivier Grenie2e802862011-08-05 10:39:15 -03002588 dib7090_cfg_DibRx(state, 8, 5, 0, 0, 0, 8, 0);
2589
2590 /* Do not divide the serial clock of MPEG MUX */
2591 /* in SERIAL MODE in case input mode MPEG is used */
2592 reg_1287 = dib7000p_read_word(state, 1287);
2593 /* enSerialClkDiv2 == 1 ? */
2594 if ((reg_1287 & 0x1) == 1) {
2595 /* force enSerialClkDiv2 = 0 */
2596 reg_1287 &= ~0x1;
2597 dib7000p_write_word(state, 1287, reg_1287);
2598 }
2599 state->input_mode_mpeg = 1;
2600 break;
2601 case 1: /* both ways */
2602 case 2: /* only the diversity input */
Mauro Carvalho Chehab5a0e2a42016-10-14 09:35:33 -03002603 dprintk("%s ON : Enable diversity INPUT\n", __func__);
Olivier Grenie2e802862011-08-05 10:39:15 -03002604 dib7090_cfg_DibRx(state, 5, 5, 0, 0, 0, 0, 0);
2605 state->input_mode_mpeg = 0;
2606 break;
Olivier Grenie713d54a2011-01-04 04:54:31 -03002607 }
2608
Olivier Grenie2e802862011-08-05 10:39:15 -03002609 dib7000p_set_diversity_in(&state->demod, onoff);
Olivier Grenie713d54a2011-01-04 04:54:31 -03002610 return 0;
2611}
2612
2613static int dib7090_set_output_mode(struct dvb_frontend *fe, int mode)
2614{
2615 struct dib7000p_state *state = fe->demodulator_priv;
2616
2617 u16 outreg, smo_mode, fifo_threshold;
2618 u8 prefer_mpeg_mux_use = 1;
2619 int ret = 0;
2620
2621 dib7090_host_bus_drive(state, 1);
2622
2623 fifo_threshold = 1792;
2624 smo_mode = (dib7000p_read_word(state, 235) & 0x0050) | (1 << 1);
2625 outreg = dib7000p_read_word(state, 1286) & ~((1 << 10) | (0x7 << 6) | (1 << 1));
2626
2627 switch (mode) {
2628 case OUTMODE_HIGH_Z:
2629 outreg = 0;
2630 break;
2631
2632 case OUTMODE_MPEG2_SERIAL:
2633 if (prefer_mpeg_mux_use) {
Mauro Carvalho Chehab5a0e2a42016-10-14 09:35:33 -03002634 dprintk("setting output mode TS_SERIAL using Mpeg Mux\n");
Olivier Grenie2e802862011-08-05 10:39:15 -03002635 dib7090_configMpegMux(state, 3, 1, 1);
2636 dib7090_setHostBusMux(state, MPEG_ON_HOSTBUS);
2637 } else {/* Use Smooth block */
Mauro Carvalho Chehab5a0e2a42016-10-14 09:35:33 -03002638 dprintk("setting output mode TS_SERIAL using Smooth bloc\n");
Olivier Grenie2e802862011-08-05 10:39:15 -03002639 dib7090_setHostBusMux(state, DEMOUT_ON_HOSTBUS);
2640 outreg |= (2<<6) | (0 << 1);
Olivier Grenie713d54a2011-01-04 04:54:31 -03002641 }
2642 break;
2643
2644 case OUTMODE_MPEG2_PAR_GATED_CLK:
2645 if (prefer_mpeg_mux_use) {
Mauro Carvalho Chehab5a0e2a42016-10-14 09:35:33 -03002646 dprintk("setting output mode TS_PARALLEL_GATED using Mpeg Mux\n");
Olivier Grenie2e802862011-08-05 10:39:15 -03002647 dib7090_configMpegMux(state, 2, 0, 0);
2648 dib7090_setHostBusMux(state, MPEG_ON_HOSTBUS);
2649 } else { /* Use Smooth block */
Mauro Carvalho Chehab5a0e2a42016-10-14 09:35:33 -03002650 dprintk("setting output mode TS_PARALLEL_GATED using Smooth block\n");
Olivier Grenie2e802862011-08-05 10:39:15 -03002651 dib7090_setHostBusMux(state, DEMOUT_ON_HOSTBUS);
2652 outreg |= (0<<6);
Olivier Grenie713d54a2011-01-04 04:54:31 -03002653 }
2654 break;
2655
2656 case OUTMODE_MPEG2_PAR_CONT_CLK: /* Using Smooth block only */
Mauro Carvalho Chehab5a0e2a42016-10-14 09:35:33 -03002657 dprintk("setting output mode TS_PARALLEL_CONT using Smooth block\n");
Olivier Grenie2e802862011-08-05 10:39:15 -03002658 dib7090_setHostBusMux(state, DEMOUT_ON_HOSTBUS);
2659 outreg |= (1<<6);
Olivier Grenie713d54a2011-01-04 04:54:31 -03002660 break;
2661
2662 case OUTMODE_MPEG2_FIFO: /* Using Smooth block because not supported by new Mpeg Mux bloc */
Mauro Carvalho Chehab5a0e2a42016-10-14 09:35:33 -03002663 dprintk("setting output mode TS_FIFO using Smooth block\n");
Olivier Grenie2e802862011-08-05 10:39:15 -03002664 dib7090_setHostBusMux(state, DEMOUT_ON_HOSTBUS);
2665 outreg |= (5<<6);
Olivier Grenie713d54a2011-01-04 04:54:31 -03002666 smo_mode |= (3 << 1);
2667 fifo_threshold = 512;
2668 break;
2669
2670 case OUTMODE_DIVERSITY:
Mauro Carvalho Chehab5a0e2a42016-10-14 09:35:33 -03002671 dprintk("setting output mode MODE_DIVERSITY\n");
Olivier Grenie2e802862011-08-05 10:39:15 -03002672 dib7090_setDibTxMux(state, DIV_ON_DIBTX);
2673 dib7090_setHostBusMux(state, DIBTX_ON_HOSTBUS);
Olivier Grenie713d54a2011-01-04 04:54:31 -03002674 break;
2675
2676 case OUTMODE_ANALOG_ADC:
Mauro Carvalho Chehab5a0e2a42016-10-14 09:35:33 -03002677 dprintk("setting output mode MODE_ANALOG_ADC\n");
Olivier Grenie2e802862011-08-05 10:39:15 -03002678 dib7090_setDibTxMux(state, ADC_ON_DIBTX);
2679 dib7090_setHostBusMux(state, DIBTX_ON_HOSTBUS);
Olivier Grenie713d54a2011-01-04 04:54:31 -03002680 break;
2681 }
Olivier Grenie2e802862011-08-05 10:39:15 -03002682 if (mode != OUTMODE_HIGH_Z)
2683 outreg |= (1 << 10);
Olivier Grenie713d54a2011-01-04 04:54:31 -03002684
2685 if (state->cfg.output_mpeg2_in_188_bytes)
2686 smo_mode |= (1 << 5);
2687
2688 ret |= dib7000p_write_word(state, 235, smo_mode);
2689 ret |= dib7000p_write_word(state, 236, fifo_threshold); /* synchronous fread */
Olivier Grenie2e802862011-08-05 10:39:15 -03002690 ret |= dib7000p_write_word(state, 1286, outreg);
Olivier Grenie713d54a2011-01-04 04:54:31 -03002691
2692 return ret;
2693}
2694
Mauro Carvalho Chehab8abe4a02014-05-29 09:20:15 -03002695static int dib7090_tuner_sleep(struct dvb_frontend *fe, int onoff)
Olivier Grenie713d54a2011-01-04 04:54:31 -03002696{
2697 struct dib7000p_state *state = fe->demodulator_priv;
2698 u16 en_cur_state;
2699
Mauro Carvalho Chehab5a0e2a42016-10-14 09:35:33 -03002700 dprintk("sleep dib7090: %d\n", onoff);
Olivier Grenie713d54a2011-01-04 04:54:31 -03002701
2702 en_cur_state = dib7000p_read_word(state, 1922);
2703
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002704 if (en_cur_state > 0xff)
Olivier Grenie713d54a2011-01-04 04:54:31 -03002705 state->tuner_enable = en_cur_state;
Olivier Grenie713d54a2011-01-04 04:54:31 -03002706
2707 if (onoff)
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002708 en_cur_state &= 0x00ff;
Olivier Grenie713d54a2011-01-04 04:54:31 -03002709 else {
2710 if (state->tuner_enable != 0)
2711 en_cur_state = state->tuner_enable;
2712 }
2713
2714 dib7000p_write_word(state, 1922, en_cur_state);
2715
2716 return 0;
2717}
Olivier Grenie713d54a2011-01-04 04:54:31 -03002718
Mauro Carvalho Chehab8abe4a02014-05-29 09:20:15 -03002719static int dib7090_get_adc_power(struct dvb_frontend *fe)
Olivier Grenie713d54a2011-01-04 04:54:31 -03002720{
2721 return dib7000p_get_adc_power(fe);
2722}
Olivier Grenie713d54a2011-01-04 04:54:31 -03002723
Mauro Carvalho Chehab8abe4a02014-05-29 09:20:15 -03002724static int dib7090_slave_reset(struct dvb_frontend *fe)
Olivier Grenie713d54a2011-01-04 04:54:31 -03002725{
2726 struct dib7000p_state *state = fe->demodulator_priv;
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002727 u16 reg;
Olivier Grenie713d54a2011-01-04 04:54:31 -03002728
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002729 reg = dib7000p_read_word(state, 1794);
2730 dib7000p_write_word(state, 1794, reg | (4 << 12));
Olivier Grenie713d54a2011-01-04 04:54:31 -03002731
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002732 dib7000p_write_word(state, 1032, 0xffff);
2733 return 0;
Olivier Grenie713d54a2011-01-04 04:54:31 -03002734}
Olivier Grenie713d54a2011-01-04 04:54:31 -03002735
Max Kellermannbd336e62016-08-09 18:32:21 -03002736static const struct dvb_frontend_ops dib7000p_ops;
Mauro Carvalho Chehab8abe4a02014-05-29 09:20:15 -03002737static struct dvb_frontend *dib7000p_init(struct i2c_adapter *i2c_adap, u8 i2c_addr, struct dib7000p_config *cfg)
Patrick Boettchera75763f2006-10-18 08:34:16 -03002738{
2739 struct dvb_frontend *demod;
2740 struct dib7000p_state *st;
2741 st = kzalloc(sizeof(struct dib7000p_state), GFP_KERNEL);
2742 if (st == NULL)
2743 return NULL;
2744
2745 memcpy(&st->cfg, cfg, sizeof(struct dib7000p_config));
2746 st->i2c_adap = i2c_adap;
2747 st->i2c_addr = i2c_addr;
2748 st->gpio_val = cfg->gpio_val;
2749 st->gpio_dir = cfg->gpio_dir;
2750
Steven Totha38d6e32008-04-22 15:37:01 -03002751 /* Ensure the output mode remains at the previous default if it's
2752 * not specifically set by the caller.
2753 */
Olivier Grenie713d54a2011-01-04 04:54:31 -03002754 if ((st->cfg.output_mode != OUTMODE_MPEG2_SERIAL) && (st->cfg.output_mode != OUTMODE_MPEG2_PAR_GATED_CLK))
Steven Totha38d6e32008-04-22 15:37:01 -03002755 st->cfg.output_mode = OUTMODE_MPEG2_FIFO;
2756
Olivier Grenie713d54a2011-01-04 04:54:31 -03002757 demod = &st->demod;
Patrick Boettchera75763f2006-10-18 08:34:16 -03002758 demod->demodulator_priv = st;
2759 memcpy(&st->demod.ops, &dib7000p_ops, sizeof(struct dvb_frontend_ops));
Patrick Boettcher79fcce32011-08-03 12:08:21 -03002760 mutex_init(&st->i2c_buffer_lock);
Patrick Boettchera75763f2006-10-18 08:34:16 -03002761
Olivier Grenie713d54a2011-01-04 04:54:31 -03002762 dib7000p_write_word(st, 1287, 0x0003); /* sram lead in, rdy */
Olivier Grenieeac1fe12009-09-23 13:41:27 -03002763
Patrick Boettchera75763f2006-10-18 08:34:16 -03002764 if (dib7000p_identify(st) != 0)
2765 goto error;
2766
Olivier Grenie713d54a2011-01-04 04:54:31 -03002767 st->version = dib7000p_read_word(st, 897);
2768
Martin Samek7646b9d2009-09-30 22:59:09 -03002769 /* FIXME: make sure the dev.parent field is initialized, or else
Patrick Boettcher79fcce32011-08-03 12:08:21 -03002770 request_firmware() will hit an OOPS (this should be moved somewhere
2771 more common) */
2772 st->i2c_master.gated_tuner_i2c_adap.dev.parent = i2c_adap->dev.parent;
Martin Samek7646b9d2009-09-30 22:59:09 -03002773
Patrick Boettchera75763f2006-10-18 08:34:16 -03002774 dibx000_init_i2c_master(&st->i2c_master, DIB7000P, st->i2c_adap, st->i2c_addr);
2775
Olivier Grenie713d54a2011-01-04 04:54:31 -03002776 /* init 7090 tuner adapter */
Mauro Carvalho Chehab85709cb2018-09-10 08:19:16 -04002777 strscpy(st->dib7090_tuner_adap.name, "DiB7090 tuner interface",
2778 sizeof(st->dib7090_tuner_adap.name));
Olivier Grenie713d54a2011-01-04 04:54:31 -03002779 st->dib7090_tuner_adap.algo = &dib7090_tuner_xfer_algo;
2780 st->dib7090_tuner_adap.algo_data = NULL;
2781 st->dib7090_tuner_adap.dev.parent = st->i2c_adap->dev.parent;
2782 i2c_set_adapdata(&st->dib7090_tuner_adap, st);
2783 i2c_add_adapter(&st->dib7090_tuner_adap);
2784
Patrick Boettchera75763f2006-10-18 08:34:16 -03002785 dib7000p_demod_reset(st);
2786
Mauro Carvalho Chehab041ad442014-05-29 14:44:56 -03002787 dib7000p_reset_stats(demod);
2788
Olivier Grenie713d54a2011-01-04 04:54:31 -03002789 if (st->version == SOC7090) {
2790 dib7090_set_output_mode(demod, st->cfg.output_mode);
2791 dib7090_set_diversity_in(demod, 0);
2792 }
2793
Patrick Boettchera75763f2006-10-18 08:34:16 -03002794 return demod;
2795
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002796error:
Patrick Boettchera75763f2006-10-18 08:34:16 -03002797 kfree(st);
2798 return NULL;
2799}
Mauro Carvalho Chehab8abe4a02014-05-29 09:20:15 -03002800
2801void *dib7000p_attach(struct dib7000p_ops *ops)
2802{
2803 if (!ops)
2804 return NULL;
2805
2806 ops->slave_reset = dib7090_slave_reset;
2807 ops->get_adc_power = dib7090_get_adc_power;
2808 ops->dib7000pc_detection = dib7000pc_detection;
2809 ops->get_i2c_tuner = dib7090_get_i2c_tuner;
2810 ops->tuner_sleep = dib7090_tuner_sleep;
2811 ops->init = dib7000p_init;
2812 ops->set_agc1_min = dib7000p_set_agc1_min;
2813 ops->set_gpio = dib7000p_set_gpio;
2814 ops->i2c_enumeration = dib7000p_i2c_enumeration;
2815 ops->pid_filter = dib7000p_pid_filter;
2816 ops->pid_filter_ctrl = dib7000p_pid_filter_ctrl;
2817 ops->get_i2c_master = dib7000p_get_i2c_master;
2818 ops->update_pll = dib7000p_update_pll;
2819 ops->ctrl_timf = dib7000p_ctrl_timf;
2820 ops->get_agc_values = dib7000p_get_agc_values;
2821 ops->set_wbd_ref = dib7000p_set_wbd_ref;
2822
2823 return ops;
2824}
2825EXPORT_SYMBOL(dib7000p_attach);
Patrick Boettchera75763f2006-10-18 08:34:16 -03002826
Max Kellermannbd336e62016-08-09 18:32:21 -03002827static const struct dvb_frontend_ops dib7000p_ops = {
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -03002828 .delsys = { SYS_DVBT },
Patrick Boettchera75763f2006-10-18 08:34:16 -03002829 .info = {
Olivier Grenie713d54a2011-01-04 04:54:31 -03002830 .name = "DiBcom 7000PC",
Mauro Carvalho Chehabf1b1eab2018-07-05 18:59:36 -04002831 .frequency_min_hz = 44250 * kHz,
2832 .frequency_max_hz = 867250 * kHz,
2833 .frequency_stepsize_hz = 62500,
Olivier Grenie713d54a2011-01-04 04:54:31 -03002834 .caps = FE_CAN_INVERSION_AUTO |
2835 FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
2836 FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
2837 FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO |
2838 FE_CAN_TRANSMISSION_MODE_AUTO | FE_CAN_GUARD_INTERVAL_AUTO | FE_CAN_RECOVER | FE_CAN_HIERARCHY_AUTO,
2839 },
Patrick Boettchera75763f2006-10-18 08:34:16 -03002840
Olivier Grenie713d54a2011-01-04 04:54:31 -03002841 .release = dib7000p_release,
Patrick Boettchera75763f2006-10-18 08:34:16 -03002842
Olivier Grenie713d54a2011-01-04 04:54:31 -03002843 .init = dib7000p_wakeup,
2844 .sleep = dib7000p_sleep,
Patrick Boettchera75763f2006-10-18 08:34:16 -03002845
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -03002846 .set_frontend = dib7000p_set_frontend,
Olivier Grenie713d54a2011-01-04 04:54:31 -03002847 .get_tune_settings = dib7000p_fe_get_tune_settings,
Mauro Carvalho Chehabc1f814f2011-12-22 19:06:20 -03002848 .get_frontend = dib7000p_get_frontend,
Patrick Boettchera75763f2006-10-18 08:34:16 -03002849
Olivier Grenie713d54a2011-01-04 04:54:31 -03002850 .read_status = dib7000p_read_status,
2851 .read_ber = dib7000p_read_ber,
Patrick Boettchera75763f2006-10-18 08:34:16 -03002852 .read_signal_strength = dib7000p_read_signal_strength,
Olivier Grenie713d54a2011-01-04 04:54:31 -03002853 .read_snr = dib7000p_read_snr,
2854 .read_ucblocks = dib7000p_read_unc_blocks,
Patrick Boettchera75763f2006-10-18 08:34:16 -03002855};
2856
Patrick Boettcher99e44da2016-01-24 12:56:58 -02002857MODULE_AUTHOR("Olivier Grenie <olivie.grenie@parrot.com>");
2858MODULE_AUTHOR("Patrick Boettcher <patrick.boettcher@posteo.de>");
Patrick Boettchera75763f2006-10-18 08:34:16 -03002859MODULE_DESCRIPTION("Driver for the DiBcom 7000PC COFDM demodulator");
2860MODULE_LICENSE("GPL");