blob: e501ec964df1e2823a8d982e379f743399e1d2bf [file] [log] [blame]
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001/*
2 * Linux-DVB Driver for DiBcom's DiB8000 chip (ISDB-T).
3 *
4 * Copyright (C) 2009 DiBcom (http://www.dibcom.fr/)
5 *
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 Chehab8af16ad2016-10-14 10:05:46 -030010
11#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
12
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -030013#include <linux/kernel.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090014#include <linux/slab.h>
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -030015#include <linux/i2c.h>
Patrick Boettcher79fcce32011-08-03 12:08:21 -030016#include <linux/mutex.h>
Mauro Carvalho Chehabb4600d72013-12-16 20:00:34 -030017#include <asm/div64.h>
Patrick Boettcher79fcce32011-08-03 12:08:21 -030018
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -030019#include "dvb_math.h"
20
21#include "dvb_frontend.h"
22
23#include "dib8000.h"
24
25#define LAYER_ALL -1
26#define LAYER_A 1
27#define LAYER_B 2
28#define LAYER_C 3
29
Olivier Grenie4c70e072011-01-03 15:33:37 -030030#define MAX_NUMBER_OF_FRONTENDS 6
Patrick Boettcher173a64c2013-04-22 12:45:52 -030031/* #define DIB8000_AGC_FREEZE */
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -030032
Patrick Boettcher78f3bc62009-08-17 12:53:51 -030033static int debug;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -030034module_param(debug, int, 0644);
35MODULE_PARM_DESC(debug, "turn on debugging (default: 0)");
36
Mauro Carvalho Chehab8af16ad2016-10-14 10:05:46 -030037#define dprintk(fmt, arg...) do { \
38 if (debug) \
39 printk(KERN_DEBUG pr_fmt("%s: " fmt), \
40 __func__, ##arg); \
41} while (0)
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -030042
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -030043struct i2c_device {
44 struct i2c_adapter *adap;
45 u8 addr;
Olivier Grenie5a0deee2011-05-03 12:27:33 -030046 u8 *i2c_write_buffer;
47 u8 *i2c_read_buffer;
Patrick Boettcher79fcce32011-08-03 12:08:21 -030048 struct mutex *i2c_buffer_lock;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -030049};
50
Patrick Boettcher173a64c2013-04-22 12:45:52 -030051enum param_loop_step {
52 LOOP_TUNE_1,
53 LOOP_TUNE_2
54};
55
56enum dib8000_autosearch_step {
57 AS_START = 0,
58 AS_SEARCHING_FFT,
59 AS_SEARCHING_GUARD,
60 AS_DONE = 100,
61};
62
63enum timeout_mode {
64 SYMBOL_DEPENDENT_OFF = 0,
65 SYMBOL_DEPENDENT_ON,
66};
67
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -030068struct dib8000_state {
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -030069 struct dib8000_config cfg;
70
71 struct i2c_device i2c;
72
73 struct dibx000_i2c_master i2c_master;
74
75 u16 wbd_ref;
76
77 u8 current_band;
78 u32 current_bandwidth;
79 struct dibx000_agc_config *current_agc;
80 u32 timf;
81 u32 timf_default;
82
83 u8 div_force_off:1;
84 u8 div_state:1;
85 u16 div_sync_wait;
86
87 u8 agc_state;
88 u8 differential_constellation;
89 u8 diversity_onoff;
90
91 s16 ber_monitored_layer;
92 u16 gpio_dir;
93 u16 gpio_val;
94
95 u16 revision;
96 u8 isdbt_cfg_loaded;
97 enum frontend_tune_state tune_state;
Patrick Boettcher173a64c2013-04-22 12:45:52 -030098 s32 status;
Olivier Grenie4c70e072011-01-03 15:33:37 -030099
100 struct dvb_frontend *fe[MAX_NUMBER_OF_FRONTENDS];
Olivier Grenie5a0deee2011-05-03 12:27:33 -0300101
102 /* for the I2C transfer */
103 struct i2c_msg msg[2];
104 u8 i2c_write_buffer[4];
105 u8 i2c_read_buffer[2];
Patrick Boettcher79fcce32011-08-03 12:08:21 -0300106 struct mutex i2c_buffer_lock;
Olivier Grenie0c32dbd2011-08-10 05:17:18 -0300107 u8 input_mode_mpeg;
108
109 u16 tuner_enable;
110 struct i2c_adapter dib8096p_tuner_adap;
Patrick Boettcher173a64c2013-04-22 12:45:52 -0300111 u16 current_demod_bw;
112
113 u16 seg_mask;
114 u16 seg_diff_mask;
115 u16 mode;
116 u8 layer_b_nb_seg;
117 u8 layer_c_nb_seg;
118
119 u8 channel_parameters_set;
120 u16 autosearch_state;
121 u16 found_nfft;
122 u16 found_guard;
123 u8 subchannel;
124 u8 symbol_duration;
Mauro Carvalho Chehabd6c62b72014-07-04 14:15:37 -0300125 unsigned long timeout;
Patrick Boettcher173a64c2013-04-22 12:45:52 -0300126 u8 longest_intlv_layer;
127 u16 output_mode;
128
Mauro Carvalho Chehab704f01b2013-12-17 10:08:20 -0300129 /* for DVBv5 stats */
Mauro Carvalho Chehab7a9d85d2013-12-17 04:55:26 -0300130 s64 init_ucb;
Mauro Carvalho Chehab0400c532013-12-17 11:34:22 -0300131 unsigned long per_jiffies_stats;
132 unsigned long ber_jiffies_stats;
133 unsigned long ber_jiffies_stats_layer[3];
Mauro Carvalho Chehab704f01b2013-12-17 10:08:20 -0300134
Patrick Boettcher173a64c2013-04-22 12:45:52 -0300135#ifdef DIB8000_AGC_FREEZE
136 u16 agc1_max;
137 u16 agc1_min;
138 u16 agc2_max;
139 u16 agc2_min;
140#endif
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300141};
142
143enum dib8000_power_mode {
Olivier Grenie0c32dbd2011-08-10 05:17:18 -0300144 DIB8000_POWER_ALL = 0,
145 DIB8000_POWER_INTERFACE_ONLY,
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300146};
147
148static u16 dib8000_i2c_read16(struct i2c_device *i2c, u16 reg)
149{
Patrick Boettcher79fcce32011-08-03 12:08:21 -0300150 u16 ret;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300151 struct i2c_msg msg[2] = {
Patrick Boettcher79fcce32011-08-03 12:08:21 -0300152 {.addr = i2c->addr >> 1, .flags = 0, .len = 2},
153 {.addr = i2c->addr >> 1, .flags = I2C_M_RD, .len = 2},
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300154 };
155
Patrick Boettcher79fcce32011-08-03 12:08:21 -0300156 if (mutex_lock_interruptible(i2c->i2c_buffer_lock) < 0) {
Mauro Carvalho Chehab8af16ad2016-10-14 10:05:46 -0300157 dprintk("could not acquire lock\n");
Patrick Boettcher79fcce32011-08-03 12:08:21 -0300158 return 0;
159 }
160
161 msg[0].buf = i2c->i2c_write_buffer;
Olivier Grenie5a0deee2011-05-03 12:27:33 -0300162 msg[0].buf[0] = reg >> 8;
163 msg[0].buf[1] = reg & 0xff;
Patrick Boettcher79fcce32011-08-03 12:08:21 -0300164 msg[1].buf = i2c->i2c_read_buffer;
Olivier Grenie5a0deee2011-05-03 12:27:33 -0300165
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300166 if (i2c_transfer(i2c->adap, msg, 2) != 2)
Mauro Carvalho Chehab8af16ad2016-10-14 10:05:46 -0300167 dprintk("i2c read error on %d\n", reg);
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300168
Patrick Boettcher79fcce32011-08-03 12:08:21 -0300169 ret = (msg[1].buf[0] << 8) | msg[1].buf[1];
170 mutex_unlock(i2c->i2c_buffer_lock);
171 return ret;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300172}
173
Mauro Carvalho Chehab5ac64ba2013-12-13 10:35:03 -0300174static u16 __dib8000_read_word(struct dib8000_state *state, u16 reg)
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300175{
Patrick Boettcher79fcce32011-08-03 12:08:21 -0300176 u16 ret;
177
Olivier Grenie5a0deee2011-05-03 12:27:33 -0300178 state->i2c_write_buffer[0] = reg >> 8;
179 state->i2c_write_buffer[1] = reg & 0xff;
180
181 memset(state->msg, 0, 2 * sizeof(struct i2c_msg));
182 state->msg[0].addr = state->i2c.addr >> 1;
183 state->msg[0].flags = 0;
184 state->msg[0].buf = state->i2c_write_buffer;
185 state->msg[0].len = 2;
186 state->msg[1].addr = state->i2c.addr >> 1;
187 state->msg[1].flags = I2C_M_RD;
188 state->msg[1].buf = state->i2c_read_buffer;
189 state->msg[1].len = 2;
190
191 if (i2c_transfer(state->i2c.adap, state->msg, 2) != 2)
Mauro Carvalho Chehab8af16ad2016-10-14 10:05:46 -0300192 dprintk("i2c read error on %d\n", reg);
Olivier Grenie5a0deee2011-05-03 12:27:33 -0300193
Patrick Boettcher79fcce32011-08-03 12:08:21 -0300194 ret = (state->i2c_read_buffer[0] << 8) | state->i2c_read_buffer[1];
Mauro Carvalho Chehab5ac64ba2013-12-13 10:35:03 -0300195
196 return ret;
197}
198
199static u16 dib8000_read_word(struct dib8000_state *state, u16 reg)
200{
201 u16 ret;
202
203 if (mutex_lock_interruptible(&state->i2c_buffer_lock) < 0) {
Mauro Carvalho Chehab8af16ad2016-10-14 10:05:46 -0300204 dprintk("could not acquire lock\n");
Mauro Carvalho Chehab5ac64ba2013-12-13 10:35:03 -0300205 return 0;
206 }
207
208 ret = __dib8000_read_word(state, reg);
209
Patrick Boettcher79fcce32011-08-03 12:08:21 -0300210 mutex_unlock(&state->i2c_buffer_lock);
211
212 return ret;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300213}
214
215static u32 dib8000_read32(struct dib8000_state *state, u16 reg)
216{
217 u16 rw[2];
218
Mauro Carvalho Chehab5ac64ba2013-12-13 10:35:03 -0300219 if (mutex_lock_interruptible(&state->i2c_buffer_lock) < 0) {
Mauro Carvalho Chehab8af16ad2016-10-14 10:05:46 -0300220 dprintk("could not acquire lock\n");
Mauro Carvalho Chehab5ac64ba2013-12-13 10:35:03 -0300221 return 0;
222 }
223
224 rw[0] = __dib8000_read_word(state, reg + 0);
225 rw[1] = __dib8000_read_word(state, reg + 1);
226
227 mutex_unlock(&state->i2c_buffer_lock);
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300228
229 return ((rw[0] << 16) | (rw[1]));
230}
231
232static int dib8000_i2c_write16(struct i2c_device *i2c, u16 reg, u16 val)
233{
Patrick Boettcher79fcce32011-08-03 12:08:21 -0300234 struct i2c_msg msg = {.addr = i2c->addr >> 1, .flags = 0, .len = 4};
Olivier Grenie5a0deee2011-05-03 12:27:33 -0300235 int ret = 0;
236
Patrick Boettcher79fcce32011-08-03 12:08:21 -0300237 if (mutex_lock_interruptible(i2c->i2c_buffer_lock) < 0) {
Mauro Carvalho Chehab8af16ad2016-10-14 10:05:46 -0300238 dprintk("could not acquire lock\n");
Patrick Boettcher79fcce32011-08-03 12:08:21 -0300239 return -EINVAL;
240 }
241
242 msg.buf = i2c->i2c_write_buffer;
Olivier Grenie5a0deee2011-05-03 12:27:33 -0300243 msg.buf[0] = (reg >> 8) & 0xff;
244 msg.buf[1] = reg & 0xff;
245 msg.buf[2] = (val >> 8) & 0xff;
246 msg.buf[3] = val & 0xff;
247
248 ret = i2c_transfer(i2c->adap, &msg, 1) != 1 ? -EREMOTEIO : 0;
Patrick Boettcher79fcce32011-08-03 12:08:21 -0300249 mutex_unlock(i2c->i2c_buffer_lock);
Olivier Grenie5a0deee2011-05-03 12:27:33 -0300250
251 return ret;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300252}
253
254static int dib8000_write_word(struct dib8000_state *state, u16 reg, u16 val)
255{
Patrick Boettcher79fcce32011-08-03 12:08:21 -0300256 int ret;
257
258 if (mutex_lock_interruptible(&state->i2c_buffer_lock) < 0) {
Mauro Carvalho Chehab8af16ad2016-10-14 10:05:46 -0300259 dprintk("could not acquire lock\n");
Patrick Boettcher79fcce32011-08-03 12:08:21 -0300260 return -EINVAL;
261 }
262
Olivier Grenie5a0deee2011-05-03 12:27:33 -0300263 state->i2c_write_buffer[0] = (reg >> 8) & 0xff;
264 state->i2c_write_buffer[1] = reg & 0xff;
265 state->i2c_write_buffer[2] = (val >> 8) & 0xff;
266 state->i2c_write_buffer[3] = val & 0xff;
267
268 memset(&state->msg[0], 0, sizeof(struct i2c_msg));
269 state->msg[0].addr = state->i2c.addr >> 1;
270 state->msg[0].flags = 0;
271 state->msg[0].buf = state->i2c_write_buffer;
272 state->msg[0].len = 4;
273
Patrick Boettcher79fcce32011-08-03 12:08:21 -0300274 ret = (i2c_transfer(state->i2c.adap, state->msg, 1) != 1 ?
275 -EREMOTEIO : 0);
276 mutex_unlock(&state->i2c_buffer_lock);
277
278 return ret;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300279}
280
Olivier Grenie4c70e072011-01-03 15:33:37 -0300281static const s16 coeff_2k_sb_1seg_dqpsk[8] = {
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300282 (769 << 5) | 0x0a, (745 << 5) | 0x03, (595 << 5) | 0x0d, (769 << 5) | 0x0a, (920 << 5) | 0x09, (784 << 5) | 0x02, (519 << 5) | 0x0c,
Olivier Grenie4c70e072011-01-03 15:33:37 -0300283 (920 << 5) | 0x09
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300284};
285
Olivier Grenie4c70e072011-01-03 15:33:37 -0300286static const s16 coeff_2k_sb_1seg[8] = {
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300287 (692 << 5) | 0x0b, (683 << 5) | 0x01, (519 << 5) | 0x09, (692 << 5) | 0x0b, 0 | 0x1f, 0 | 0x1f, 0 | 0x1f, 0 | 0x1f
288};
289
Olivier Grenie4c70e072011-01-03 15:33:37 -0300290static const s16 coeff_2k_sb_3seg_0dqpsk_1dqpsk[8] = {
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300291 (832 << 5) | 0x10, (912 << 5) | 0x05, (900 << 5) | 0x12, (832 << 5) | 0x10, (-931 << 5) | 0x0f, (912 << 5) | 0x04, (807 << 5) | 0x11,
Olivier Grenie4c70e072011-01-03 15:33:37 -0300292 (-931 << 5) | 0x0f
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300293};
294
Olivier Grenie4c70e072011-01-03 15:33:37 -0300295static const s16 coeff_2k_sb_3seg_0dqpsk[8] = {
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300296 (622 << 5) | 0x0c, (941 << 5) | 0x04, (796 << 5) | 0x10, (622 << 5) | 0x0c, (982 << 5) | 0x0c, (519 << 5) | 0x02, (572 << 5) | 0x0e,
Olivier Grenie4c70e072011-01-03 15:33:37 -0300297 (982 << 5) | 0x0c
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300298};
299
Olivier Grenie4c70e072011-01-03 15:33:37 -0300300static const s16 coeff_2k_sb_3seg_1dqpsk[8] = {
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300301 (699 << 5) | 0x14, (607 << 5) | 0x04, (944 << 5) | 0x13, (699 << 5) | 0x14, (-720 << 5) | 0x0d, (640 << 5) | 0x03, (866 << 5) | 0x12,
Olivier Grenie4c70e072011-01-03 15:33:37 -0300302 (-720 << 5) | 0x0d
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300303};
304
Olivier Grenie4c70e072011-01-03 15:33:37 -0300305static const s16 coeff_2k_sb_3seg[8] = {
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300306 (664 << 5) | 0x0c, (925 << 5) | 0x03, (937 << 5) | 0x10, (664 << 5) | 0x0c, (-610 << 5) | 0x0a, (697 << 5) | 0x01, (836 << 5) | 0x0e,
Olivier Grenie4c70e072011-01-03 15:33:37 -0300307 (-610 << 5) | 0x0a
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300308};
309
Olivier Grenie4c70e072011-01-03 15:33:37 -0300310static const s16 coeff_4k_sb_1seg_dqpsk[8] = {
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300311 (-955 << 5) | 0x0e, (687 << 5) | 0x04, (818 << 5) | 0x10, (-955 << 5) | 0x0e, (-922 << 5) | 0x0d, (750 << 5) | 0x03, (665 << 5) | 0x0f,
Olivier Grenie4c70e072011-01-03 15:33:37 -0300312 (-922 << 5) | 0x0d
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300313};
314
Olivier Grenie4c70e072011-01-03 15:33:37 -0300315static const s16 coeff_4k_sb_1seg[8] = {
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300316 (638 << 5) | 0x0d, (683 << 5) | 0x02, (638 << 5) | 0x0d, (638 << 5) | 0x0d, (-655 << 5) | 0x0a, (517 << 5) | 0x00, (698 << 5) | 0x0d,
Olivier Grenie4c70e072011-01-03 15:33:37 -0300317 (-655 << 5) | 0x0a
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300318};
319
Olivier Grenie4c70e072011-01-03 15:33:37 -0300320static const s16 coeff_4k_sb_3seg_0dqpsk_1dqpsk[8] = {
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300321 (-707 << 5) | 0x14, (910 << 5) | 0x06, (889 << 5) | 0x16, (-707 << 5) | 0x14, (-958 << 5) | 0x13, (993 << 5) | 0x05, (523 << 5) | 0x14,
Olivier Grenie4c70e072011-01-03 15:33:37 -0300322 (-958 << 5) | 0x13
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300323};
324
Olivier Grenie4c70e072011-01-03 15:33:37 -0300325static const s16 coeff_4k_sb_3seg_0dqpsk[8] = {
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300326 (-723 << 5) | 0x13, (910 << 5) | 0x05, (777 << 5) | 0x14, (-723 << 5) | 0x13, (-568 << 5) | 0x0f, (547 << 5) | 0x03, (696 << 5) | 0x12,
Olivier Grenie4c70e072011-01-03 15:33:37 -0300327 (-568 << 5) | 0x0f
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300328};
329
Olivier Grenie4c70e072011-01-03 15:33:37 -0300330static const s16 coeff_4k_sb_3seg_1dqpsk[8] = {
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300331 (-940 << 5) | 0x15, (607 << 5) | 0x05, (915 << 5) | 0x16, (-940 << 5) | 0x15, (-848 << 5) | 0x13, (683 << 5) | 0x04, (543 << 5) | 0x14,
Olivier Grenie4c70e072011-01-03 15:33:37 -0300332 (-848 << 5) | 0x13
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300333};
334
Olivier Grenie4c70e072011-01-03 15:33:37 -0300335static const s16 coeff_4k_sb_3seg[8] = {
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300336 (612 << 5) | 0x12, (910 << 5) | 0x04, (864 << 5) | 0x14, (612 << 5) | 0x12, (-869 << 5) | 0x13, (683 << 5) | 0x02, (869 << 5) | 0x12,
Olivier Grenie4c70e072011-01-03 15:33:37 -0300337 (-869 << 5) | 0x13
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300338};
339
Olivier Grenie4c70e072011-01-03 15:33:37 -0300340static const s16 coeff_8k_sb_1seg_dqpsk[8] = {
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300341 (-835 << 5) | 0x12, (684 << 5) | 0x05, (735 << 5) | 0x14, (-835 << 5) | 0x12, (-598 << 5) | 0x10, (781 << 5) | 0x04, (739 << 5) | 0x13,
Olivier Grenie4c70e072011-01-03 15:33:37 -0300342 (-598 << 5) | 0x10
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300343};
344
Olivier Grenie4c70e072011-01-03 15:33:37 -0300345static const s16 coeff_8k_sb_1seg[8] = {
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300346 (673 << 5) | 0x0f, (683 << 5) | 0x03, (808 << 5) | 0x12, (673 << 5) | 0x0f, (585 << 5) | 0x0f, (512 << 5) | 0x01, (780 << 5) | 0x0f,
Olivier Grenie4c70e072011-01-03 15:33:37 -0300347 (585 << 5) | 0x0f
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300348};
349
Olivier Grenie4c70e072011-01-03 15:33:37 -0300350static const s16 coeff_8k_sb_3seg_0dqpsk_1dqpsk[8] = {
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300351 (863 << 5) | 0x17, (930 << 5) | 0x07, (878 << 5) | 0x19, (863 << 5) | 0x17, (0 << 5) | 0x14, (521 << 5) | 0x05, (980 << 5) | 0x18,
Olivier Grenie4c70e072011-01-03 15:33:37 -0300352 (0 << 5) | 0x14
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300353};
354
Olivier Grenie4c70e072011-01-03 15:33:37 -0300355static const s16 coeff_8k_sb_3seg_0dqpsk[8] = {
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300356 (-924 << 5) | 0x17, (910 << 5) | 0x06, (774 << 5) | 0x17, (-924 << 5) | 0x17, (-877 << 5) | 0x15, (565 << 5) | 0x04, (553 << 5) | 0x15,
Olivier Grenie4c70e072011-01-03 15:33:37 -0300357 (-877 << 5) | 0x15
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300358};
359
Olivier Grenie4c70e072011-01-03 15:33:37 -0300360static const s16 coeff_8k_sb_3seg_1dqpsk[8] = {
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300361 (-921 << 5) | 0x19, (607 << 5) | 0x06, (881 << 5) | 0x19, (-921 << 5) | 0x19, (-921 << 5) | 0x14, (713 << 5) | 0x05, (1018 << 5) | 0x18,
Olivier Grenie4c70e072011-01-03 15:33:37 -0300362 (-921 << 5) | 0x14
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300363};
364
Olivier Grenie4c70e072011-01-03 15:33:37 -0300365static const s16 coeff_8k_sb_3seg[8] = {
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300366 (514 << 5) | 0x14, (910 << 5) | 0x05, (861 << 5) | 0x17, (514 << 5) | 0x14, (690 << 5) | 0x14, (683 << 5) | 0x03, (662 << 5) | 0x15,
Olivier Grenie4c70e072011-01-03 15:33:37 -0300367 (690 << 5) | 0x14
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300368};
369
Olivier Grenie4c70e072011-01-03 15:33:37 -0300370static const s16 ana_fe_coeff_3seg[24] = {
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300371 81, 80, 78, 74, 68, 61, 54, 45, 37, 28, 19, 11, 4, 1022, 1017, 1013, 1010, 1008, 1008, 1008, 1008, 1010, 1014, 1017
372};
373
Olivier Grenie4c70e072011-01-03 15:33:37 -0300374static const s16 ana_fe_coeff_1seg[24] = {
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300375 249, 226, 164, 82, 5, 981, 970, 988, 1018, 20, 31, 26, 8, 1012, 1000, 1018, 1012, 8, 15, 14, 9, 3, 1017, 1003
376};
377
Olivier Grenie4c70e072011-01-03 15:33:37 -0300378static const s16 ana_fe_coeff_13seg[24] = {
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300379 396, 305, 105, -51, -77, -12, 41, 31, -11, -30, -11, 14, 15, -2, -13, -7, 5, 8, 1, -6, -7, -3, 0, 1
380};
381
382static u16 fft_to_mode(struct dib8000_state *state)
383{
384 u16 mode;
Olivier Grenie4c70e072011-01-03 15:33:37 -0300385 switch (state->fe[0]->dtv_property_cache.transmission_mode) {
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300386 case TRANSMISSION_MODE_2K:
387 mode = 1;
388 break;
389 case TRANSMISSION_MODE_4K:
390 mode = 2;
391 break;
392 default:
393 case TRANSMISSION_MODE_AUTO:
394 case TRANSMISSION_MODE_8K:
395 mode = 3;
396 break;
397 }
398 return mode;
399}
400
401static void dib8000_set_acquisition_mode(struct dib8000_state *state)
402{
403 u16 nud = dib8000_read_word(state, 298);
404 nud |= (1 << 3) | (1 << 0);
Mauro Carvalho Chehab8af16ad2016-10-14 10:05:46 -0300405 dprintk("acquisition mode activated\n");
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300406 dib8000_write_word(state, 298, nud);
407}
Olivier Grenie4c70e072011-01-03 15:33:37 -0300408static int dib8000_set_output_mode(struct dvb_frontend *fe, int mode)
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300409{
Olivier Grenie4c70e072011-01-03 15:33:37 -0300410 struct dib8000_state *state = fe->demodulator_priv;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300411 u16 outreg, fifo_threshold, smo_mode, sram = 0x0205; /* by default SDRAM deintlv is enabled */
412
Patrick Boettcher173a64c2013-04-22 12:45:52 -0300413 state->output_mode = mode;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300414 outreg = 0;
415 fifo_threshold = 1792;
416 smo_mode = (dib8000_read_word(state, 299) & 0x0050) | (1 << 1);
417
Mauro Carvalho Chehab8af16ad2016-10-14 10:05:46 -0300418 dprintk("-I- Setting output mode for demod %p to %d\n",
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300419 &state->fe[0], mode);
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300420
421 switch (mode) {
422 case OUTMODE_MPEG2_PAR_GATED_CLK: // STBs with parallel gated clock
423 outreg = (1 << 10); /* 0x0400 */
424 break;
425 case OUTMODE_MPEG2_PAR_CONT_CLK: // STBs with parallel continues clock
426 outreg = (1 << 10) | (1 << 6); /* 0x0440 */
427 break;
428 case OUTMODE_MPEG2_SERIAL: // STBs with serial input
429 outreg = (1 << 10) | (2 << 6) | (0 << 1); /* 0x0482 */
430 break;
431 case OUTMODE_DIVERSITY:
432 if (state->cfg.hostbus_diversity) {
433 outreg = (1 << 10) | (4 << 6); /* 0x0500 */
434 sram &= 0xfdff;
435 } else
436 sram |= 0x0c00;
437 break;
438 case OUTMODE_MPEG2_FIFO: // e.g. USB feeding
439 smo_mode |= (3 << 1);
440 fifo_threshold = 512;
441 outreg = (1 << 10) | (5 << 6);
442 break;
443 case OUTMODE_HIGH_Z: // disable
444 outreg = 0;
445 break;
446
447 case OUTMODE_ANALOG_ADC:
448 outreg = (1 << 10) | (3 << 6);
449 dib8000_set_acquisition_mode(state);
450 break;
451
452 default:
Mauro Carvalho Chehab8af16ad2016-10-14 10:05:46 -0300453 dprintk("Unhandled output_mode passed to be set for demod %p\n",
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300454 &state->fe[0]);
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300455 return -EINVAL;
456 }
457
458 if (state->cfg.output_mpeg2_in_188_bytes)
459 smo_mode |= (1 << 5);
460
461 dib8000_write_word(state, 299, smo_mode);
462 dib8000_write_word(state, 300, fifo_threshold); /* synchronous fread */
463 dib8000_write_word(state, 1286, outreg);
464 dib8000_write_word(state, 1291, sram);
465
466 return 0;
467}
468
469static int dib8000_set_diversity_in(struct dvb_frontend *fe, int onoff)
470{
471 struct dib8000_state *state = fe->demodulator_priv;
Patrick Boettcher173a64c2013-04-22 12:45:52 -0300472 u16 tmp, sync_wait = dib8000_read_word(state, 273) & 0xfff0;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300473
Mauro Carvalho Chehab8af16ad2016-10-14 10:05:46 -0300474 dprintk("set diversity input to %i\n", onoff);
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300475 if (!state->differential_constellation) {
476 dib8000_write_word(state, 272, 1 << 9); //dvsy_off_lmod4 = 1
477 dib8000_write_word(state, 273, sync_wait | (1 << 2) | 2); // sync_enable = 1; comb_mode = 2
478 } else {
479 dib8000_write_word(state, 272, 0); //dvsy_off_lmod4 = 0
480 dib8000_write_word(state, 273, sync_wait); // sync_enable = 0; comb_mode = 0
481 }
482 state->diversity_onoff = onoff;
483
484 switch (onoff) {
485 case 0: /* only use the internal way - not the diversity input */
486 dib8000_write_word(state, 270, 1);
487 dib8000_write_word(state, 271, 0);
488 break;
489 case 1: /* both ways */
490 dib8000_write_word(state, 270, 6);
491 dib8000_write_word(state, 271, 6);
492 break;
493 case 2: /* only the diversity input */
494 dib8000_write_word(state, 270, 0);
495 dib8000_write_word(state, 271, 1);
496 break;
497 }
Patrick Boettcher173a64c2013-04-22 12:45:52 -0300498
499 if (state->revision == 0x8002) {
500 tmp = dib8000_read_word(state, 903);
501 dib8000_write_word(state, 903, tmp & ~(1 << 3));
502 msleep(30);
503 dib8000_write_word(state, 903, tmp | (1 << 3));
504 }
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300505 return 0;
506}
507
508static void dib8000_set_power_mode(struct dib8000_state *state, enum dib8000_power_mode mode)
509{
510 /* by default everything is going to be powered off */
511 u16 reg_774 = 0x3fff, reg_775 = 0xffff, reg_776 = 0xffff,
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300512 reg_900 = (dib8000_read_word(state, 900) & 0xfffc) | 0x3,
Olivier Grenie0c32dbd2011-08-10 05:17:18 -0300513 reg_1280;
514
515 if (state->revision != 0x8090)
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300516 reg_1280 = (dib8000_read_word(state, 1280) & 0x00ff) | 0xff00;
Olivier Grenie0c32dbd2011-08-10 05:17:18 -0300517 else
518 reg_1280 = (dib8000_read_word(state, 1280) & 0x707f) | 0x8f80;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300519
520 /* now, depending on the requested mode, we power on */
521 switch (mode) {
522 /* power up everything in the demod */
Olivier Grenie0c32dbd2011-08-10 05:17:18 -0300523 case DIB8000_POWER_ALL:
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300524 reg_774 = 0x0000;
525 reg_775 = 0x0000;
526 reg_776 = 0x0000;
527 reg_900 &= 0xfffc;
Olivier Grenie0c32dbd2011-08-10 05:17:18 -0300528 if (state->revision != 0x8090)
529 reg_1280 &= 0x00ff;
530 else
531 reg_1280 &= 0x707f;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300532 break;
Olivier Grenie0c32dbd2011-08-10 05:17:18 -0300533 case DIB8000_POWER_INTERFACE_ONLY:
534 if (state->revision != 0x8090)
535 reg_1280 &= 0x00ff;
536 else
537 reg_1280 &= 0xfa7b;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300538 break;
539 }
540
Mauro Carvalho Chehab8af16ad2016-10-14 10:05:46 -0300541 dprintk("powermode : 774 : %x ; 775 : %x; 776 : %x ; 900 : %x; 1280 : %x\n", reg_774, reg_775, reg_776, reg_900, reg_1280);
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300542 dib8000_write_word(state, 774, reg_774);
543 dib8000_write_word(state, 775, reg_775);
544 dib8000_write_word(state, 776, reg_776);
545 dib8000_write_word(state, 900, reg_900);
546 dib8000_write_word(state, 1280, reg_1280);
547}
548
549static int dib8000_set_adc_state(struct dib8000_state *state, enum dibx000_adc_states no)
550{
551 int ret = 0;
Olivier Grenie0c32dbd2011-08-10 05:17:18 -0300552 u16 reg, reg_907 = dib8000_read_word(state, 907);
553 u16 reg_908 = dib8000_read_word(state, 908);
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300554
555 switch (no) {
556 case DIBX000_SLOW_ADC_ON:
Olivier Grenie0c32dbd2011-08-10 05:17:18 -0300557 if (state->revision != 0x8090) {
558 reg_908 |= (1 << 1) | (1 << 0);
559 ret |= dib8000_write_word(state, 908, reg_908);
560 reg_908 &= ~(1 << 1);
561 } else {
562 reg = dib8000_read_word(state, 1925);
563 /* en_slowAdc = 1 & reset_sladc = 1 */
564 dib8000_write_word(state, 1925, reg |
565 (1<<4) | (1<<2));
566
567 /* read acces to make it works... strange ... */
568 reg = dib8000_read_word(state, 1925);
569 msleep(20);
570 /* en_slowAdc = 1 & reset_sladc = 0 */
571 dib8000_write_word(state, 1925, reg & ~(1<<4));
572
573 reg = dib8000_read_word(state, 921) & ~((0x3 << 14)
574 | (0x3 << 12));
575 /* ref = Vin1 => Vbg ; sel = Vin0 or Vin3 ;
576 (Vin2 = Vcm) */
577 dib8000_write_word(state, 921, reg | (1 << 14)
578 | (3 << 12));
579 }
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300580 break;
581
582 case DIBX000_SLOW_ADC_OFF:
Olivier Grenie0c32dbd2011-08-10 05:17:18 -0300583 if (state->revision == 0x8090) {
584 reg = dib8000_read_word(state, 1925);
585 /* reset_sladc = 1 en_slowAdc = 0 */
586 dib8000_write_word(state, 1925,
587 (reg & ~(1<<2)) | (1<<4));
588 }
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300589 reg_908 |= (1 << 1) | (1 << 0);
590 break;
591
592 case DIBX000_ADC_ON:
593 reg_907 &= 0x0fff;
594 reg_908 &= 0x0003;
595 break;
596
597 case DIBX000_ADC_OFF: // leave the VBG voltage on
Mauro Carvalho Chehabc063c7c2014-07-04 14:15:28 -0300598 reg_907 = (1 << 13) | (1 << 12);
599 reg_908 = (1 << 6) | (1 << 5) | (1 << 4) | (1 << 3) | (1 << 1);
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300600 break;
601
602 case DIBX000_VBG_ENABLE:
603 reg_907 &= ~(1 << 15);
604 break;
605
606 case DIBX000_VBG_DISABLE:
607 reg_907 |= (1 << 15);
608 break;
609
610 default:
611 break;
612 }
613
614 ret |= dib8000_write_word(state, 907, reg_907);
615 ret |= dib8000_write_word(state, 908, reg_908);
616
617 return ret;
618}
619
Olivier Grenie4c70e072011-01-03 15:33:37 -0300620static int dib8000_set_bandwidth(struct dvb_frontend *fe, u32 bw)
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300621{
Olivier Grenie4c70e072011-01-03 15:33:37 -0300622 struct dib8000_state *state = fe->demodulator_priv;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300623 u32 timf;
624
625 if (bw == 0)
626 bw = 6000;
627
628 if (state->timf == 0) {
Mauro Carvalho Chehab8af16ad2016-10-14 10:05:46 -0300629 dprintk("using default timf\n");
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300630 timf = state->timf_default;
631 } else {
Mauro Carvalho Chehab8af16ad2016-10-14 10:05:46 -0300632 dprintk("using updated timf\n");
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300633 timf = state->timf;
634 }
635
636 dib8000_write_word(state, 29, (u16) ((timf >> 16) & 0xffff));
637 dib8000_write_word(state, 30, (u16) ((timf) & 0xffff));
638
639 return 0;
640}
641
642static int dib8000_sad_calib(struct dib8000_state *state)
643{
Patrick Boettcher173a64c2013-04-22 12:45:52 -0300644 u8 sad_sel = 3;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300645
Patrick Boettcher173a64c2013-04-22 12:45:52 -0300646 if (state->revision == 0x8090) {
647 dib8000_write_word(state, 922, (sad_sel << 2));
648 dib8000_write_word(state, 923, 2048);
649
650 dib8000_write_word(state, 922, (sad_sel << 2) | 0x1);
651 dib8000_write_word(state, 922, (sad_sel << 2));
652 } else {
653 /* internal */
654 dib8000_write_word(state, 923, (0 << 1) | (0 << 0));
655 dib8000_write_word(state, 924, 776);
656
657 /* do the calibration */
658 dib8000_write_word(state, 923, (1 << 0));
659 dib8000_write_word(state, 923, (0 << 0));
660 }
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300661
662 msleep(1);
663 return 0;
664}
665
Mauro Carvalho Chehabd44913c2014-05-29 09:20:17 -0300666static int dib8000_set_wbd_ref(struct dvb_frontend *fe, u16 value)
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300667{
668 struct dib8000_state *state = fe->demodulator_priv;
669 if (value > 4095)
670 value = 4095;
671 state->wbd_ref = value;
672 return dib8000_write_word(state, 106, value);
673}
Patrick Boettcher173a64c2013-04-22 12:45:52 -0300674
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300675static void dib8000_reset_pll_common(struct dib8000_state *state, const struct dibx000_bandwidth_config *bw)
676{
Mauro Carvalho Chehab8af16ad2016-10-14 10:05:46 -0300677 dprintk("ifreq: %d %x, inversion: %d\n", bw->ifreq, bw->ifreq, bw->ifreq >> 25);
Olivier Grenie0c32dbd2011-08-10 05:17:18 -0300678 if (state->revision != 0x8090) {
679 dib8000_write_word(state, 23,
680 (u16) (((bw->internal * 1000) >> 16) & 0xffff));
681 dib8000_write_word(state, 24,
682 (u16) ((bw->internal * 1000) & 0xffff));
683 } else {
684 dib8000_write_word(state, 23, (u16) (((bw->internal / 2 * 1000) >> 16) & 0xffff));
685 dib8000_write_word(state, 24,
686 (u16) ((bw->internal / 2 * 1000) & 0xffff));
687 }
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300688 dib8000_write_word(state, 27, (u16) ((bw->ifreq >> 16) & 0x01ff));
689 dib8000_write_word(state, 28, (u16) (bw->ifreq & 0xffff));
690 dib8000_write_word(state, 26, (u16) ((bw->ifreq >> 25) & 0x0003));
691
Olivier Grenie0c32dbd2011-08-10 05:17:18 -0300692 if (state->revision != 0x8090)
693 dib8000_write_word(state, 922, bw->sad_cfg);
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300694}
695
696static void dib8000_reset_pll(struct dib8000_state *state)
697{
698 const struct dibx000_bandwidth_config *pll = state->cfg.pll;
Olivier Grenie0c32dbd2011-08-10 05:17:18 -0300699 u16 clk_cfg1, reg;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300700
Olivier Grenie0c32dbd2011-08-10 05:17:18 -0300701 if (state->revision != 0x8090) {
702 dib8000_write_word(state, 901,
703 (pll->pll_prediv << 8) | (pll->pll_ratio << 0));
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300704
Olivier Grenie0c32dbd2011-08-10 05:17:18 -0300705 clk_cfg1 = (1 << 10) | (0 << 9) | (pll->IO_CLK_en_core << 8) |
706 (pll->bypclk_div << 5) | (pll->enable_refdiv << 4) |
707 (1 << 3) | (pll->pll_range << 1) |
708 (pll->pll_reset << 0);
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300709
Olivier Grenie0c32dbd2011-08-10 05:17:18 -0300710 dib8000_write_word(state, 902, clk_cfg1);
711 clk_cfg1 = (clk_cfg1 & 0xfff7) | (pll->pll_bypass << 3);
712 dib8000_write_word(state, 902, clk_cfg1);
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300713
Mauro Carvalho Chehab8af16ad2016-10-14 10:05:46 -0300714 dprintk("clk_cfg1: 0x%04x\n", clk_cfg1);
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300715
Olivier Grenie0c32dbd2011-08-10 05:17:18 -0300716 /* smpl_cfg: P_refclksel=2, P_ensmplsel=1 nodivsmpl=1 */
717 if (state->cfg.pll->ADClkSrc == 0)
718 dib8000_write_word(state, 904,
719 (0 << 15) | (0 << 12) | (0 << 10) |
720 (pll->modulo << 8) |
721 (pll->ADClkSrc << 7) | (0 << 1));
722 else if (state->cfg.refclksel != 0)
723 dib8000_write_word(state, 904, (0 << 15) | (1 << 12) |
724 ((state->cfg.refclksel & 0x3) << 10) |
725 (pll->modulo << 8) |
726 (pll->ADClkSrc << 7) | (0 << 1));
727 else
728 dib8000_write_word(state, 904, (0 << 15) | (1 << 12) |
729 (3 << 10) | (pll->modulo << 8) |
730 (pll->ADClkSrc << 7) | (0 << 1));
731 } else {
732 dib8000_write_word(state, 1856, (!pll->pll_reset<<13) |
733 (pll->pll_range<<12) | (pll->pll_ratio<<6) |
734 (pll->pll_prediv));
735
736 reg = dib8000_read_word(state, 1857);
737 dib8000_write_word(state, 1857, reg|(!pll->pll_bypass<<15));
738
739 reg = dib8000_read_word(state, 1858); /* Force clk out pll /2 */
740 dib8000_write_word(state, 1858, reg | 1);
741
742 dib8000_write_word(state, 904, (pll->modulo << 8));
743 }
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300744
745 dib8000_reset_pll_common(state, pll);
746}
747
Mauro Carvalho Chehabd44913c2014-05-29 09:20:17 -0300748static int dib8000_update_pll(struct dvb_frontend *fe,
Patrick Boettcher173a64c2013-04-22 12:45:52 -0300749 struct dibx000_bandwidth_config *pll, u32 bw, u8 ratio)
Olivier Grenie0c32dbd2011-08-10 05:17:18 -0300750{
751 struct dib8000_state *state = fe->demodulator_priv;
752 u16 reg_1857, reg_1856 = dib8000_read_word(state, 1856);
Patrick Boettcher173a64c2013-04-22 12:45:52 -0300753 u8 loopdiv, prediv, oldprediv = state->cfg.pll->pll_prediv ;
Olivier Grenie0c32dbd2011-08-10 05:17:18 -0300754 u32 internal, xtal;
755
756 /* get back old values */
757 prediv = reg_1856 & 0x3f;
758 loopdiv = (reg_1856 >> 6) & 0x3f;
759
Patrick Boettcher173a64c2013-04-22 12:45:52 -0300760 if ((pll == NULL) || (pll->pll_prediv == prediv &&
761 pll->pll_ratio == loopdiv))
762 return -EINVAL;
763
Mauro Carvalho Chehab8af16ad2016-10-14 10:05:46 -0300764 dprintk("Updating pll (prediv: old = %d new = %d ; loopdiv : old = %d new = %d)\n", prediv, pll->pll_prediv, loopdiv, pll->pll_ratio);
Patrick Boettcher173a64c2013-04-22 12:45:52 -0300765 if (state->revision == 0x8090) {
Olivier Grenie0c32dbd2011-08-10 05:17:18 -0300766 reg_1856 &= 0xf000;
767 reg_1857 = dib8000_read_word(state, 1857);
768 /* disable PLL */
769 dib8000_write_word(state, 1857, reg_1857 & ~(1 << 15));
770
771 dib8000_write_word(state, 1856, reg_1856 |
772 ((pll->pll_ratio & 0x3f) << 6) |
773 (pll->pll_prediv & 0x3f));
774
775 /* write new system clk into P_sec_len */
776 internal = dib8000_read32(state, 23) / 1000;
Mauro Carvalho Chehab8af16ad2016-10-14 10:05:46 -0300777 dprintk("Old Internal = %d\n", internal);
Olivier Grenie0c32dbd2011-08-10 05:17:18 -0300778 xtal = 2 * (internal / loopdiv) * prediv;
779 internal = 1000 * (xtal/pll->pll_prediv) * pll->pll_ratio;
Mauro Carvalho Chehab8af16ad2016-10-14 10:05:46 -0300780 dprintk("Xtal = %d , New Fmem = %d New Fdemod = %d, New Fsampling = %d\n", xtal, internal/1000, internal/2000, internal/8000);
781 dprintk("New Internal = %d\n", internal);
Olivier Grenie0c32dbd2011-08-10 05:17:18 -0300782
783 dib8000_write_word(state, 23,
784 (u16) (((internal / 2) >> 16) & 0xffff));
785 dib8000_write_word(state, 24, (u16) ((internal / 2) & 0xffff));
786 /* enable PLL */
787 dib8000_write_word(state, 1857, reg_1857 | (1 << 15));
788
789 while (((dib8000_read_word(state, 1856)>>15)&0x1) != 1)
Mauro Carvalho Chehab8af16ad2016-10-14 10:05:46 -0300790 dprintk("Waiting for PLL to lock\n");
Olivier Grenie0c32dbd2011-08-10 05:17:18 -0300791
792 /* verify */
793 reg_1856 = dib8000_read_word(state, 1856);
Mauro Carvalho Chehab8af16ad2016-10-14 10:05:46 -0300794 dprintk("PLL Updated with prediv = %d and loopdiv = %d\n",
Olivier Grenie0c32dbd2011-08-10 05:17:18 -0300795 reg_1856&0x3f, (reg_1856>>6)&0x3f);
Patrick Boettcher173a64c2013-04-22 12:45:52 -0300796 } else {
797 if (bw != state->current_demod_bw) {
798 /** Bandwidth change => force PLL update **/
Mauro Carvalho Chehab8af16ad2016-10-14 10:05:46 -0300799 dprintk("PLL: Bandwidth Change %d MHz -> %d MHz (prediv: %d->%d)\n", state->current_demod_bw / 1000, bw / 1000, oldprediv, state->cfg.pll->pll_prediv);
Olivier Grenie0c32dbd2011-08-10 05:17:18 -0300800
Patrick Boettcher173a64c2013-04-22 12:45:52 -0300801 if (state->cfg.pll->pll_prediv != oldprediv) {
802 /** Full PLL change only if prediv is changed **/
803
804 /** full update => bypass and reconfigure **/
Mauro Carvalho Chehab8af16ad2016-10-14 10:05:46 -0300805 dprintk("PLL: New Setting for %d MHz Bandwidth (prediv: %d, ratio: %d)\n", bw/1000, state->cfg.pll->pll_prediv, state->cfg.pll->pll_ratio);
Patrick Boettcher173a64c2013-04-22 12:45:52 -0300806 dib8000_write_word(state, 902, dib8000_read_word(state, 902) | (1<<3)); /* bypass PLL */
807 dib8000_reset_pll(state);
808 dib8000_write_word(state, 898, 0x0004); /* sad */
809 } else
810 ratio = state->cfg.pll->pll_ratio;
811
812 state->current_demod_bw = bw;
813 }
814
815 if (ratio != 0) {
816 /** ratio update => only change ratio **/
Mauro Carvalho Chehab8af16ad2016-10-14 10:05:46 -0300817 dprintk("PLL: Update ratio (prediv: %d, ratio: %d)\n", state->cfg.pll->pll_prediv, ratio);
Patrick Boettcher173a64c2013-04-22 12:45:52 -0300818 dib8000_write_word(state, 901, (state->cfg.pll->pll_prediv << 8) | (ratio << 0)); /* only the PLL ratio is updated. */
819 }
Mauro Carvalho Chehab6ef06e72013-12-16 19:10:59 -0300820 }
Patrick Boettcher173a64c2013-04-22 12:45:52 -0300821
822 return 0;
Olivier Grenie0c32dbd2011-08-10 05:17:18 -0300823}
Olivier Grenie0c32dbd2011-08-10 05:17:18 -0300824
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300825static int dib8000_reset_gpio(struct dib8000_state *st)
826{
827 /* reset the GPIOs */
828 dib8000_write_word(st, 1029, st->cfg.gpio_dir);
829 dib8000_write_word(st, 1030, st->cfg.gpio_val);
830
831 /* TODO 782 is P_gpio_od */
832
833 dib8000_write_word(st, 1032, st->cfg.gpio_pwm_pos);
834
835 dib8000_write_word(st, 1037, st->cfg.pwm_freq_div);
836 return 0;
837}
838
839static int dib8000_cfg_gpio(struct dib8000_state *st, u8 num, u8 dir, u8 val)
840{
841 st->cfg.gpio_dir = dib8000_read_word(st, 1029);
842 st->cfg.gpio_dir &= ~(1 << num); /* reset the direction bit */
843 st->cfg.gpio_dir |= (dir & 0x1) << num; /* set the new direction */
844 dib8000_write_word(st, 1029, st->cfg.gpio_dir);
845
846 st->cfg.gpio_val = dib8000_read_word(st, 1030);
847 st->cfg.gpio_val &= ~(1 << num); /* reset the direction bit */
848 st->cfg.gpio_val |= (val & 0x01) << num; /* set the new value */
849 dib8000_write_word(st, 1030, st->cfg.gpio_val);
850
Mauro Carvalho Chehab8af16ad2016-10-14 10:05:46 -0300851 dprintk("gpio dir: %x: gpio val: %x\n", st->cfg.gpio_dir, st->cfg.gpio_val);
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300852
853 return 0;
854}
855
Mauro Carvalho Chehabd44913c2014-05-29 09:20:17 -0300856static int dib8000_set_gpio(struct dvb_frontend *fe, u8 num, u8 dir, u8 val)
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300857{
858 struct dib8000_state *state = fe->demodulator_priv;
859 return dib8000_cfg_gpio(state, num, dir, val);
860}
861
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300862static const u16 dib8000_defaults[] = {
863 /* auto search configuration - lock0 by default waiting
864 * for cpil_lock; lock1 cpil_lock; lock2 tmcc_sync_lock */
865 3, 7,
866 0x0004,
867 0x0400,
868 0x0814,
869
870 12, 11,
871 0x001b,
872 0x7740,
873 0x005b,
874 0x8d80,
875 0x01c9,
876 0xc380,
877 0x0000,
878 0x0080,
879 0x0000,
880 0x0090,
881 0x0001,
882 0xd4c0,
883
884 /*1, 32,
Olivier Grenie4c70e072011-01-03 15:33:37 -0300885 0x6680 // P_corm_thres Lock algorithms configuration */
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300886
887 11, 80, /* set ADC level to -16 */
888 (1 << 13) - 825 - 117,
889 (1 << 13) - 837 - 117,
890 (1 << 13) - 811 - 117,
891 (1 << 13) - 766 - 117,
892 (1 << 13) - 737 - 117,
893 (1 << 13) - 693 - 117,
894 (1 << 13) - 648 - 117,
895 (1 << 13) - 619 - 117,
896 (1 << 13) - 575 - 117,
897 (1 << 13) - 531 - 117,
898 (1 << 13) - 501 - 117,
899
900 4, 108,
901 0,
902 0,
903 0,
904 0,
905
906 1, 175,
907 0x0410,
908 1, 179,
909 8192, // P_fft_nb_to_cut
910
911 6, 181,
912 0x2800, // P_coff_corthres_ ( 2k 4k 8k ) 0x2800
913 0x2800,
914 0x2800,
915 0x2800, // P_coff_cpilthres_ ( 2k 4k 8k ) 0x2800
916 0x2800,
917 0x2800,
918
919 2, 193,
920 0x0666, // P_pha3_thres
921 0x0000, // P_cti_use_cpe, P_cti_use_prog
922
923 2, 205,
924 0x200f, // P_cspu_regul, P_cspu_win_cut
925 0x000f, // P_des_shift_work
926
927 5, 215,
928 0x023d, // P_adp_regul_cnt
929 0x00a4, // P_adp_noise_cnt
930 0x00a4, // P_adp_regul_ext
931 0x7ff0, // P_adp_noise_ext
932 0x3ccc, // P_adp_fil
933
934 1, 230,
935 0x0000, // P_2d_byp_ti_num
936
937 1, 263,
938 0x800, //P_equal_thres_wgn
939
940 1, 268,
941 (2 << 9) | 39, // P_equal_ctrl_synchro, P_equal_speedmode
942
943 1, 270,
944 0x0001, // P_div_lock0_wait
945 1, 285,
946 0x0020, //p_fec_
947 1, 299,
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300948 0x0062, /* P_smo_mode, P_smo_rs_discard, P_smo_fifo_flush, P_smo_pid_parse, P_smo_error_discard */
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300949
950 1, 338,
951 (1 << 12) | // P_ctrl_corm_thres4pre_freq_inh=1
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300952 (1 << 10) |
953 (0 << 9) | /* P_ctrl_pre_freq_inh=0 */
954 (3 << 5) | /* P_ctrl_pre_freq_step=3 */
955 (1 << 0), /* P_pre_freq_win_len=1 */
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300956
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300957 0,
958};
959
960static u16 dib8000_identify(struct i2c_device *client)
961{
962 u16 value;
963
964 //because of glitches sometimes
965 value = dib8000_i2c_read16(client, 896);
966
967 if ((value = dib8000_i2c_read16(client, 896)) != 0x01b3) {
Mauro Carvalho Chehab8af16ad2016-10-14 10:05:46 -0300968 dprintk("wrong Vendor ID (read=0x%x)\n", value);
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300969 return 0;
970 }
971
972 value = dib8000_i2c_read16(client, 897);
Olivier Grenie0c32dbd2011-08-10 05:17:18 -0300973 if (value != 0x8000 && value != 0x8001 &&
974 value != 0x8002 && value != 0x8090) {
Mauro Carvalho Chehab8af16ad2016-10-14 10:05:46 -0300975 dprintk("wrong Device ID (%x)\n", value);
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300976 return 0;
977 }
978
979 switch (value) {
980 case 0x8000:
Mauro Carvalho Chehab8af16ad2016-10-14 10:05:46 -0300981 dprintk("found DiB8000A\n");
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300982 break;
983 case 0x8001:
Mauro Carvalho Chehab8af16ad2016-10-14 10:05:46 -0300984 dprintk("found DiB8000B\n");
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300985 break;
986 case 0x8002:
Mauro Carvalho Chehab8af16ad2016-10-14 10:05:46 -0300987 dprintk("found DiB8000C\n");
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300988 break;
Olivier Grenie0c32dbd2011-08-10 05:17:18 -0300989 case 0x8090:
Mauro Carvalho Chehab8af16ad2016-10-14 10:05:46 -0300990 dprintk("found DiB8096P\n");
Olivier Grenie0c32dbd2011-08-10 05:17:18 -0300991 break;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300992 }
993 return value;
994}
995
Mauro Carvalho Chehab7a9d85d2013-12-17 04:55:26 -0300996static int dib8000_read_unc_blocks(struct dvb_frontend *fe, u32 *unc);
997
Mauro Carvalho Chehab6ef06e72013-12-16 19:10:59 -0300998static void dib8000_reset_stats(struct dvb_frontend *fe)
999{
1000 struct dib8000_state *state = fe->demodulator_priv;
1001 struct dtv_frontend_properties *c = &state->fe[0]->dtv_property_cache;
Mauro Carvalho Chehab7a9d85d2013-12-17 04:55:26 -03001002 u32 ucb;
Mauro Carvalho Chehab6ef06e72013-12-16 19:10:59 -03001003
1004 memset(&c->strength, 0, sizeof(c->strength));
1005 memset(&c->cnr, 0, sizeof(c->cnr));
1006 memset(&c->post_bit_error, 0, sizeof(c->post_bit_error));
1007 memset(&c->post_bit_count, 0, sizeof(c->post_bit_count));
1008 memset(&c->block_error, 0, sizeof(c->block_error));
1009
1010 c->strength.len = 1;
1011 c->cnr.len = 1;
1012 c->block_error.len = 1;
Mauro Carvalho Chehab0400c532013-12-17 11:34:22 -03001013 c->block_count.len = 1;
Mauro Carvalho Chehab6ef06e72013-12-16 19:10:59 -03001014 c->post_bit_error.len = 1;
1015 c->post_bit_count.len = 1;
1016
Mauro Carvalho Chehabb4600d72013-12-16 20:00:34 -03001017 c->strength.stat[0].scale = FE_SCALE_DECIBEL;
Mauro Carvalho Chehab6ef06e72013-12-16 19:10:59 -03001018 c->strength.stat[0].uvalue = 0;
1019
1020 c->cnr.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
1021 c->block_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
Mauro Carvalho Chehab0400c532013-12-17 11:34:22 -03001022 c->block_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
Mauro Carvalho Chehab6ef06e72013-12-16 19:10:59 -03001023 c->post_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
1024 c->post_bit_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
Mauro Carvalho Chehab7a9d85d2013-12-17 04:55:26 -03001025
1026 dib8000_read_unc_blocks(fe, &ucb);
Mauro Carvalho Chehab704f01b2013-12-17 10:08:20 -03001027
Mauro Carvalho Chehab7a9d85d2013-12-17 04:55:26 -03001028 state->init_ucb = -ucb;
Mauro Carvalho Chehab0400c532013-12-17 11:34:22 -03001029 state->ber_jiffies_stats = 0;
1030 state->per_jiffies_stats = 0;
1031 memset(&state->ber_jiffies_stats_layer, 0,
1032 sizeof(state->ber_jiffies_stats_layer));
Mauro Carvalho Chehab6ef06e72013-12-16 19:10:59 -03001033}
1034
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001035static int dib8000_reset(struct dvb_frontend *fe)
1036{
1037 struct dib8000_state *state = fe->demodulator_priv;
1038
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001039 if ((state->revision = dib8000_identify(&state->i2c)) == 0)
1040 return -EINVAL;
1041
Olivier Grenie0c32dbd2011-08-10 05:17:18 -03001042 /* sram lead in, rdy */
1043 if (state->revision != 0x8090)
1044 dib8000_write_word(state, 1287, 0x0003);
1045
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001046 if (state->revision == 0x8000)
Mauro Carvalho Chehab8af16ad2016-10-14 10:05:46 -03001047 dprintk("error : dib8000 MA not supported\n");
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001048
1049 dibx000_reset_i2c_master(&state->i2c_master);
1050
Olivier Grenie0c32dbd2011-08-10 05:17:18 -03001051 dib8000_set_power_mode(state, DIB8000_POWER_ALL);
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001052
1053 /* always leave the VBG voltage on - it consumes almost nothing but takes a long time to start */
Patrick Boettcher173a64c2013-04-22 12:45:52 -03001054 dib8000_set_adc_state(state, DIBX000_ADC_OFF);
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001055
1056 /* restart all parts */
1057 dib8000_write_word(state, 770, 0xffff);
1058 dib8000_write_word(state, 771, 0xffff);
1059 dib8000_write_word(state, 772, 0xfffc);
Mauro Carvalho Chehab6d384542014-07-04 14:15:33 -03001060 dib8000_write_word(state, 898, 0x000c); /* restart sad */
Olivier Grenie0c32dbd2011-08-10 05:17:18 -03001061 if (state->revision == 0x8090)
1062 dib8000_write_word(state, 1280, 0x0045);
1063 else
1064 dib8000_write_word(state, 1280, 0x004d);
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001065 dib8000_write_word(state, 1281, 0x000c);
1066
1067 dib8000_write_word(state, 770, 0x0000);
1068 dib8000_write_word(state, 771, 0x0000);
1069 dib8000_write_word(state, 772, 0x0000);
1070 dib8000_write_word(state, 898, 0x0004); // sad
1071 dib8000_write_word(state, 1280, 0x0000);
1072 dib8000_write_word(state, 1281, 0x0000);
1073
1074 /* drives */
Olivier Grenie0c32dbd2011-08-10 05:17:18 -03001075 if (state->revision != 0x8090) {
1076 if (state->cfg.drives)
1077 dib8000_write_word(state, 906, state->cfg.drives);
1078 else {
Mauro Carvalho Chehab8af16ad2016-10-14 10:05:46 -03001079 dprintk("using standard PAD-drive-settings, please adjust settings in config-struct to be optimal.\n");
Olivier Grenie0c32dbd2011-08-10 05:17:18 -03001080 /* min drive SDRAM - not optimal - adjust */
1081 dib8000_write_word(state, 906, 0x2d98);
1082 }
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001083 }
1084
1085 dib8000_reset_pll(state);
Olivier Grenie0c32dbd2011-08-10 05:17:18 -03001086 if (state->revision != 0x8090)
1087 dib8000_write_word(state, 898, 0x0004);
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001088
1089 if (dib8000_reset_gpio(state) != 0)
Mauro Carvalho Chehab8af16ad2016-10-14 10:05:46 -03001090 dprintk("GPIO reset was not successful.\n");
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001091
Olivier Grenie0c32dbd2011-08-10 05:17:18 -03001092 if ((state->revision != 0x8090) &&
1093 (dib8000_set_output_mode(fe, OUTMODE_HIGH_Z) != 0))
Mauro Carvalho Chehab8af16ad2016-10-14 10:05:46 -03001094 dprintk("OUTPUT_MODE could not be resetted.\n");
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001095
1096 state->current_agc = NULL;
1097
1098 // P_iqc_alpha_pha, P_iqc_alpha_amp, P_iqc_dcc_alpha, ...
1099 /* P_iqc_ca2 = 0; P_iqc_impnc_on = 0; P_iqc_mode = 0; */
1100 if (state->cfg.pll->ifreq == 0)
1101 dib8000_write_word(state, 40, 0x0755); /* P_iqc_corr_inh = 0 enable IQcorr block */
1102 else
1103 dib8000_write_word(state, 40, 0x1f55); /* P_iqc_corr_inh = 1 disable IQcorr block */
1104
1105 {
1106 u16 l = 0, r;
1107 const u16 *n;
1108 n = dib8000_defaults;
1109 l = *n++;
1110 while (l) {
1111 r = *n++;
1112 do {
1113 dib8000_write_word(state, r, *n++);
1114 r++;
1115 } while (--l);
1116 l = *n++;
1117 }
1118 }
Patrick Boettcher173a64c2013-04-22 12:45:52 -03001119
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001120 state->isdbt_cfg_loaded = 0;
1121
1122 //div_cfg override for special configs
Patrick Boettcher173a64c2013-04-22 12:45:52 -03001123 if ((state->revision != 8090) && (state->cfg.div_cfg != 0))
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001124 dib8000_write_word(state, 903, state->cfg.div_cfg);
1125
1126 /* unforce divstr regardless whether i2c enumeration was done or not */
1127 dib8000_write_word(state, 1285, dib8000_read_word(state, 1285) & ~(1 << 1));
1128
Olivier Grenie4c70e072011-01-03 15:33:37 -03001129 dib8000_set_bandwidth(fe, 6000);
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001130
1131 dib8000_set_adc_state(state, DIBX000_SLOW_ADC_ON);
Patrick Boettcher173a64c2013-04-22 12:45:52 -03001132 dib8000_sad_calib(state);
1133 if (state->revision != 0x8090)
Olivier Grenie0c32dbd2011-08-10 05:17:18 -03001134 dib8000_set_adc_state(state, DIBX000_SLOW_ADC_OFF);
Patrick Boettcher173a64c2013-04-22 12:45:52 -03001135
1136 /* ber_rs_len = 3 */
1137 dib8000_write_word(state, 285, (dib8000_read_word(state, 285) & ~0x60) | (3 << 5));
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001138
Olivier Grenie0c32dbd2011-08-10 05:17:18 -03001139 dib8000_set_power_mode(state, DIB8000_POWER_INTERFACE_ONLY);
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001140
Mauro Carvalho Chehab6ef06e72013-12-16 19:10:59 -03001141 dib8000_reset_stats(fe);
1142
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001143 return 0;
1144}
1145
1146static void dib8000_restart_agc(struct dib8000_state *state)
1147{
1148 // P_restart_iqc & P_restart_agc
1149 dib8000_write_word(state, 770, 0x0a00);
1150 dib8000_write_word(state, 770, 0x0000);
1151}
1152
1153static int dib8000_update_lna(struct dib8000_state *state)
1154{
1155 u16 dyn_gain;
1156
1157 if (state->cfg.update_lna) {
1158 // read dyn_gain here (because it is demod-dependent and not tuner)
1159 dyn_gain = dib8000_read_word(state, 390);
1160
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001161 if (state->cfg.update_lna(state->fe[0], dyn_gain)) {
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001162 dib8000_restart_agc(state);
1163 return 1;
1164 }
1165 }
1166 return 0;
1167}
1168
1169static int dib8000_set_agc_config(struct dib8000_state *state, u8 band)
1170{
1171 struct dibx000_agc_config *agc = NULL;
1172 int i;
Olivier Grenie0c32dbd2011-08-10 05:17:18 -03001173 u16 reg;
1174
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001175 if (state->current_band == band && state->current_agc != NULL)
1176 return 0;
1177 state->current_band = band;
1178
1179 for (i = 0; i < state->cfg.agc_config_count; i++)
1180 if (state->cfg.agc[i].band_caps & band) {
1181 agc = &state->cfg.agc[i];
1182 break;
1183 }
1184
1185 if (agc == NULL) {
Mauro Carvalho Chehab8af16ad2016-10-14 10:05:46 -03001186 dprintk("no valid AGC configuration found for band 0x%02x\n", band);
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001187 return -EINVAL;
1188 }
1189
1190 state->current_agc = agc;
1191
1192 /* AGC */
1193 dib8000_write_word(state, 76, agc->setup);
1194 dib8000_write_word(state, 77, agc->inv_gain);
1195 dib8000_write_word(state, 78, agc->time_stabiliz);
1196 dib8000_write_word(state, 101, (agc->alpha_level << 12) | agc->thlock);
1197
1198 // Demod AGC loop configuration
1199 dib8000_write_word(state, 102, (agc->alpha_mant << 5) | agc->alpha_exp);
1200 dib8000_write_word(state, 103, (agc->beta_mant << 6) | agc->beta_exp);
1201
Mauro Carvalho Chehab8af16ad2016-10-14 10:05:46 -03001202 dprintk("WBD: ref: %d, sel: %d, active: %d, alpha: %d\n",
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001203 state->wbd_ref != 0 ? state->wbd_ref : agc->wbd_ref, agc->wbd_sel, !agc->perform_agc_softsplit, agc->wbd_sel);
1204
1205 /* AGC continued */
1206 if (state->wbd_ref != 0)
1207 dib8000_write_word(state, 106, state->wbd_ref);
1208 else // use default
1209 dib8000_write_word(state, 106, agc->wbd_ref);
Olivier Grenie0c32dbd2011-08-10 05:17:18 -03001210
1211 if (state->revision == 0x8090) {
1212 reg = dib8000_read_word(state, 922) & (0x3 << 2);
1213 dib8000_write_word(state, 922, reg | (agc->wbd_sel << 2));
1214 }
1215
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001216 dib8000_write_word(state, 107, (agc->wbd_alpha << 9) | (agc->perform_agc_softsplit << 8));
1217 dib8000_write_word(state, 108, agc->agc1_max);
1218 dib8000_write_word(state, 109, agc->agc1_min);
1219 dib8000_write_word(state, 110, agc->agc2_max);
1220 dib8000_write_word(state, 111, agc->agc2_min);
1221 dib8000_write_word(state, 112, (agc->agc1_pt1 << 8) | agc->agc1_pt2);
1222 dib8000_write_word(state, 113, (agc->agc1_slope1 << 8) | agc->agc1_slope2);
1223 dib8000_write_word(state, 114, (agc->agc2_pt1 << 8) | agc->agc2_pt2);
1224 dib8000_write_word(state, 115, (agc->agc2_slope1 << 8) | agc->agc2_slope2);
1225
1226 dib8000_write_word(state, 75, agc->agc1_pt3);
Olivier Grenie0c32dbd2011-08-10 05:17:18 -03001227 if (state->revision != 0x8090)
1228 dib8000_write_word(state, 923,
1229 (dib8000_read_word(state, 923) & 0xffe3) |
1230 (agc->wbd_inv << 4) | (agc->wbd_sel << 2));
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001231
1232 return 0;
1233}
1234
Mauro Carvalho Chehabd44913c2014-05-29 09:20:17 -03001235static void dib8000_pwm_agc_reset(struct dvb_frontend *fe)
Olivier Grenie03245a52009-12-04 13:27:57 -03001236{
1237 struct dib8000_state *state = fe->demodulator_priv;
1238 dib8000_set_adc_state(state, DIBX000_ADC_ON);
1239 dib8000_set_agc_config(state, (unsigned char)(BAND_OF_FREQUENCY(fe->dtv_property_cache.frequency / 1000)));
1240}
Olivier Grenie03245a52009-12-04 13:27:57 -03001241
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001242static int dib8000_agc_soft_split(struct dib8000_state *state)
1243{
1244 u16 agc, split_offset;
1245
1246 if (!state->current_agc || !state->current_agc->perform_agc_softsplit || state->current_agc->split.max == 0)
Mauro Carvalho Chehabd6c62b72014-07-04 14:15:37 -03001247 return 0;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001248
1249 // n_agc_global
1250 agc = dib8000_read_word(state, 390);
1251
1252 if (agc > state->current_agc->split.min_thres)
1253 split_offset = state->current_agc->split.min;
1254 else if (agc < state->current_agc->split.max_thres)
1255 split_offset = state->current_agc->split.max;
1256 else
1257 split_offset = state->current_agc->split.max *
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001258 (agc - state->current_agc->split.min_thres) /
1259 (state->current_agc->split.max_thres - state->current_agc->split.min_thres);
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001260
Mauro Carvalho Chehab8af16ad2016-10-14 10:05:46 -03001261 dprintk("AGC split_offset: %d\n", split_offset);
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001262
1263 // P_agc_force_split and P_agc_split_offset
1264 dib8000_write_word(state, 107, (dib8000_read_word(state, 107) & 0xff00) | split_offset);
1265 return 5000;
1266}
1267
1268static int dib8000_agc_startup(struct dvb_frontend *fe)
1269{
1270 struct dib8000_state *state = fe->demodulator_priv;
1271 enum frontend_tune_state *tune_state = &state->tune_state;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001272 int ret = 0;
Mauro Carvalho Chehab901c4ad2014-12-23 11:21:12 -03001273 u16 reg;
1274 u32 upd_demod_gain_period = 0x8000;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001275
1276 switch (*tune_state) {
1277 case CT_AGC_START:
1278 // set power-up level: interf+analog+AGC
1279
Olivier Grenie0c32dbd2011-08-10 05:17:18 -03001280 if (state->revision != 0x8090)
1281 dib8000_set_adc_state(state, DIBX000_ADC_ON);
1282 else {
1283 dib8000_set_power_mode(state, DIB8000_POWER_ALL);
1284
1285 reg = dib8000_read_word(state, 1947)&0xff00;
1286 dib8000_write_word(state, 1946,
1287 upd_demod_gain_period & 0xFFFF);
1288 /* bit 14 = enDemodGain */
1289 dib8000_write_word(state, 1947, reg | (1<<14) |
1290 ((upd_demod_gain_period >> 16) & 0xFF));
1291
1292 /* enable adc i & q */
1293 reg = dib8000_read_word(state, 1920);
1294 dib8000_write_word(state, 1920, (reg | 0x3) &
1295 (~(1 << 7)));
1296 }
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001297
1298 if (dib8000_set_agc_config(state, (unsigned char)(BAND_OF_FREQUENCY(fe->dtv_property_cache.frequency / 1000))) != 0) {
1299 *tune_state = CT_AGC_STOP;
1300 state->status = FE_STATUS_TUNE_FAILED;
1301 break;
1302 }
1303
1304 ret = 70;
1305 *tune_state = CT_AGC_STEP_0;
1306 break;
1307
1308 case CT_AGC_STEP_0:
1309 //AGC initialization
1310 if (state->cfg.agc_control)
Olivier Grenie4c70e072011-01-03 15:33:37 -03001311 state->cfg.agc_control(fe, 1);
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001312
1313 dib8000_restart_agc(state);
1314
1315 // wait AGC rough lock time
1316 ret = 50;
1317 *tune_state = CT_AGC_STEP_1;
1318 break;
1319
1320 case CT_AGC_STEP_1:
1321 // wait AGC accurate lock time
1322 ret = 70;
1323
1324 if (dib8000_update_lna(state))
1325 // wait only AGC rough lock time
1326 ret = 50;
1327 else
1328 *tune_state = CT_AGC_STEP_2;
1329 break;
1330
1331 case CT_AGC_STEP_2:
1332 dib8000_agc_soft_split(state);
1333
1334 if (state->cfg.agc_control)
Olivier Grenie4c70e072011-01-03 15:33:37 -03001335 state->cfg.agc_control(fe, 0);
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001336
1337 *tune_state = CT_AGC_STOP;
1338 break;
1339 default:
1340 ret = dib8000_agc_soft_split(state);
1341 break;
1342 }
1343 return ret;
1344
1345}
1346
Olivier Grenie0c32dbd2011-08-10 05:17:18 -03001347static void dib8096p_host_bus_drive(struct dib8000_state *state, u8 drive)
1348{
1349 u16 reg;
1350
1351 drive &= 0x7;
1352
1353 /* drive host bus 2, 3, 4 */
1354 reg = dib8000_read_word(state, 1798) &
1355 ~(0x7 | (0x7 << 6) | (0x7 << 12));
1356 reg |= (drive<<12) | (drive<<6) | drive;
1357 dib8000_write_word(state, 1798, reg);
1358
1359 /* drive host bus 5,6 */
1360 reg = dib8000_read_word(state, 1799) & ~((0x7 << 2) | (0x7 << 8));
1361 reg |= (drive<<8) | (drive<<2);
1362 dib8000_write_word(state, 1799, reg);
1363
1364 /* drive host bus 7, 8, 9 */
1365 reg = dib8000_read_word(state, 1800) &
1366 ~(0x7 | (0x7 << 6) | (0x7 << 12));
1367 reg |= (drive<<12) | (drive<<6) | drive;
1368 dib8000_write_word(state, 1800, reg);
1369
1370 /* drive host bus 10, 11 */
1371 reg = dib8000_read_word(state, 1801) & ~((0x7 << 2) | (0x7 << 8));
1372 reg |= (drive<<8) | (drive<<2);
1373 dib8000_write_word(state, 1801, reg);
1374
1375 /* drive host bus 12, 13, 14 */
1376 reg = dib8000_read_word(state, 1802) &
1377 ~(0x7 | (0x7 << 6) | (0x7 << 12));
1378 reg |= (drive<<12) | (drive<<6) | drive;
1379 dib8000_write_word(state, 1802, reg);
1380}
1381
1382static u32 dib8096p_calcSyncFreq(u32 P_Kin, u32 P_Kout,
1383 u32 insertExtSynchro, u32 syncSize)
1384{
1385 u32 quantif = 3;
1386 u32 nom = (insertExtSynchro * P_Kin+syncSize);
1387 u32 denom = P_Kout;
1388 u32 syncFreq = ((nom << quantif) / denom);
1389
1390 if ((syncFreq & ((1 << quantif) - 1)) != 0)
1391 syncFreq = (syncFreq >> quantif) + 1;
1392 else
1393 syncFreq = (syncFreq >> quantif);
1394
1395 if (syncFreq != 0)
1396 syncFreq = syncFreq - 1;
1397
1398 return syncFreq;
1399}
1400
1401static void dib8096p_cfg_DibTx(struct dib8000_state *state, u32 P_Kin,
1402 u32 P_Kout, u32 insertExtSynchro, u32 synchroMode,
1403 u32 syncWord, u32 syncSize)
1404{
Mauro Carvalho Chehab8af16ad2016-10-14 10:05:46 -03001405 dprintk("Configure DibStream Tx\n");
Olivier Grenie0c32dbd2011-08-10 05:17:18 -03001406
1407 dib8000_write_word(state, 1615, 1);
1408 dib8000_write_word(state, 1603, P_Kin);
1409 dib8000_write_word(state, 1605, P_Kout);
1410 dib8000_write_word(state, 1606, insertExtSynchro);
1411 dib8000_write_word(state, 1608, synchroMode);
1412 dib8000_write_word(state, 1609, (syncWord >> 16) & 0xffff);
1413 dib8000_write_word(state, 1610, syncWord & 0xffff);
1414 dib8000_write_word(state, 1612, syncSize);
1415 dib8000_write_word(state, 1615, 0);
1416}
1417
1418static void dib8096p_cfg_DibRx(struct dib8000_state *state, u32 P_Kin,
1419 u32 P_Kout, u32 synchroMode, u32 insertExtSynchro,
1420 u32 syncWord, u32 syncSize, u32 dataOutRate)
1421{
1422 u32 syncFreq;
1423
Mauro Carvalho Chehab8af16ad2016-10-14 10:05:46 -03001424 dprintk("Configure DibStream Rx synchroMode = %d\n", synchroMode);
Olivier Grenie0c32dbd2011-08-10 05:17:18 -03001425
1426 if ((P_Kin != 0) && (P_Kout != 0)) {
1427 syncFreq = dib8096p_calcSyncFreq(P_Kin, P_Kout,
1428 insertExtSynchro, syncSize);
1429 dib8000_write_word(state, 1542, syncFreq);
1430 }
1431
1432 dib8000_write_word(state, 1554, 1);
1433 dib8000_write_word(state, 1536, P_Kin);
1434 dib8000_write_word(state, 1537, P_Kout);
1435 dib8000_write_word(state, 1539, synchroMode);
1436 dib8000_write_word(state, 1540, (syncWord >> 16) & 0xffff);
1437 dib8000_write_word(state, 1541, syncWord & 0xffff);
1438 dib8000_write_word(state, 1543, syncSize);
1439 dib8000_write_word(state, 1544, dataOutRate);
1440 dib8000_write_word(state, 1554, 0);
1441}
1442
1443static void dib8096p_enMpegMux(struct dib8000_state *state, int onoff)
1444{
1445 u16 reg_1287;
1446
1447 reg_1287 = dib8000_read_word(state, 1287);
1448
1449 switch (onoff) {
1450 case 1:
1451 reg_1287 &= ~(1 << 8);
1452 break;
1453 case 0:
1454 reg_1287 |= (1 << 8);
1455 break;
1456 }
1457
1458 dib8000_write_word(state, 1287, reg_1287);
1459}
1460
1461static void dib8096p_configMpegMux(struct dib8000_state *state,
1462 u16 pulseWidth, u16 enSerialMode, u16 enSerialClkDiv2)
1463{
1464 u16 reg_1287;
1465
Mauro Carvalho Chehab8af16ad2016-10-14 10:05:46 -03001466 dprintk("Enable Mpeg mux\n");
Olivier Grenie0c32dbd2011-08-10 05:17:18 -03001467
1468 dib8096p_enMpegMux(state, 0);
1469
1470 /* If the input mode is MPEG do not divide the serial clock */
1471 if ((enSerialMode == 1) && (state->input_mode_mpeg == 1))
1472 enSerialClkDiv2 = 0;
1473
1474 reg_1287 = ((pulseWidth & 0x1f) << 3) |
1475 ((enSerialMode & 0x1) << 2) | (enSerialClkDiv2 & 0x1);
1476 dib8000_write_word(state, 1287, reg_1287);
1477
1478 dib8096p_enMpegMux(state, 1);
1479}
1480
1481static void dib8096p_setDibTxMux(struct dib8000_state *state, int mode)
1482{
1483 u16 reg_1288 = dib8000_read_word(state, 1288) & ~(0x7 << 7);
1484
1485 switch (mode) {
1486 case MPEG_ON_DIBTX:
Mauro Carvalho Chehab8af16ad2016-10-14 10:05:46 -03001487 dprintk("SET MPEG ON DIBSTREAM TX\n");
Olivier Grenie0c32dbd2011-08-10 05:17:18 -03001488 dib8096p_cfg_DibTx(state, 8, 5, 0, 0, 0, 0);
1489 reg_1288 |= (1 << 9); break;
1490 case DIV_ON_DIBTX:
Mauro Carvalho Chehab8af16ad2016-10-14 10:05:46 -03001491 dprintk("SET DIV_OUT ON DIBSTREAM TX\n");
Olivier Grenie0c32dbd2011-08-10 05:17:18 -03001492 dib8096p_cfg_DibTx(state, 5, 5, 0, 0, 0, 0);
1493 reg_1288 |= (1 << 8); break;
1494 case ADC_ON_DIBTX:
Mauro Carvalho Chehab8af16ad2016-10-14 10:05:46 -03001495 dprintk("SET ADC_OUT ON DIBSTREAM TX\n");
Olivier Grenie0c32dbd2011-08-10 05:17:18 -03001496 dib8096p_cfg_DibTx(state, 20, 5, 10, 0, 0, 0);
1497 reg_1288 |= (1 << 7); break;
1498 default:
1499 break;
1500 }
1501 dib8000_write_word(state, 1288, reg_1288);
1502}
1503
1504static void dib8096p_setHostBusMux(struct dib8000_state *state, int mode)
1505{
1506 u16 reg_1288 = dib8000_read_word(state, 1288) & ~(0x7 << 4);
1507
1508 switch (mode) {
1509 case DEMOUT_ON_HOSTBUS:
Mauro Carvalho Chehab8af16ad2016-10-14 10:05:46 -03001510 dprintk("SET DEM OUT OLD INTERF ON HOST BUS\n");
Olivier Grenie0c32dbd2011-08-10 05:17:18 -03001511 dib8096p_enMpegMux(state, 0);
1512 reg_1288 |= (1 << 6);
1513 break;
1514 case DIBTX_ON_HOSTBUS:
Mauro Carvalho Chehab8af16ad2016-10-14 10:05:46 -03001515 dprintk("SET DIBSTREAM TX ON HOST BUS\n");
Olivier Grenie0c32dbd2011-08-10 05:17:18 -03001516 dib8096p_enMpegMux(state, 0);
1517 reg_1288 |= (1 << 5);
1518 break;
1519 case MPEG_ON_HOSTBUS:
Mauro Carvalho Chehab8af16ad2016-10-14 10:05:46 -03001520 dprintk("SET MPEG MUX ON HOST BUS\n");
Olivier Grenie0c32dbd2011-08-10 05:17:18 -03001521 reg_1288 |= (1 << 4);
1522 break;
1523 default:
1524 break;
1525 }
1526 dib8000_write_word(state, 1288, reg_1288);
1527}
1528
1529static int dib8096p_set_diversity_in(struct dvb_frontend *fe, int onoff)
1530{
1531 struct dib8000_state *state = fe->demodulator_priv;
1532 u16 reg_1287;
1533
1534 switch (onoff) {
1535 case 0: /* only use the internal way - not the diversity input */
Mauro Carvalho Chehab8af16ad2016-10-14 10:05:46 -03001536 dprintk("%s mode OFF : by default Enable Mpeg INPUT\n",
Olivier Grenie0c32dbd2011-08-10 05:17:18 -03001537 __func__);
1538 /* outputRate = 8 */
1539 dib8096p_cfg_DibRx(state, 8, 5, 0, 0, 0, 8, 0);
1540
1541 /* Do not divide the serial clock of MPEG MUX in
1542 SERIAL MODE in case input mode MPEG is used */
1543 reg_1287 = dib8000_read_word(state, 1287);
1544 /* enSerialClkDiv2 == 1 ? */
1545 if ((reg_1287 & 0x1) == 1) {
1546 /* force enSerialClkDiv2 = 0 */
1547 reg_1287 &= ~0x1;
1548 dib8000_write_word(state, 1287, reg_1287);
1549 }
1550 state->input_mode_mpeg = 1;
1551 break;
1552 case 1: /* both ways */
1553 case 2: /* only the diversity input */
Mauro Carvalho Chehab8af16ad2016-10-14 10:05:46 -03001554 dprintk("%s ON : Enable diversity INPUT\n", __func__);
Olivier Grenie0c32dbd2011-08-10 05:17:18 -03001555 dib8096p_cfg_DibRx(state, 5, 5, 0, 0, 0, 0, 0);
1556 state->input_mode_mpeg = 0;
1557 break;
1558 }
1559
1560 dib8000_set_diversity_in(state->fe[0], onoff);
1561 return 0;
1562}
1563
1564static int dib8096p_set_output_mode(struct dvb_frontend *fe, int mode)
1565{
1566 struct dib8000_state *state = fe->demodulator_priv;
1567 u16 outreg, smo_mode, fifo_threshold;
1568 u8 prefer_mpeg_mux_use = 1;
1569 int ret = 0;
1570
Patrick Boettcher173a64c2013-04-22 12:45:52 -03001571 state->output_mode = mode;
Olivier Grenie0c32dbd2011-08-10 05:17:18 -03001572 dib8096p_host_bus_drive(state, 1);
1573
1574 fifo_threshold = 1792;
1575 smo_mode = (dib8000_read_word(state, 299) & 0x0050) | (1 << 1);
1576 outreg = dib8000_read_word(state, 1286) &
1577 ~((1 << 10) | (0x7 << 6) | (1 << 1));
1578
1579 switch (mode) {
1580 case OUTMODE_HIGH_Z:
1581 outreg = 0;
1582 break;
1583
1584 case OUTMODE_MPEG2_SERIAL:
1585 if (prefer_mpeg_mux_use) {
Mauro Carvalho Chehab8af16ad2016-10-14 10:05:46 -03001586 dprintk("dib8096P setting output mode TS_SERIAL using Mpeg Mux\n");
Olivier Grenie0c32dbd2011-08-10 05:17:18 -03001587 dib8096p_configMpegMux(state, 3, 1, 1);
1588 dib8096p_setHostBusMux(state, MPEG_ON_HOSTBUS);
1589 } else {/* Use Smooth block */
Mauro Carvalho Chehab8af16ad2016-10-14 10:05:46 -03001590 dprintk("dib8096P setting output mode TS_SERIAL using Smooth bloc\n");
Olivier Grenie0c32dbd2011-08-10 05:17:18 -03001591 dib8096p_setHostBusMux(state,
1592 DEMOUT_ON_HOSTBUS);
1593 outreg |= (2 << 6) | (0 << 1);
1594 }
1595 break;
1596
1597 case OUTMODE_MPEG2_PAR_GATED_CLK:
1598 if (prefer_mpeg_mux_use) {
Mauro Carvalho Chehab8af16ad2016-10-14 10:05:46 -03001599 dprintk("dib8096P setting output mode TS_PARALLEL_GATED using Mpeg Mux\n");
Olivier Grenie0c32dbd2011-08-10 05:17:18 -03001600 dib8096p_configMpegMux(state, 2, 0, 0);
1601 dib8096p_setHostBusMux(state, MPEG_ON_HOSTBUS);
1602 } else { /* Use Smooth block */
Mauro Carvalho Chehab8af16ad2016-10-14 10:05:46 -03001603 dprintk("dib8096P setting output mode TS_PARALLEL_GATED using Smooth block\n");
Olivier Grenie0c32dbd2011-08-10 05:17:18 -03001604 dib8096p_setHostBusMux(state,
1605 DEMOUT_ON_HOSTBUS);
1606 outreg |= (0 << 6);
1607 }
1608 break;
1609
1610 case OUTMODE_MPEG2_PAR_CONT_CLK: /* Using Smooth block only */
Mauro Carvalho Chehab8af16ad2016-10-14 10:05:46 -03001611 dprintk("dib8096P setting output mode TS_PARALLEL_CONT using Smooth block\n");
Olivier Grenie0c32dbd2011-08-10 05:17:18 -03001612 dib8096p_setHostBusMux(state, DEMOUT_ON_HOSTBUS);
1613 outreg |= (1 << 6);
1614 break;
1615
1616 case OUTMODE_MPEG2_FIFO:
1617 /* Using Smooth block because not supported
1618 by new Mpeg Mux bloc */
Mauro Carvalho Chehab8af16ad2016-10-14 10:05:46 -03001619 dprintk("dib8096P setting output mode TS_FIFO using Smooth block\n");
Olivier Grenie0c32dbd2011-08-10 05:17:18 -03001620 dib8096p_setHostBusMux(state, DEMOUT_ON_HOSTBUS);
1621 outreg |= (5 << 6);
1622 smo_mode |= (3 << 1);
1623 fifo_threshold = 512;
1624 break;
1625
1626 case OUTMODE_DIVERSITY:
Mauro Carvalho Chehab8af16ad2016-10-14 10:05:46 -03001627 dprintk("dib8096P setting output mode MODE_DIVERSITY\n");
Olivier Grenie0c32dbd2011-08-10 05:17:18 -03001628 dib8096p_setDibTxMux(state, DIV_ON_DIBTX);
1629 dib8096p_setHostBusMux(state, DIBTX_ON_HOSTBUS);
1630 break;
1631
1632 case OUTMODE_ANALOG_ADC:
Mauro Carvalho Chehab8af16ad2016-10-14 10:05:46 -03001633 dprintk("dib8096P setting output mode MODE_ANALOG_ADC\n");
Olivier Grenie0c32dbd2011-08-10 05:17:18 -03001634 dib8096p_setDibTxMux(state, ADC_ON_DIBTX);
1635 dib8096p_setHostBusMux(state, DIBTX_ON_HOSTBUS);
1636 break;
1637 }
1638
1639 if (mode != OUTMODE_HIGH_Z)
1640 outreg |= (1<<10);
1641
Mauro Carvalho Chehab8af16ad2016-10-14 10:05:46 -03001642 dprintk("output_mpeg2_in_188_bytes = %d\n",
Olivier Grenie0c32dbd2011-08-10 05:17:18 -03001643 state->cfg.output_mpeg2_in_188_bytes);
1644 if (state->cfg.output_mpeg2_in_188_bytes)
1645 smo_mode |= (1 << 5);
1646
1647 ret |= dib8000_write_word(state, 299, smo_mode);
1648 /* synchronous fread */
1649 ret |= dib8000_write_word(state, 299 + 1, fifo_threshold);
1650 ret |= dib8000_write_word(state, 1286, outreg);
1651
1652 return ret;
1653}
1654
1655static int map_addr_to_serpar_number(struct i2c_msg *msg)
1656{
1657 if (msg->buf[0] <= 15)
1658 msg->buf[0] -= 1;
1659 else if (msg->buf[0] == 17)
1660 msg->buf[0] = 15;
1661 else if (msg->buf[0] == 16)
1662 msg->buf[0] = 17;
1663 else if (msg->buf[0] == 19)
1664 msg->buf[0] = 16;
1665 else if (msg->buf[0] >= 21 && msg->buf[0] <= 25)
1666 msg->buf[0] -= 3;
1667 else if (msg->buf[0] == 28)
1668 msg->buf[0] = 23;
1669 else if (msg->buf[0] == 99)
1670 msg->buf[0] = 99;
1671 else
1672 return -EINVAL;
1673 return 0;
1674}
1675
1676static int dib8096p_tuner_write_serpar(struct i2c_adapter *i2c_adap,
1677 struct i2c_msg msg[], int num)
1678{
1679 struct dib8000_state *state = i2c_get_adapdata(i2c_adap);
1680 u8 n_overflow = 1;
1681 u16 i = 1000;
1682 u16 serpar_num = msg[0].buf[0];
1683
1684 while (n_overflow == 1 && i) {
1685 n_overflow = (dib8000_read_word(state, 1984) >> 1) & 0x1;
1686 i--;
1687 if (i == 0)
Mauro Carvalho Chehab8af16ad2016-10-14 10:05:46 -03001688 dprintk("Tuner ITF: write busy (overflow)\n");
Olivier Grenie0c32dbd2011-08-10 05:17:18 -03001689 }
1690 dib8000_write_word(state, 1985, (1 << 6) | (serpar_num & 0x3f));
1691 dib8000_write_word(state, 1986, (msg[0].buf[1] << 8) | msg[0].buf[2]);
1692
1693 return num;
1694}
1695
1696static int dib8096p_tuner_read_serpar(struct i2c_adapter *i2c_adap,
1697 struct i2c_msg msg[], int num)
1698{
1699 struct dib8000_state *state = i2c_get_adapdata(i2c_adap);
1700 u8 n_overflow = 1, n_empty = 1;
1701 u16 i = 1000;
1702 u16 serpar_num = msg[0].buf[0];
1703 u16 read_word;
1704
1705 while (n_overflow == 1 && i) {
1706 n_overflow = (dib8000_read_word(state, 1984) >> 1) & 0x1;
1707 i--;
1708 if (i == 0)
Mauro Carvalho Chehab8af16ad2016-10-14 10:05:46 -03001709 dprintk("TunerITF: read busy (overflow)\n");
Olivier Grenie0c32dbd2011-08-10 05:17:18 -03001710 }
1711 dib8000_write_word(state, 1985, (0<<6) | (serpar_num&0x3f));
1712
1713 i = 1000;
1714 while (n_empty == 1 && i) {
1715 n_empty = dib8000_read_word(state, 1984)&0x1;
1716 i--;
1717 if (i == 0)
Mauro Carvalho Chehab8af16ad2016-10-14 10:05:46 -03001718 dprintk("TunerITF: read busy (empty)\n");
Olivier Grenie0c32dbd2011-08-10 05:17:18 -03001719 }
1720
1721 read_word = dib8000_read_word(state, 1987);
1722 msg[1].buf[0] = (read_word >> 8) & 0xff;
1723 msg[1].buf[1] = (read_word) & 0xff;
1724
1725 return num;
1726}
1727
1728static int dib8096p_tuner_rw_serpar(struct i2c_adapter *i2c_adap,
1729 struct i2c_msg msg[], int num)
1730{
1731 if (map_addr_to_serpar_number(&msg[0]) == 0) {
1732 if (num == 1) /* write */
1733 return dib8096p_tuner_write_serpar(i2c_adap, msg, 1);
1734 else /* read */
1735 return dib8096p_tuner_read_serpar(i2c_adap, msg, 2);
1736 }
1737 return num;
1738}
1739
1740static int dib8096p_rw_on_apb(struct i2c_adapter *i2c_adap,
1741 struct i2c_msg msg[], int num, u16 apb_address)
1742{
1743 struct dib8000_state *state = i2c_get_adapdata(i2c_adap);
1744 u16 word;
1745
1746 if (num == 1) { /* write */
1747 dib8000_write_word(state, apb_address,
1748 ((msg[0].buf[1] << 8) | (msg[0].buf[2])));
1749 } else {
1750 word = dib8000_read_word(state, apb_address);
1751 msg[1].buf[0] = (word >> 8) & 0xff;
1752 msg[1].buf[1] = (word) & 0xff;
1753 }
1754 return num;
1755}
1756
1757static int dib8096p_tuner_xfer(struct i2c_adapter *i2c_adap,
1758 struct i2c_msg msg[], int num)
1759{
1760 struct dib8000_state *state = i2c_get_adapdata(i2c_adap);
1761 u16 apb_address = 0, word;
1762 int i = 0;
1763
1764 switch (msg[0].buf[0]) {
1765 case 0x12:
1766 apb_address = 1920;
1767 break;
1768 case 0x14:
1769 apb_address = 1921;
1770 break;
1771 case 0x24:
1772 apb_address = 1922;
1773 break;
1774 case 0x1a:
1775 apb_address = 1923;
1776 break;
1777 case 0x22:
1778 apb_address = 1924;
1779 break;
1780 case 0x33:
1781 apb_address = 1926;
1782 break;
1783 case 0x34:
1784 apb_address = 1927;
1785 break;
1786 case 0x35:
1787 apb_address = 1928;
1788 break;
1789 case 0x36:
1790 apb_address = 1929;
1791 break;
1792 case 0x37:
1793 apb_address = 1930;
1794 break;
1795 case 0x38:
1796 apb_address = 1931;
1797 break;
1798 case 0x39:
1799 apb_address = 1932;
1800 break;
1801 case 0x2a:
1802 apb_address = 1935;
1803 break;
1804 case 0x2b:
1805 apb_address = 1936;
1806 break;
1807 case 0x2c:
1808 apb_address = 1937;
1809 break;
1810 case 0x2d:
1811 apb_address = 1938;
1812 break;
1813 case 0x2e:
1814 apb_address = 1939;
1815 break;
1816 case 0x2f:
1817 apb_address = 1940;
1818 break;
1819 case 0x30:
1820 apb_address = 1941;
1821 break;
1822 case 0x31:
1823 apb_address = 1942;
1824 break;
1825 case 0x32:
1826 apb_address = 1943;
1827 break;
1828 case 0x3e:
1829 apb_address = 1944;
1830 break;
1831 case 0x3f:
1832 apb_address = 1945;
1833 break;
1834 case 0x40:
1835 apb_address = 1948;
1836 break;
1837 case 0x25:
1838 apb_address = 936;
1839 break;
1840 case 0x26:
1841 apb_address = 937;
1842 break;
1843 case 0x27:
1844 apb_address = 938;
1845 break;
1846 case 0x28:
1847 apb_address = 939;
1848 break;
1849 case 0x1d:
1850 /* get sad sel request */
1851 i = ((dib8000_read_word(state, 921) >> 12)&0x3);
1852 word = dib8000_read_word(state, 924+i);
1853 msg[1].buf[0] = (word >> 8) & 0xff;
1854 msg[1].buf[1] = (word) & 0xff;
1855 return num;
1856 case 0x1f:
1857 if (num == 1) { /* write */
1858 word = (u16) ((msg[0].buf[1] << 8) |
1859 msg[0].buf[2]);
1860 /* in the VGAMODE Sel are located on bit 0/1 */
1861 word &= 0x3;
1862 word = (dib8000_read_word(state, 921) &
1863 ~(3<<12)) | (word<<12);
1864 /* Set the proper input */
1865 dib8000_write_word(state, 921, word);
1866 return num;
1867 }
1868 }
1869
1870 if (apb_address != 0) /* R/W acces via APB */
1871 return dib8096p_rw_on_apb(i2c_adap, msg, num, apb_address);
1872 else /* R/W access via SERPAR */
1873 return dib8096p_tuner_rw_serpar(i2c_adap, msg, num);
1874
1875 return 0;
1876}
1877
1878static u32 dib8096p_i2c_func(struct i2c_adapter *adapter)
1879{
1880 return I2C_FUNC_I2C;
1881}
1882
1883static struct i2c_algorithm dib8096p_tuner_xfer_algo = {
1884 .master_xfer = dib8096p_tuner_xfer,
1885 .functionality = dib8096p_i2c_func,
1886};
1887
Mauro Carvalho Chehabd44913c2014-05-29 09:20:17 -03001888static struct i2c_adapter *dib8096p_get_i2c_tuner(struct dvb_frontend *fe)
Olivier Grenie0c32dbd2011-08-10 05:17:18 -03001889{
1890 struct dib8000_state *st = fe->demodulator_priv;
1891 return &st->dib8096p_tuner_adap;
1892}
Olivier Grenie0c32dbd2011-08-10 05:17:18 -03001893
Mauro Carvalho Chehabd44913c2014-05-29 09:20:17 -03001894static int dib8096p_tuner_sleep(struct dvb_frontend *fe, int onoff)
Olivier Grenie0c32dbd2011-08-10 05:17:18 -03001895{
1896 struct dib8000_state *state = fe->demodulator_priv;
1897 u16 en_cur_state;
1898
Mauro Carvalho Chehab8af16ad2016-10-14 10:05:46 -03001899 dprintk("sleep dib8096p: %d\n", onoff);
Olivier Grenie0c32dbd2011-08-10 05:17:18 -03001900
1901 en_cur_state = dib8000_read_word(state, 1922);
1902
1903 /* LNAs and MIX are ON and therefore it is a valid configuration */
1904 if (en_cur_state > 0xff)
1905 state->tuner_enable = en_cur_state ;
1906
1907 if (onoff)
1908 en_cur_state &= 0x00ff;
1909 else {
1910 if (state->tuner_enable != 0)
1911 en_cur_state = state->tuner_enable;
1912 }
1913
1914 dib8000_write_word(state, 1922, en_cur_state);
1915
1916 return 0;
1917}
Olivier Grenie0c32dbd2011-08-10 05:17:18 -03001918
Olivier Grenie4c70e072011-01-03 15:33:37 -03001919static const s32 lut_1000ln_mant[] =
Olivier Grenie03245a52009-12-04 13:27:57 -03001920{
Olivier Grenie9c783032009-12-07 07:49:40 -03001921 908, 7003, 7090, 7170, 7244, 7313, 7377, 7438, 7495, 7549, 7600
Olivier Grenie03245a52009-12-04 13:27:57 -03001922};
1923
Mauro Carvalho Chehabd44913c2014-05-29 09:20:17 -03001924static s32 dib8000_get_adc_power(struct dvb_frontend *fe, u8 mode)
Olivier Grenie03245a52009-12-04 13:27:57 -03001925{
Olivier Grenie4c70e072011-01-03 15:33:37 -03001926 struct dib8000_state *state = fe->demodulator_priv;
1927 u32 ix = 0, tmp_val = 0, exp = 0, mant = 0;
1928 s32 val;
Olivier Grenie03245a52009-12-04 13:27:57 -03001929
Olivier Grenie4c70e072011-01-03 15:33:37 -03001930 val = dib8000_read32(state, 384);
Olivier Grenie4c70e072011-01-03 15:33:37 -03001931 if (mode) {
1932 tmp_val = val;
1933 while (tmp_val >>= 1)
1934 exp++;
1935 mant = (val * 1000 / (1<<exp));
1936 ix = (u8)((mant-1000)/100); /* index of the LUT */
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001937 val = (lut_1000ln_mant[ix] + 693*(exp-20) - 6908);
Olivier Grenie4c70e072011-01-03 15:33:37 -03001938 val = (val*256)/1000;
1939 }
1940 return val;
Olivier Grenie03245a52009-12-04 13:27:57 -03001941}
Olivier Grenie03245a52009-12-04 13:27:57 -03001942
Mauro Carvalho Chehabd44913c2014-05-29 09:20:17 -03001943static int dib8090p_get_dc_power(struct dvb_frontend *fe, u8 IQ)
Olivier Grenie0c32dbd2011-08-10 05:17:18 -03001944{
1945 struct dib8000_state *state = fe->demodulator_priv;
1946 int val = 0;
1947
1948 switch (IQ) {
1949 case 1:
1950 val = dib8000_read_word(state, 403);
1951 break;
1952 case 0:
1953 val = dib8000_read_word(state, 404);
1954 break;
1955 }
1956 if (val & 0x200)
1957 val -= 1024;
1958
1959 return val;
1960}
Olivier Grenie0c32dbd2011-08-10 05:17:18 -03001961
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001962static void dib8000_update_timf(struct dib8000_state *state)
1963{
1964 u32 timf = state->timf = dib8000_read32(state, 435);
1965
1966 dib8000_write_word(state, 29, (u16) (timf >> 16));
1967 dib8000_write_word(state, 30, (u16) (timf & 0xffff));
Mauro Carvalho Chehab8af16ad2016-10-14 10:05:46 -03001968 dprintk("Updated timing frequency: %d (default: %d)\n", state->timf, state->timf_default);
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001969}
1970
Mauro Carvalho Chehabd44913c2014-05-29 09:20:17 -03001971static u32 dib8000_ctrl_timf(struct dvb_frontend *fe, uint8_t op, uint32_t timf)
Olivier Grenie0c32dbd2011-08-10 05:17:18 -03001972{
1973 struct dib8000_state *state = fe->demodulator_priv;
1974
1975 switch (op) {
1976 case DEMOD_TIMF_SET:
1977 state->timf = timf;
1978 break;
1979 case DEMOD_TIMF_UPDATE:
1980 dib8000_update_timf(state);
1981 break;
1982 case DEMOD_TIMF_GET:
1983 break;
1984 }
1985 dib8000_set_bandwidth(state->fe[0], 6000);
1986
1987 return state->timf;
1988}
Olivier Grenie0c32dbd2011-08-10 05:17:18 -03001989
Olivier Grenie5a0deee2011-05-03 12:27:33 -03001990static const u16 adc_target_16dB[11] = {
Mauro Carvalho Chehaba768f902014-07-04 14:15:38 -03001991 7250, 7238, 7264, 7309, 7338, 7382, 7427, 7456, 7500, 7544, 7574
Olivier Grenie5a0deee2011-05-03 12:27:33 -03001992};
Mauro Carvalho Chehaba768f902014-07-04 14:15:38 -03001993
Olivier Grenie5a0deee2011-05-03 12:27:33 -03001994static const u8 permu_seg[] = { 6, 5, 7, 4, 8, 3, 9, 2, 10, 1, 11, 0, 12 };
1995
Patrick Boettcher173a64c2013-04-22 12:45:52 -03001996static u16 dib8000_set_layer(struct dib8000_state *state, u8 layer_index, u16 max_constellation)
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001997{
Patrick Boettcher173a64c2013-04-22 12:45:52 -03001998 u8 cr, constellation, time_intlv;
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03001999 struct dtv_frontend_properties *c = &state->fe[0]->dtv_property_cache;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002000
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03002001 switch (c->layer[layer_index].modulation) {
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002002 case DQPSK:
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002003 constellation = 0;
2004 break;
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002005 case QPSK:
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002006 constellation = 1;
2007 break;
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002008 case QAM_16:
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002009 constellation = 2;
2010 break;
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002011 case QAM_64:
2012 default:
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002013 constellation = 3;
2014 break;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002015 }
2016
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03002017 switch (c->layer[layer_index].fec) {
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002018 case FEC_1_2:
2019 cr = 1;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002020 break;
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002021 case FEC_2_3:
2022 cr = 2;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002023 break;
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002024 case FEC_3_4:
2025 cr = 3;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002026 break;
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002027 case FEC_5_6:
2028 cr = 5;
2029 break;
2030 case FEC_7_8:
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002031 default:
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002032 cr = 7;
2033 break;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002034 }
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002035
Mauro Carvalho Chehab34ba2e62014-07-04 14:15:27 -03002036 time_intlv = fls(c->layer[layer_index].interleaving);
2037 if (time_intlv > 3 && !(time_intlv == 4 && c->isdbt_sb_mode == 1))
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002038 time_intlv = 0;
2039
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03002040 dib8000_write_word(state, 2 + layer_index, (constellation << 10) | ((c->layer[layer_index].segment_count & 0xf) << 6) | (cr << 3) | time_intlv);
2041 if (c->layer[layer_index].segment_count > 0) {
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002042 switch (max_constellation) {
2043 case DQPSK:
2044 case QPSK:
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03002045 if (c->layer[layer_index].modulation == QAM_16 || c->layer[layer_index].modulation == QAM_64)
2046 max_constellation = c->layer[layer_index].modulation;
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002047 break;
2048 case QAM_16:
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03002049 if (c->layer[layer_index].modulation == QAM_64)
2050 max_constellation = c->layer[layer_index].modulation;
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002051 break;
2052 }
2053 }
2054
2055 return max_constellation;
2056}
2057
2058static const u16 adp_Q64[4] = {0x0148, 0xfff0, 0x00a4, 0xfff8}; /* P_adp_regul_cnt 0.04, P_adp_noise_cnt -0.002, P_adp_regul_ext 0.02, P_adp_noise_ext -0.001 */
2059static const u16 adp_Q16[4] = {0x023d, 0xffdf, 0x00a4, 0xfff0}; /* P_adp_regul_cnt 0.07, P_adp_noise_cnt -0.004, P_adp_regul_ext 0.02, P_adp_noise_ext -0.002 */
2060static const u16 adp_Qdefault[4] = {0x099a, 0xffae, 0x0333, 0xfff8}; /* P_adp_regul_cnt 0.3, P_adp_noise_cnt -0.01, P_adp_regul_ext 0.1, P_adp_noise_ext -0.002 */
2061static u16 dib8000_adp_fine_tune(struct dib8000_state *state, u16 max_constellation)
2062{
2063 u16 i, ana_gain = 0;
2064 const u16 *adp;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002065
2066 /* channel estimation fine configuration */
2067 switch (max_constellation) {
2068 case QAM_64:
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002069 ana_gain = 0x7;
2070 adp = &adp_Q64[0];
2071 break;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002072 case QAM_16:
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002073 ana_gain = 0x7;
2074 adp = &adp_Q16[0];
2075 break;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002076 default:
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002077 ana_gain = 0;
2078 adp = &adp_Qdefault[0];
2079 break;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002080 }
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002081
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002082 for (i = 0; i < 4; i++)
2083 dib8000_write_word(state, 215 + i, adp[i]);
2084
2085 return ana_gain;
2086}
2087
2088static void dib8000_update_ana_gain(struct dib8000_state *state, u16 ana_gain)
2089{
2090 u16 i;
2091
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002092 dib8000_write_word(state, 116, ana_gain);
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002093
2094 /* update ADC target depending on ana_gain */
2095 if (ana_gain) { /* set -16dB ADC target for ana_gain=-1 */
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002096 for (i = 0; i < 10; i++)
2097 dib8000_write_word(state, 80 + i, adc_target_16dB[i]);
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002098 } else { /* set -22dB ADC target for ana_gain=0 */
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002099 for (i = 0; i < 10; i++)
2100 dib8000_write_word(state, 80 + i, adc_target_16dB[i] - 355);
2101 }
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002102}
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002103
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002104static void dib8000_load_ana_fe_coefs(struct dib8000_state *state, const s16 *ana_fe)
2105{
2106 u16 mode = 0;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002107
2108 if (state->isdbt_cfg_loaded == 0)
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002109 for (mode = 0; mode < 24; mode++)
2110 dib8000_write_word(state, 117 + mode, ana_fe[mode]);
2111}
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002112
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002113static const u16 lut_prbs_2k[14] = {
2114 0, 0x423, 0x009, 0x5C7, 0x7A6, 0x3D8, 0x527, 0x7FF, 0x79B, 0x3D6, 0x3A2, 0x53B, 0x2F4, 0x213
2115};
2116static const u16 lut_prbs_4k[14] = {
2117 0, 0x208, 0x0C3, 0x7B9, 0x423, 0x5C7, 0x3D8, 0x7FF, 0x3D6, 0x53B, 0x213, 0x029, 0x0D0, 0x48E
2118};
2119static const u16 lut_prbs_8k[14] = {
2120 0, 0x740, 0x069, 0x7DD, 0x208, 0x7B9, 0x5C7, 0x7FF, 0x53B, 0x029, 0x48E, 0x4C4, 0x367, 0x684
2121};
2122
2123static u16 dib8000_get_init_prbs(struct dib8000_state *state, u16 subchannel)
2124{
2125 int sub_channel_prbs_group = 0;
2126
2127 sub_channel_prbs_group = (subchannel / 3) + 1;
Mauro Carvalho Chehab8af16ad2016-10-14 10:05:46 -03002128 dprintk("sub_channel_prbs_group = %d , subchannel =%d prbs = 0x%04x\n", sub_channel_prbs_group, subchannel, lut_prbs_8k[sub_channel_prbs_group]);
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002129
2130 switch (state->fe[0]->dtv_property_cache.transmission_mode) {
2131 case TRANSMISSION_MODE_2K:
2132 return lut_prbs_2k[sub_channel_prbs_group];
2133 case TRANSMISSION_MODE_4K:
2134 return lut_prbs_4k[sub_channel_prbs_group];
2135 default:
2136 case TRANSMISSION_MODE_8K:
2137 return lut_prbs_8k[sub_channel_prbs_group];
2138 }
2139}
2140
2141static void dib8000_set_13seg_channel(struct dib8000_state *state)
2142{
2143 u16 i;
2144 u16 coff_pow = 0x2800;
2145
2146 state->seg_mask = 0x1fff; /* All 13 segments enabled */
2147
2148 /* ---- COFF ---- Carloff, the most robust --- */
2149 if (state->isdbt_cfg_loaded == 0) { /* if not Sound Broadcasting mode : put default values for 13 segments */
2150 dib8000_write_word(state, 180, (16 << 6) | 9);
2151 dib8000_write_word(state, 187, (4 << 12) | (8 << 5) | 0x2);
2152 coff_pow = 0x2800;
2153 for (i = 0; i < 6; i++)
2154 dib8000_write_word(state, 181+i, coff_pow);
2155
2156 /* P_ctrl_corm_thres4pre_freq_inh=1, P_ctrl_pre_freq_mode_sat=1 */
2157 /* P_ctrl_pre_freq_mode_sat=1, P_ctrl_pre_freq_inh=0, P_ctrl_pre_freq_step = 3, P_pre_freq_win_len=1 */
2158 dib8000_write_word(state, 338, (1 << 12) | (1 << 10) | (0 << 9) | (3 << 5) | 1);
2159
2160 /* P_ctrl_pre_freq_win_len=8, P_ctrl_pre_freq_thres_lockin=6 */
2161 dib8000_write_word(state, 340, (8 << 6) | (6 << 0));
2162 /* P_ctrl_pre_freq_thres_lockout=4, P_small_use_tmcc/ac/cp=1 */
2163 dib8000_write_word(state, 341, (4 << 3) | (1 << 2) | (1 << 1) | (1 << 0));
2164
2165 dib8000_write_word(state, 228, 0); /* default value */
2166 dib8000_write_word(state, 265, 31); /* default value */
2167 dib8000_write_word(state, 205, 0x200f); /* init value */
2168 }
2169
2170 /*
2171 * make the cpil_coff_lock more robust but slower p_coff_winlen
2172 * 6bits; p_coff_thres_lock 6bits (for coff lock if needed)
2173 */
2174
2175 if (state->cfg.pll->ifreq == 0)
2176 dib8000_write_word(state, 266, ~state->seg_mask | state->seg_diff_mask | 0x40); /* P_equal_noise_seg_inh */
2177
2178 dib8000_load_ana_fe_coefs(state, ana_fe_coeff_13seg);
2179}
2180
2181static void dib8000_set_subchannel_prbs(struct dib8000_state *state, u16 init_prbs)
2182{
2183 u16 reg_1;
2184
2185 reg_1 = dib8000_read_word(state, 1);
2186 dib8000_write_word(state, 1, (init_prbs << 2) | (reg_1 & 0x3)); /* ADDR 1 */
2187}
2188
2189static void dib8000_small_fine_tune(struct dib8000_state *state)
2190{
2191 u16 i;
2192 const s16 *ncoeff;
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03002193 struct dtv_frontend_properties *c = &state->fe[0]->dtv_property_cache;
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002194
2195 dib8000_write_word(state, 352, state->seg_diff_mask);
2196 dib8000_write_word(state, 353, state->seg_mask);
2197
2198 /* P_small_coef_ext_enable=ISDB-Tsb, P_small_narrow_band=ISDB-Tsb, P_small_last_seg=13, P_small_offset_num_car=5 */
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03002199 dib8000_write_word(state, 351, (c->isdbt_sb_mode << 9) | (c->isdbt_sb_mode << 8) | (13 << 4) | 5);
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002200
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03002201 if (c->isdbt_sb_mode) {
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002202 /* ---- SMALL ---- */
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03002203 switch (c->transmission_mode) {
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002204 case TRANSMISSION_MODE_2K:
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03002205 if (c->isdbt_partial_reception == 0) { /* 1-seg */
2206 if (c->layer[0].modulation == DQPSK) /* DQPSK */
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002207 ncoeff = coeff_2k_sb_1seg_dqpsk;
2208 else /* QPSK or QAM */
2209 ncoeff = coeff_2k_sb_1seg;
2210 } else { /* 3-segments */
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03002211 if (c->layer[0].modulation == DQPSK) { /* DQPSK on central segment */
2212 if (c->layer[1].modulation == DQPSK) /* DQPSK on external segments */
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002213 ncoeff = coeff_2k_sb_3seg_0dqpsk_1dqpsk;
2214 else /* QPSK or QAM on external segments */
2215 ncoeff = coeff_2k_sb_3seg_0dqpsk;
2216 } else { /* QPSK or QAM on central segment */
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03002217 if (c->layer[1].modulation == DQPSK) /* DQPSK on external segments */
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002218 ncoeff = coeff_2k_sb_3seg_1dqpsk;
2219 else /* QPSK or QAM on external segments */
2220 ncoeff = coeff_2k_sb_3seg;
2221 }
2222 }
2223 break;
2224 case TRANSMISSION_MODE_4K:
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03002225 if (c->isdbt_partial_reception == 0) { /* 1-seg */
2226 if (c->layer[0].modulation == DQPSK) /* DQPSK */
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002227 ncoeff = coeff_4k_sb_1seg_dqpsk;
2228 else /* QPSK or QAM */
2229 ncoeff = coeff_4k_sb_1seg;
2230 } else { /* 3-segments */
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03002231 if (c->layer[0].modulation == DQPSK) { /* DQPSK on central segment */
2232 if (c->layer[1].modulation == DQPSK) /* DQPSK on external segments */
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002233 ncoeff = coeff_4k_sb_3seg_0dqpsk_1dqpsk;
2234 else /* QPSK or QAM on external segments */
2235 ncoeff = coeff_4k_sb_3seg_0dqpsk;
2236 } else { /* QPSK or QAM on central segment */
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03002237 if (c->layer[1].modulation == DQPSK) /* DQPSK on external segments */
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002238 ncoeff = coeff_4k_sb_3seg_1dqpsk;
2239 else /* QPSK or QAM on external segments */
2240 ncoeff = coeff_4k_sb_3seg;
2241 }
2242 }
2243 break;
2244 case TRANSMISSION_MODE_AUTO:
2245 case TRANSMISSION_MODE_8K:
2246 default:
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03002247 if (c->isdbt_partial_reception == 0) { /* 1-seg */
2248 if (c->layer[0].modulation == DQPSK) /* DQPSK */
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002249 ncoeff = coeff_8k_sb_1seg_dqpsk;
2250 else /* QPSK or QAM */
2251 ncoeff = coeff_8k_sb_1seg;
2252 } else { /* 3-segments */
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03002253 if (c->layer[0].modulation == DQPSK) { /* DQPSK on central segment */
2254 if (c->layer[1].modulation == DQPSK) /* DQPSK on external segments */
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002255 ncoeff = coeff_8k_sb_3seg_0dqpsk_1dqpsk;
2256 else /* QPSK or QAM on external segments */
2257 ncoeff = coeff_8k_sb_3seg_0dqpsk;
2258 } else { /* QPSK or QAM on central segment */
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03002259 if (c->layer[1].modulation == DQPSK) /* DQPSK on external segments */
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002260 ncoeff = coeff_8k_sb_3seg_1dqpsk;
2261 else /* QPSK or QAM on external segments */
2262 ncoeff = coeff_8k_sb_3seg;
2263 }
2264 }
2265 break;
2266 }
2267
2268 for (i = 0; i < 8; i++)
2269 dib8000_write_word(state, 343 + i, ncoeff[i]);
2270 }
2271}
2272
2273static const u16 coff_thres_1seg[3] = {300, 150, 80};
2274static const u16 coff_thres_3seg[3] = {350, 300, 250};
2275static void dib8000_set_sb_channel(struct dib8000_state *state)
2276{
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03002277 struct dtv_frontend_properties *c = &state->fe[0]->dtv_property_cache;
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002278 const u16 *coff;
2279 u16 i;
2280
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03002281 if (c->transmission_mode == TRANSMISSION_MODE_2K || c->transmission_mode == TRANSMISSION_MODE_4K) {
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002282 dib8000_write_word(state, 219, dib8000_read_word(state, 219) | 0x1); /* adp_pass =1 */
2283 dib8000_write_word(state, 190, dib8000_read_word(state, 190) | (0x1 << 14)); /* pha3_force_pha_shift = 1 */
2284 } else {
2285 dib8000_write_word(state, 219, dib8000_read_word(state, 219) & 0xfffe); /* adp_pass =0 */
2286 dib8000_write_word(state, 190, dib8000_read_word(state, 190) & 0xbfff); /* pha3_force_pha_shift = 0 */
2287 }
2288
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03002289 if (c->isdbt_partial_reception == 1) /* 3-segments */
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002290 state->seg_mask = 0x00E0;
2291 else /* 1-segment */
2292 state->seg_mask = 0x0040;
2293
2294 dib8000_write_word(state, 268, (dib8000_read_word(state, 268) & 0xF9FF) | 0x0200);
2295
2296 /* ---- COFF ---- Carloff, the most robust --- */
2297 /* P_coff_cpil_alpha=4, P_coff_inh=0, P_coff_cpil_winlen=64, P_coff_narrow_band=1, P_coff_square_val=1, P_coff_one_seg=~partial_rcpt, P_coff_use_tmcc=1, P_coff_use_ac=1 */
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03002298 dib8000_write_word(state, 187, (4 << 12) | (0 << 11) | (63 << 5) | (0x3 << 3) | ((~c->isdbt_partial_reception & 1) << 2) | 0x3);
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002299
2300 dib8000_write_word(state, 340, (16 << 6) | (8 << 0)); /* P_ctrl_pre_freq_win_len=16, P_ctrl_pre_freq_thres_lockin=8 */
2301 dib8000_write_word(state, 341, (6 << 3) | (1 << 2) | (1 << 1) | (1 << 0));/* P_ctrl_pre_freq_thres_lockout=6, P_small_use_tmcc/ac/cp=1 */
2302
2303 /* Sound Broadcasting mode 1 seg */
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03002304 if (c->isdbt_partial_reception == 0) {
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002305 /* P_coff_winlen=63, P_coff_thres_lock=15, P_coff_one_seg_width = (P_mode == 3) , P_coff_one_seg_sym = (P_mode-1) */
2306 if (state->mode == 3)
2307 dib8000_write_word(state, 180, 0x1fcf | ((state->mode - 1) << 14));
2308 else
2309 dib8000_write_word(state, 180, 0x0fcf | ((state->mode - 1) << 14));
2310
2311 /* P_ctrl_corm_thres4pre_freq_inh=1,P_ctrl_pre_freq_mode_sat=1, P_ctrl_pre_freq_inh=0, P_ctrl_pre_freq_step = 5, P_pre_freq_win_len=4 */
2312 dib8000_write_word(state, 338, (1 << 12) | (1 << 10) | (0 << 9) | (5 << 5) | 4);
2313 coff = &coff_thres_1seg[0];
2314 } else { /* Sound Broadcasting mode 3 seg */
2315 dib8000_write_word(state, 180, 0x1fcf | (1 << 14));
2316 /* P_ctrl_corm_thres4pre_freq_inh = 1, P_ctrl_pre_freq_mode_sat=1, P_ctrl_pre_freq_inh=0, P_ctrl_pre_freq_step = 4, P_pre_freq_win_len=4 */
2317 dib8000_write_word(state, 338, (1 << 12) | (1 << 10) | (0 << 9) | (4 << 5) | 4);
2318 coff = &coff_thres_3seg[0];
2319 }
2320
2321 dib8000_write_word(state, 228, 1); /* P_2d_mode_byp=1 */
2322 dib8000_write_word(state, 205, dib8000_read_word(state, 205) & 0xfff0); /* P_cspu_win_cut = 0 */
2323
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03002324 if (c->isdbt_partial_reception == 0 && c->transmission_mode == TRANSMISSION_MODE_2K)
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002325 dib8000_write_word(state, 265, 15); /* P_equal_noise_sel = 15 */
2326
2327 /* Write COFF thres */
2328 for (i = 0 ; i < 3; i++) {
2329 dib8000_write_word(state, 181+i, coff[i]);
2330 dib8000_write_word(state, 184+i, coff[i]);
2331 }
2332
2333 /*
2334 * make the cpil_coff_lock more robust but slower p_coff_winlen
2335 * 6bits; p_coff_thres_lock 6bits (for coff lock if needed)
2336 */
2337
2338 dib8000_write_word(state, 266, ~state->seg_mask | state->seg_diff_mask); /* P_equal_noise_seg_inh */
2339
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03002340 if (c->isdbt_partial_reception == 0)
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002341 dib8000_write_word(state, 178, 64); /* P_fft_powrange = 64 */
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002342 else
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002343 dib8000_write_word(state, 178, 32); /* P_fft_powrange = 32 */
2344}
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002345
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002346static void dib8000_set_isdbt_common_channel(struct dib8000_state *state, u8 seq, u8 autosearching)
2347{
2348 u16 p_cfr_left_edge = 0, p_cfr_right_edge = 0;
2349 u16 tmcc_pow = 0, ana_gain = 0, tmp = 0, i = 0, nbseg_diff = 0 ;
2350 u16 max_constellation = DQPSK;
2351 int init_prbs;
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03002352 struct dtv_frontend_properties *c = &state->fe[0]->dtv_property_cache;
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002353
Mauro Carvalho Chehabdde8e112014-07-04 14:15:32 -03002354 if (autosearching)
2355 c->isdbt_partial_reception = 1;
2356
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002357 /* P_mode */
2358 dib8000_write_word(state, 10, (seq << 4));
2359
2360 /* init mode */
2361 state->mode = fft_to_mode(state);
2362
2363 /* set guard */
2364 tmp = dib8000_read_word(state, 1);
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03002365 dib8000_write_word(state, 1, (tmp&0xfffc) | (c->guard_interval & 0x3));
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002366
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03002367 dib8000_write_word(state, 274, (dib8000_read_word(state, 274) & 0xffcf) | ((c->isdbt_partial_reception & 1) << 5) | ((c->isdbt_sb_mode & 1) << 4));
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002368
2369 /* signal optimization parameter */
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03002370 if (c->isdbt_partial_reception) {
2371 state->seg_diff_mask = (c->layer[0].modulation == DQPSK) << permu_seg[0];
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002372 for (i = 1; i < 3; i++)
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03002373 nbseg_diff += (c->layer[i].modulation == DQPSK) * c->layer[i].segment_count;
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002374 for (i = 0; i < nbseg_diff; i++)
2375 state->seg_diff_mask |= 1 << permu_seg[i+1];
2376 } else {
2377 for (i = 0; i < 3; i++)
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03002378 nbseg_diff += (c->layer[i].modulation == DQPSK) * c->layer[i].segment_count;
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002379 for (i = 0; i < nbseg_diff; i++)
2380 state->seg_diff_mask |= 1 << permu_seg[i];
2381 }
2382
2383 if (state->seg_diff_mask)
2384 dib8000_write_word(state, 268, (dib8000_read_word(state, 268) & 0xF9FF) | 0x0200);
2385 else
2386 dib8000_write_word(state, 268, (2 << 9) | 39); /*init value */
2387
2388 for (i = 0; i < 3; i++)
2389 max_constellation = dib8000_set_layer(state, i, max_constellation);
2390 if (autosearching == 0) {
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03002391 state->layer_b_nb_seg = c->layer[1].segment_count;
2392 state->layer_c_nb_seg = c->layer[2].segment_count;
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002393 }
2394
2395 /* WRITE: Mode & Diff mask */
2396 dib8000_write_word(state, 0, (state->mode << 13) | state->seg_diff_mask);
2397
2398 state->differential_constellation = (state->seg_diff_mask != 0);
2399
2400 /* channel estimation fine configuration */
2401 ana_gain = dib8000_adp_fine_tune(state, max_constellation);
2402
2403 /* update ana_gain depending on max constellation */
2404 dib8000_update_ana_gain(state, ana_gain);
2405
2406 /* ---- ANA_FE ---- */
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03002407 if (c->isdbt_partial_reception) /* 3-segments */
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002408 dib8000_load_ana_fe_coefs(state, ana_fe_coeff_3seg);
2409 else
2410 dib8000_load_ana_fe_coefs(state, ana_fe_coeff_1seg); /* 1-segment */
2411
2412 /* TSB or ISDBT ? apply it now */
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03002413 if (c->isdbt_sb_mode) {
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002414 dib8000_set_sb_channel(state);
Mauro Carvalho Chehab746f7ae2013-04-25 11:15:54 -03002415 if (c->isdbt_sb_subchannel < 14)
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03002416 init_prbs = dib8000_get_init_prbs(state, c->isdbt_sb_subchannel);
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002417 else
2418 init_prbs = 0;
2419 } else {
2420 dib8000_set_13seg_channel(state);
2421 init_prbs = 0xfff;
2422 }
2423
2424 /* SMALL */
2425 dib8000_small_fine_tune(state);
2426
2427 dib8000_set_subchannel_prbs(state, init_prbs);
2428
2429 /* ---- CHAN_BLK ---- */
2430 for (i = 0; i < 13; i++) {
2431 if ((((~state->seg_diff_mask) >> i) & 1) == 1) {
2432 p_cfr_left_edge += (1 << i) * ((i == 0) || ((((state->seg_mask & (~state->seg_diff_mask)) >> (i - 1)) & 1) == 0));
2433 p_cfr_right_edge += (1 << i) * ((i == 12) || ((((state->seg_mask & (~state->seg_diff_mask)) >> (i + 1)) & 1) == 0));
2434 }
2435 }
2436 dib8000_write_word(state, 222, p_cfr_left_edge); /* p_cfr_left_edge */
2437 dib8000_write_word(state, 223, p_cfr_right_edge); /* p_cfr_right_edge */
2438 /* "P_cspu_left_edge" & "P_cspu_right_edge" not used => do not care */
2439
2440 dib8000_write_word(state, 189, ~state->seg_mask | state->seg_diff_mask); /* P_lmod4_seg_inh */
2441 dib8000_write_word(state, 192, ~state->seg_mask | state->seg_diff_mask); /* P_pha3_seg_inh */
2442 dib8000_write_word(state, 225, ~state->seg_mask | state->seg_diff_mask); /* P_tac_seg_inh */
2443
2444 if (!autosearching)
2445 dib8000_write_word(state, 288, (~state->seg_mask | state->seg_diff_mask) & 0x1fff); /* P_tmcc_seg_eq_inh */
2446 else
2447 dib8000_write_word(state, 288, 0x1fff); /*disable equalisation of the tmcc when autosearch to be able to find the DQPSK channels. */
2448
2449 dib8000_write_word(state, 211, state->seg_mask & (~state->seg_diff_mask)); /* P_des_seg_enabled */
2450 dib8000_write_word(state, 287, ~state->seg_mask | 0x1000); /* P_tmcc_seg_inh */
2451
2452 dib8000_write_word(state, 178, 32); /* P_fft_powrange = 32 */
2453
2454 /* ---- TMCC ---- */
2455 for (i = 0; i < 3; i++)
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03002456 tmcc_pow += (((c->layer[i].modulation == DQPSK) * 4 + 1) * c->layer[i].segment_count) ;
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002457
2458 /* Quantif of "P_tmcc_dec_thres_?k" is (0, 5+mode, 9); */
2459 /* Threshold is set at 1/4 of max power. */
2460 tmcc_pow *= (1 << (9-2));
2461 dib8000_write_word(state, 290, tmcc_pow); /* P_tmcc_dec_thres_2k */
2462 dib8000_write_word(state, 291, tmcc_pow); /* P_tmcc_dec_thres_4k */
2463 dib8000_write_word(state, 292, tmcc_pow); /* P_tmcc_dec_thres_8k */
2464 /*dib8000_write_word(state, 287, (1 << 13) | 0x1000 ); */
2465
2466 /* ---- PHA3 ---- */
2467 if (state->isdbt_cfg_loaded == 0)
2468 dib8000_write_word(state, 250, 3285); /* p_2d_hspeed_thr0 */
2469
2470 state->isdbt_cfg_loaded = 0;
2471}
2472
Mauro Carvalho Chehab6f7ee062013-04-25 10:36:56 -03002473static u32 dib8000_wait_lock(struct dib8000_state *state, u32 internal,
2474 u32 wait0_ms, u32 wait1_ms, u32 wait2_ms)
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002475{
Mauro Carvalho Chehab13122f92013-04-25 15:22:20 -03002476 u32 value = 0; /* P_search_end0 wait time */
2477 u16 reg = 11; /* P_search_end0 start addr */
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002478
2479 for (reg = 11; reg < 16; reg += 2) {
2480 if (reg == 11) {
2481 if (state->revision == 0x8090)
Mauro Carvalho Chehab13122f92013-04-25 15:22:20 -03002482 value = internal * wait1_ms;
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002483 else
Mauro Carvalho Chehab13122f92013-04-25 15:22:20 -03002484 value = internal * wait0_ms;
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002485 } else if (reg == 13)
Mauro Carvalho Chehab13122f92013-04-25 15:22:20 -03002486 value = internal * wait1_ms;
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002487 else if (reg == 15)
Mauro Carvalho Chehab13122f92013-04-25 15:22:20 -03002488 value = internal * wait2_ms;
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002489 dib8000_write_word(state, reg, (u16)((value >> 16) & 0xffff));
2490 dib8000_write_word(state, (reg + 1), (u16)(value & 0xffff));
2491 }
2492 return value;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002493}
2494
2495static int dib8000_autosearch_start(struct dvb_frontend *fe)
2496{
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002497 struct dib8000_state *state = fe->demodulator_priv;
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03002498 struct dtv_frontend_properties *c = &state->fe[0]->dtv_property_cache;
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002499 u8 slist = 0;
2500 u32 value, internal = state->cfg.pll->internal;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002501
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002502 if (state->revision == 0x8090)
2503 internal = dib8000_read32(state, 23) / 1000;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002504
Olivier Grenied67350f2013-12-12 09:26:22 -03002505 if ((state->revision >= 0x8002) &&
2506 (state->autosearch_state == AS_SEARCHING_FFT)) {
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002507 dib8000_write_word(state, 37, 0x0065); /* P_ctrl_pha_off_max default values */
2508 dib8000_write_word(state, 116, 0x0000); /* P_ana_gain to 0 */
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002509
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002510 dib8000_write_word(state, 0, (dib8000_read_word(state, 0) & 0x1fff) | (0 << 13) | (1 << 15)); /* P_mode = 0, P_restart_search=1 */
2511 dib8000_write_word(state, 1, (dib8000_read_word(state, 1) & 0xfffc) | 0); /* P_guard = 0 */
2512 dib8000_write_word(state, 6, 0); /* P_lock0_mask = 0 */
2513 dib8000_write_word(state, 7, 0); /* P_lock1_mask = 0 */
2514 dib8000_write_word(state, 8, 0); /* P_lock2_mask = 0 */
2515 dib8000_write_word(state, 10, (dib8000_read_word(state, 10) & 0x200) | (16 << 4) | (0 << 0)); /* P_search_list=16, P_search_maxtrial=0 */
2516
2517 if (state->revision == 0x8090)
2518 value = dib8000_wait_lock(state, internal, 10, 10, 10); /* time in ms configure P_search_end0 P_search_end1 P_search_end2 */
2519 else
2520 value = dib8000_wait_lock(state, internal, 20, 20, 20); /* time in ms configure P_search_end0 P_search_end1 P_search_end2 */
2521
2522 dib8000_write_word(state, 17, 0);
2523 dib8000_write_word(state, 18, 200); /* P_search_rstst = 200 */
2524 dib8000_write_word(state, 19, 0);
2525 dib8000_write_word(state, 20, 400); /* P_search_rstend = 400 */
2526 dib8000_write_word(state, 21, (value >> 16) & 0xffff); /* P_search_checkst */
2527 dib8000_write_word(state, 22, value & 0xffff);
2528
2529 if (state->revision == 0x8090)
2530 dib8000_write_word(state, 32, (dib8000_read_word(state, 32) & 0xf0ff) | (0 << 8)); /* P_corm_alpha = 0 */
2531 else
2532 dib8000_write_word(state, 32, (dib8000_read_word(state, 32) & 0xf0ff) | (9 << 8)); /* P_corm_alpha = 3 */
2533 dib8000_write_word(state, 355, 2); /* P_search_param_max = 2 */
2534
2535 /* P_search_param_select = (1 | 1<<4 | 1 << 8) */
2536 dib8000_write_word(state, 356, 0);
2537 dib8000_write_word(state, 357, 0x111);
2538
2539 dib8000_write_word(state, 770, (dib8000_read_word(state, 770) & 0xdfff) | (1 << 13)); /* P_restart_ccg = 1 */
2540 dib8000_write_word(state, 770, (dib8000_read_word(state, 770) & 0xdfff) | (0 << 13)); /* P_restart_ccg = 0 */
2541 dib8000_write_word(state, 0, (dib8000_read_word(state, 0) & 0x7ff) | (0 << 15) | (1 << 13)); /* P_restart_search = 0; */
Olivier Grenied67350f2013-12-12 09:26:22 -03002542 } else if ((state->revision >= 0x8002) &&
2543 (state->autosearch_state == AS_SEARCHING_GUARD)) {
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03002544 c->transmission_mode = TRANSMISSION_MODE_8K;
2545 c->guard_interval = GUARD_INTERVAL_1_8;
2546 c->inversion = 0;
2547 c->layer[0].modulation = QAM_64;
2548 c->layer[0].fec = FEC_2_3;
2549 c->layer[0].interleaving = 0;
2550 c->layer[0].segment_count = 13;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002551
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002552 slist = 16;
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03002553 c->transmission_mode = state->found_nfft;
Patrick Boettcher78f3bc62009-08-17 12:53:51 -03002554
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002555 dib8000_set_isdbt_common_channel(state, slist, 1);
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002556
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002557 /* set lock_mask values */
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002558 dib8000_write_word(state, 6, 0x4);
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002559 if (state->revision == 0x8090)
2560 dib8000_write_word(state, 7, ((1 << 12) | (1 << 11) | (1 << 10)));/* tmcc_dec_lock, tmcc_sync_lock, tmcc_data_lock, tmcc_bch_uncor */
2561 else
2562 dib8000_write_word(state, 7, 0x8);
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002563 dib8000_write_word(state, 8, 0x1000);
2564
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002565 /* set lock_mask wait time values */
2566 if (state->revision == 0x8090)
2567 dib8000_wait_lock(state, internal, 50, 100, 1000); /* time in ms configure P_search_end0 P_search_end1 P_search_end2 */
2568 else
2569 dib8000_wait_lock(state, internal, 50, 200, 1000); /* time in ms configure P_search_end0 P_search_end1 P_search_end2 */
2570
2571 dib8000_write_word(state, 355, 3); /* P_search_param_max = 3 */
2572
2573 /* P_search_param_select = 0xf; look for the 4 different guard intervals */
2574 dib8000_write_word(state, 356, 0);
2575 dib8000_write_word(state, 357, 0xf);
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002576
2577 value = dib8000_read_word(state, 0);
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002578 dib8000_write_word(state, 0, (u16)((1 << 15) | value));
2579 dib8000_read_word(state, 1284); /* reset the INT. n_irq_pending */
2580 dib8000_write_word(state, 0, (u16)value);
2581 } else {
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03002582 c->inversion = 0;
2583 c->layer[0].modulation = QAM_64;
2584 c->layer[0].fec = FEC_2_3;
2585 c->layer[0].interleaving = 0;
2586 c->layer[0].segment_count = 13;
2587 if (!c->isdbt_sb_mode)
2588 c->layer[0].segment_count = 13;
Patrick Boettcher78f3bc62009-08-17 12:53:51 -03002589
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002590 /* choose the right list, in sb, always do everything */
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03002591 if (c->isdbt_sb_mode) {
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002592 slist = 7;
2593 dib8000_write_word(state, 0, (dib8000_read_word(state, 0) & 0x9fff) | (1 << 13));
2594 } else {
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03002595 if (c->guard_interval == GUARD_INTERVAL_AUTO) {
2596 if (c->transmission_mode == TRANSMISSION_MODE_AUTO) {
2597 c->transmission_mode = TRANSMISSION_MODE_8K;
2598 c->guard_interval = GUARD_INTERVAL_1_8;
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002599 slist = 7;
2600 dib8000_write_word(state, 0, (dib8000_read_word(state, 0) & 0x9fff) | (1 << 13)); /* P_mode = 1 to have autosearch start ok with mode2 */
2601 } else {
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03002602 c->guard_interval = GUARD_INTERVAL_1_8;
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002603 slist = 3;
2604 }
2605 } else {
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03002606 if (c->transmission_mode == TRANSMISSION_MODE_AUTO) {
2607 c->transmission_mode = TRANSMISSION_MODE_8K;
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002608 slist = 2;
2609 dib8000_write_word(state, 0, (dib8000_read_word(state, 0) & 0x9fff) | (1 << 13)); /* P_mode = 1 */
2610 } else
2611 slist = 0;
2612 }
2613 }
Mauro Carvalho Chehab8af16ad2016-10-14 10:05:46 -03002614 dprintk("Using list for autosearch : %d\n", slist);
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002615
2616 dib8000_set_isdbt_common_channel(state, slist, 1);
2617
2618 /* set lock_mask values */
2619 dib8000_write_word(state, 6, 0x4);
2620 if (state->revision == 0x8090)
2621 dib8000_write_word(state, 7, (1 << 12) | (1 << 11) | (1 << 10));
2622 else
2623 dib8000_write_word(state, 7, 0x8);
2624 dib8000_write_word(state, 8, 0x1000);
2625
2626 /* set lock_mask wait time values */
2627 if (state->revision == 0x8090)
2628 dib8000_wait_lock(state, internal, 50, 200, 1000); /* time in ms configure P_search_end0 P_search_end1 P_search_end2 */
2629 else
2630 dib8000_wait_lock(state, internal, 50, 100, 1000); /* time in ms configure P_search_end0 P_search_end1 P_search_end2 */
2631
2632 value = dib8000_read_word(state, 0);
2633 dib8000_write_word(state, 0, (u16)((1 << 15) | value));
2634 dib8000_read_word(state, 1284); /* reset the INT. n_irq_pending */
2635 dib8000_write_word(state, 0, (u16)value);
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002636 }
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002637 return 0;
2638}
2639
2640static int dib8000_autosearch_irq(struct dvb_frontend *fe)
2641{
2642 struct dib8000_state *state = fe->demodulator_priv;
2643 u16 irq_pending = dib8000_read_word(state, 1284);
2644
Olivier Grenied67350f2013-12-12 09:26:22 -03002645 if ((state->revision >= 0x8002) &&
2646 (state->autosearch_state == AS_SEARCHING_FFT)) {
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002647 if (irq_pending & 0x1) {
Mauro Carvalho Chehab8af16ad2016-10-14 10:05:46 -03002648 dprintk("dib8000_autosearch_irq: max correlation result available\n");
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002649 return 3;
2650 }
2651 } else {
2652 if (irq_pending & 0x1) { /* failed */
Mauro Carvalho Chehab8af16ad2016-10-14 10:05:46 -03002653 dprintk("dib8000_autosearch_irq failed\n");
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002654 return 1;
2655 }
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002656
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002657 if (irq_pending & 0x2) { /* succeeded */
Mauro Carvalho Chehab8af16ad2016-10-14 10:05:46 -03002658 dprintk("dib8000_autosearch_irq succeeded\n");
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002659 return 2;
2660 }
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002661 }
2662
2663 return 0; // still pending
2664}
2665
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002666static void dib8000_viterbi_state(struct dib8000_state *state, u8 onoff)
2667{
2668 u16 tmp;
2669
2670 tmp = dib8000_read_word(state, 771);
2671 if (onoff) /* start P_restart_chd : channel_decoder */
2672 dib8000_write_word(state, 771, tmp & 0xfffd);
2673 else /* stop P_restart_chd : channel_decoder */
2674 dib8000_write_word(state, 771, tmp | (1<<1));
2675}
2676
2677static void dib8000_set_dds(struct dib8000_state *state, s32 offset_khz)
2678{
2679 s16 unit_khz_dds_val;
2680 u32 abs_offset_khz = ABS(offset_khz);
2681 u32 dds = state->cfg.pll->ifreq & 0x1ffffff;
2682 u8 invert = !!(state->cfg.pll->ifreq & (1 << 25));
2683 u8 ratio;
2684
2685 if (state->revision == 0x8090) {
2686 ratio = 4;
2687 unit_khz_dds_val = (1<<26) / (dib8000_read32(state, 23) / 1000);
2688 if (offset_khz < 0)
2689 dds = (1 << 26) - (abs_offset_khz * unit_khz_dds_val);
2690 else
2691 dds = (abs_offset_khz * unit_khz_dds_val);
2692
2693 if (invert)
2694 dds = (1<<26) - dds;
2695 } else {
2696 ratio = 2;
2697 unit_khz_dds_val = (u16) (67108864 / state->cfg.pll->internal);
2698
2699 if (offset_khz < 0)
2700 unit_khz_dds_val *= -1;
2701
2702 /* IF tuner */
2703 if (invert)
2704 dds -= abs_offset_khz * unit_khz_dds_val;
2705 else
2706 dds += abs_offset_khz * unit_khz_dds_val;
2707 }
2708
Mauro Carvalho Chehab8af16ad2016-10-14 10:05:46 -03002709 dprintk("setting a DDS frequency offset of %c%dkHz\n", invert ? '-' : ' ', dds / unit_khz_dds_val);
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002710
2711 if (abs_offset_khz <= (state->cfg.pll->internal / ratio)) {
2712 /* Max dds offset is the half of the demod freq */
2713 dib8000_write_word(state, 26, invert);
2714 dib8000_write_word(state, 27, (u16)(dds >> 16) & 0x1ff);
2715 dib8000_write_word(state, 28, (u16)(dds & 0xffff));
2716 }
2717}
2718
2719static void dib8000_set_frequency_offset(struct dib8000_state *state)
2720{
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03002721 struct dtv_frontend_properties *c = &state->fe[0]->dtv_property_cache;
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002722 int i;
2723 u32 current_rf;
2724 int total_dds_offset_khz;
2725
2726 if (state->fe[0]->ops.tuner_ops.get_frequency)
2727 state->fe[0]->ops.tuner_ops.get_frequency(state->fe[0], &current_rf);
2728 else
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03002729 current_rf = c->frequency;
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002730 current_rf /= 1000;
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03002731 total_dds_offset_khz = (int)current_rf - (int)c->frequency / 1000;
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002732
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03002733 if (c->isdbt_sb_mode) {
2734 state->subchannel = c->isdbt_sb_subchannel;
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002735
2736 i = dib8000_read_word(state, 26) & 1; /* P_dds_invspec */
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03002737 dib8000_write_word(state, 26, c->inversion ^ i);
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002738
2739 if (state->cfg.pll->ifreq == 0) { /* low if tuner */
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03002740 if ((c->inversion ^ i) == 0)
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002741 dib8000_write_word(state, 26, dib8000_read_word(state, 26) | 1);
2742 } else {
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03002743 if ((c->inversion ^ i) == 0)
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002744 total_dds_offset_khz *= -1;
2745 }
2746 }
2747
Mauro Carvalho Chehab8af16ad2016-10-14 10:05:46 -03002748 dprintk("%dkhz tuner offset (frequency = %dHz & current_rf = %dHz) total_dds_offset_hz = %d\n", c->frequency - current_rf, c->frequency, current_rf, total_dds_offset_khz);
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002749
2750 /* apply dds offset now */
2751 dib8000_set_dds(state, total_dds_offset_khz);
2752}
2753
2754static u16 LUT_isdbt_symbol_duration[4] = { 26, 101, 63 };
Mauro Carvalho Chehab6f7ee062013-04-25 10:36:56 -03002755
2756static u32 dib8000_get_symbol_duration(struct dib8000_state *state)
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002757{
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03002758 struct dtv_frontend_properties *c = &state->fe[0]->dtv_property_cache;
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002759 u16 i;
2760
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03002761 switch (c->transmission_mode) {
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002762 case TRANSMISSION_MODE_2K:
2763 i = 0;
2764 break;
2765 case TRANSMISSION_MODE_4K:
2766 i = 2;
2767 break;
2768 default:
2769 case TRANSMISSION_MODE_AUTO:
2770 case TRANSMISSION_MODE_8K:
2771 i = 1;
2772 break;
2773 }
2774
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03002775 return (LUT_isdbt_symbol_duration[i] / (c->bandwidth_hz / 1000)) + 1;
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002776}
2777
2778static void dib8000_set_isdbt_loop_params(struct dib8000_state *state, enum param_loop_step loop_step)
2779{
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03002780 struct dtv_frontend_properties *c = &state->fe[0]->dtv_property_cache;
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002781 u16 reg_32 = 0, reg_37 = 0;
2782
2783 switch (loop_step) {
2784 case LOOP_TUNE_1:
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03002785 if (c->isdbt_sb_mode) {
2786 if (c->isdbt_partial_reception == 0) {
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002787 reg_32 = ((11 - state->mode) << 12) | (6 << 8) | 0x40; /* P_timf_alpha = (11-P_mode), P_corm_alpha=6, P_corm_thres=0x40 */
2788 reg_37 = (3 << 5) | (0 << 4) | (10 - state->mode); /* P_ctrl_pha_off_max=3 P_ctrl_sfreq_inh =0 P_ctrl_sfreq_step = (10-P_mode) */
2789 } else { /* Sound Broadcasting mode 3 seg */
2790 reg_32 = ((10 - state->mode) << 12) | (6 << 8) | 0x60; /* P_timf_alpha = (10-P_mode), P_corm_alpha=6, P_corm_thres=0x60 */
2791 reg_37 = (3 << 5) | (0 << 4) | (9 - state->mode); /* P_ctrl_pha_off_max=3 P_ctrl_sfreq_inh =0 P_ctrl_sfreq_step = (9-P_mode) */
2792 }
2793 } else { /* 13-seg start conf offset loop parameters */
2794 reg_32 = ((9 - state->mode) << 12) | (6 << 8) | 0x80; /* P_timf_alpha = (9-P_mode, P_corm_alpha=6, P_corm_thres=0x80 */
2795 reg_37 = (3 << 5) | (0 << 4) | (8 - state->mode); /* P_ctrl_pha_off_max=3 P_ctrl_sfreq_inh =0 P_ctrl_sfreq_step = 9 */
2796 }
2797 break;
2798 case LOOP_TUNE_2:
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03002799 if (c->isdbt_sb_mode) {
2800 if (c->isdbt_partial_reception == 0) { /* Sound Broadcasting mode 1 seg */
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002801 reg_32 = ((13-state->mode) << 12) | (6 << 8) | 0x40; /* P_timf_alpha = (13-P_mode) , P_corm_alpha=6, P_corm_thres=0x40*/
2802 reg_37 = (12-state->mode) | ((5 + state->mode) << 5);
2803 } else { /* Sound Broadcasting mode 3 seg */
2804 reg_32 = ((12-state->mode) << 12) | (6 << 8) | 0x60; /* P_timf_alpha = (12-P_mode) , P_corm_alpha=6, P_corm_thres=0x60 */
2805 reg_37 = (11-state->mode) | ((5 + state->mode) << 5);
2806 }
2807 } else { /* 13 seg */
2808 reg_32 = ((11-state->mode) << 12) | (6 << 8) | 0x80; /* P_timf_alpha = 8 , P_corm_alpha=6, P_corm_thres=0x80 */
2809 reg_37 = ((5+state->mode) << 5) | (10 - state->mode);
2810 }
2811 break;
2812 }
2813 dib8000_write_word(state, 32, reg_32);
2814 dib8000_write_word(state, 37, reg_37);
2815}
2816
2817static void dib8000_demod_restart(struct dib8000_state *state)
2818{
2819 dib8000_write_word(state, 770, 0x4000);
2820 dib8000_write_word(state, 770, 0x0000);
2821 return;
2822}
2823
2824static void dib8000_set_sync_wait(struct dib8000_state *state)
2825{
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03002826 struct dtv_frontend_properties *c = &state->fe[0]->dtv_property_cache;
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002827 u16 sync_wait = 64;
2828
2829 /* P_dvsy_sync_wait - reuse mode */
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03002830 switch (c->transmission_mode) {
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002831 case TRANSMISSION_MODE_8K:
2832 sync_wait = 256;
2833 break;
2834 case TRANSMISSION_MODE_4K:
2835 sync_wait = 128;
2836 break;
2837 default:
2838 case TRANSMISSION_MODE_2K:
2839 sync_wait = 64;
2840 break;
2841 }
2842
2843 if (state->cfg.diversity_delay == 0)
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03002844 sync_wait = (sync_wait * (1 << (c->guard_interval)) * 3) / 2 + 48; /* add 50% SFN margin + compensate for one DVSY-fifo */
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002845 else
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03002846 sync_wait = (sync_wait * (1 << (c->guard_interval)) * 3) / 2 + state->cfg.diversity_delay; /* add 50% SFN margin + compensate for DVSY-fifo */
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002847
2848 dib8000_write_word(state, 273, (dib8000_read_word(state, 273) & 0x000f) | (sync_wait << 4));
2849}
2850
Mauro Carvalho Chehabd6c62b72014-07-04 14:15:37 -03002851static unsigned long dib8000_get_timeout(struct dib8000_state *state, u32 delay, enum timeout_mode mode)
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002852{
2853 if (mode == SYMBOL_DEPENDENT_ON)
Mauro Carvalho Chehabd6c62b72014-07-04 14:15:37 -03002854 delay *= state->symbol_duration;
2855
2856 return jiffies + usecs_to_jiffies(delay * 100);
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002857}
2858
2859static s32 dib8000_get_status(struct dvb_frontend *fe)
2860{
2861 struct dib8000_state *state = fe->demodulator_priv;
2862 return state->status;
2863}
2864
Mauro Carvalho Chehabd44913c2014-05-29 09:20:17 -03002865static enum frontend_tune_state dib8000_get_tune_state(struct dvb_frontend *fe)
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002866{
2867 struct dib8000_state *state = fe->demodulator_priv;
2868 return state->tune_state;
2869}
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002870
Mauro Carvalho Chehabd44913c2014-05-29 09:20:17 -03002871static int dib8000_set_tune_state(struct dvb_frontend *fe, enum frontend_tune_state tune_state)
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002872{
2873 struct dib8000_state *state = fe->demodulator_priv;
2874
2875 state->tune_state = tune_state;
2876 return 0;
2877}
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002878
2879static int dib8000_tune_restart_from_demod(struct dvb_frontend *fe)
2880{
2881 struct dib8000_state *state = fe->demodulator_priv;
2882
2883 state->status = FE_STATUS_TUNE_PENDING;
2884 state->tune_state = CT_DEMOD_START;
2885 return 0;
2886}
2887
2888static u16 dib8000_read_lock(struct dvb_frontend *fe)
2889{
2890 struct dib8000_state *state = fe->demodulator_priv;
2891
2892 if (state->revision == 0x8090)
2893 return dib8000_read_word(state, 570);
2894 return dib8000_read_word(state, 568);
2895}
2896
2897static int dib8090p_init_sdram(struct dib8000_state *state)
2898{
2899 u16 reg = 0;
Mauro Carvalho Chehab8af16ad2016-10-14 10:05:46 -03002900 dprintk("init sdram\n");
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002901
2902 reg = dib8000_read_word(state, 274) & 0xfff0;
2903 dib8000_write_word(state, 274, reg | 0x7); /* P_dintlv_delay_ram = 7 because of MobileSdram */
2904
2905 dib8000_write_word(state, 1803, (7 << 2));
2906
2907 reg = dib8000_read_word(state, 1280);
2908 dib8000_write_word(state, 1280, reg | (1 << 2)); /* force restart P_restart_sdram */
2909 dib8000_write_word(state, 1280, reg); /* release restart P_restart_sdram */
2910
2911 return 0;
2912}
2913
Mauro Carvalho Chehabad976182013-12-15 09:57:40 -03002914/**
2915 * is_manual_mode - Check if TMCC should be used for parameters settings
2916 * @c: struct dvb_frontend_properties
2917 *
2918 * By default, TMCC table should be used for parameter settings on most
2919 * usercases. However, sometimes it is desirable to lock the demod to
2920 * use the manual parameters.
2921 *
2922 * On manual mode, the current dib8000_tune state machine is very restrict:
2923 * It requires that both per-layer and per-transponder parameters to be
2924 * properly specified, otherwise the device won't lock.
2925 *
2926 * Check if all those conditions are properly satisfied before allowing
2927 * the device to use the manual frequency lock mode.
2928 */
2929static int is_manual_mode(struct dtv_frontend_properties *c)
2930{
2931 int i, n_segs = 0;
2932
2933 /* Use auto mode on DVB-T compat mode */
2934 if (c->delivery_system != SYS_ISDBT)
2935 return 0;
2936
2937 /*
2938 * Transmission mode is only detected on auto mode, currently
2939 */
2940 if (c->transmission_mode == TRANSMISSION_MODE_AUTO) {
Mauro Carvalho Chehab8af16ad2016-10-14 10:05:46 -03002941 dprintk("transmission mode auto\n");
Mauro Carvalho Chehabad976182013-12-15 09:57:40 -03002942 return 0;
2943 }
2944
2945 /*
2946 * Guard interval is only detected on auto mode, currently
2947 */
2948 if (c->guard_interval == GUARD_INTERVAL_AUTO) {
Mauro Carvalho Chehab8af16ad2016-10-14 10:05:46 -03002949 dprintk("guard interval auto\n");
Mauro Carvalho Chehabad976182013-12-15 09:57:40 -03002950 return 0;
2951 }
2952
2953 /*
2954 * If no layer is enabled, assume auto mode, as at least one
2955 * layer should be enabled
2956 */
2957 if (!c->isdbt_layer_enabled) {
Mauro Carvalho Chehab8af16ad2016-10-14 10:05:46 -03002958 dprintk("no layer modulation specified\n");
Mauro Carvalho Chehabad976182013-12-15 09:57:40 -03002959 return 0;
2960 }
2961
2962 /*
2963 * Check if the per-layer parameters aren't auto and
2964 * disable a layer if segment count is 0 or invalid.
2965 */
2966 for (i = 0; i < 3; i++) {
2967 if (!(c->isdbt_layer_enabled & 1 << i))
2968 continue;
2969
2970 if ((c->layer[i].segment_count > 13) ||
2971 (c->layer[i].segment_count == 0)) {
2972 c->isdbt_layer_enabled &= ~(1 << i);
2973 continue;
2974 }
2975
2976 n_segs += c->layer[i].segment_count;
2977
2978 if ((c->layer[i].modulation == QAM_AUTO) ||
2979 (c->layer[i].fec == FEC_AUTO)) {
Mauro Carvalho Chehab8af16ad2016-10-14 10:05:46 -03002980 dprintk("layer %c has either modulation or FEC auto\n",
Mauro Carvalho Chehabad976182013-12-15 09:57:40 -03002981 'A' + i);
2982 return 0;
2983 }
2984 }
2985
2986 /*
2987 * Userspace specified a wrong number of segments.
2988 * fallback to auto mode.
2989 */
2990 if (n_segs == 0 || n_segs > 13) {
Mauro Carvalho Chehab8af16ad2016-10-14 10:05:46 -03002991 dprintk("number of segments is invalid\n");
Mauro Carvalho Chehabad976182013-12-15 09:57:40 -03002992 return 0;
2993 }
2994
2995 /* Everything looks ok for manual mode */
2996 return 1;
2997}
2998
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002999static int dib8000_tune(struct dvb_frontend *fe)
3000{
3001 struct dib8000_state *state = fe->demodulator_priv;
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03003002 struct dtv_frontend_properties *c = &state->fe[0]->dtv_property_cache;
Patrick Boettcher173a64c2013-04-22 12:45:52 -03003003 enum frontend_tune_state *tune_state = &state->tune_state;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003004
Patrick Boettcher173a64c2013-04-22 12:45:52 -03003005 u16 locks, deeper_interleaver = 0, i;
3006 int ret = 1; /* 1 symbol duration (in 100us unit) delay most of the time */
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003007
Mauro Carvalho Chehabd6c62b72014-07-04 14:15:37 -03003008 unsigned long *timeout = &state->timeout;
3009 unsigned long now = jiffies;
Patrick Boettcher173a64c2013-04-22 12:45:52 -03003010#ifdef DIB8000_AGC_FREEZE
3011 u16 agc1, agc2;
3012#endif
Dan Carpentere04f4b22012-07-20 07:11:57 -03003013
Patrick Boettcher173a64c2013-04-22 12:45:52 -03003014 u32 corm[4] = {0, 0, 0, 0};
3015 u8 find_index, max_value;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003016
Patrick Boettcher173a64c2013-04-22 12:45:52 -03003017#if 0
3018 if (*tune_state < CT_DEMOD_STOP)
Mauro Carvalho Chehab8af16ad2016-10-14 10:05:46 -03003019 dprintk("IN: context status = %d, TUNE_STATE %d autosearch step = %u jiffies = %lu\n",
Mauro Carvalho Chehabd6c62b72014-07-04 14:15:37 -03003020 state->channel_parameters_set, *tune_state, state->autosearch_state, now);
Patrick Boettcher173a64c2013-04-22 12:45:52 -03003021#endif
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003022
Patrick Boettcher173a64c2013-04-22 12:45:52 -03003023 switch (*tune_state) {
3024 case CT_DEMOD_START: /* 30 */
Mauro Carvalho Chehab7fa676c2014-07-04 14:15:29 -03003025 dib8000_reset_stats(fe);
Mauro Carvalho Chehab6ef06e72013-12-16 19:10:59 -03003026
Mauro Carvalho Chehab7fa676c2014-07-04 14:15:29 -03003027 if (state->revision == 0x8090)
3028 dib8090p_init_sdram(state);
3029 state->status = FE_STATUS_TUNE_PENDING;
3030 state->channel_parameters_set = is_manual_mode(c);
Mauro Carvalho Chehabad976182013-12-15 09:57:40 -03003031
Mauro Carvalho Chehab8af16ad2016-10-14 10:05:46 -03003032 dprintk("Tuning channel on %s search mode\n",
Mauro Carvalho Chehab7fa676c2014-07-04 14:15:29 -03003033 state->channel_parameters_set ? "manual" : "auto");
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003034
Mauro Carvalho Chehab7fa676c2014-07-04 14:15:29 -03003035 dib8000_viterbi_state(state, 0); /* force chan dec in restart */
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003036
Mauro Carvalho Chehab7fa676c2014-07-04 14:15:29 -03003037 /* Layer monitor */
3038 dib8000_write_word(state, 285, dib8000_read_word(state, 285) & 0x60);
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003039
Mauro Carvalho Chehab7fa676c2014-07-04 14:15:29 -03003040 dib8000_set_frequency_offset(state);
3041 dib8000_set_bandwidth(fe, c->bandwidth_hz / 1000);
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003042
Mauro Carvalho Chehab7fa676c2014-07-04 14:15:29 -03003043 if (state->channel_parameters_set == 0) { /* The channel struct is unknown, search it ! */
Patrick Boettcher173a64c2013-04-22 12:45:52 -03003044#ifdef DIB8000_AGC_FREEZE
Mauro Carvalho Chehab7fa676c2014-07-04 14:15:29 -03003045 if (state->revision != 0x8090) {
3046 state->agc1_max = dib8000_read_word(state, 108);
3047 state->agc1_min = dib8000_read_word(state, 109);
3048 state->agc2_max = dib8000_read_word(state, 110);
3049 state->agc2_min = dib8000_read_word(state, 111);
3050 agc1 = dib8000_read_word(state, 388);
3051 agc2 = dib8000_read_word(state, 389);
3052 dib8000_write_word(state, 108, agc1);
3053 dib8000_write_word(state, 109, agc1);
3054 dib8000_write_word(state, 110, agc2);
3055 dib8000_write_word(state, 111, agc2);
Patrick Boettcher173a64c2013-04-22 12:45:52 -03003056 }
Mauro Carvalho Chehab7fa676c2014-07-04 14:15:29 -03003057#endif
3058 state->autosearch_state = AS_SEARCHING_FFT;
3059 state->found_nfft = TRANSMISSION_MODE_AUTO;
3060 state->found_guard = GUARD_INTERVAL_AUTO;
3061 *tune_state = CT_DEMOD_SEARCH_NEXT;
3062 } else { /* we already know the channel struct so TUNE only ! */
3063 state->autosearch_state = AS_DONE;
3064 *tune_state = CT_DEMOD_STEP_3;
3065 }
3066 state->symbol_duration = dib8000_get_symbol_duration(state);
3067 break;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003068
Patrick Boettcher173a64c2013-04-22 12:45:52 -03003069 case CT_DEMOD_SEARCH_NEXT: /* 51 */
Mauro Carvalho Chehab7fa676c2014-07-04 14:15:29 -03003070 dib8000_autosearch_start(fe);
3071 if (state->revision == 0x8090)
3072 ret = 50;
3073 else
3074 ret = 15;
3075 *tune_state = CT_DEMOD_STEP_1;
3076 break;
3077
3078 case CT_DEMOD_STEP_1: /* 31 */
3079 switch (dib8000_autosearch_irq(fe)) {
3080 case 1: /* fail */
3081 state->status = FE_STATUS_TUNE_FAILED;
3082 state->autosearch_state = AS_DONE;
3083 *tune_state = CT_DEMOD_STOP; /* else we are done here */
3084 break;
3085 case 2: /* Succes */
3086 state->status = FE_STATUS_FFT_SUCCESS; /* signal to the upper layer, that there was a channel found and the parameters can be read */
3087 *tune_state = CT_DEMOD_STEP_3;
3088 if (state->autosearch_state == AS_SEARCHING_GUARD)
3089 *tune_state = CT_DEMOD_STEP_2;
3090 else
3091 state->autosearch_state = AS_DONE;
3092 break;
3093 case 3: /* Autosearch FFT max correlation endded */
3094 *tune_state = CT_DEMOD_STEP_2;
3095 break;
3096 }
3097 break;
3098
3099 case CT_DEMOD_STEP_2:
3100 switch (state->autosearch_state) {
3101 case AS_SEARCHING_FFT:
3102 /* searching for the correct FFT */
3103 if (state->revision == 0x8090) {
3104 corm[2] = (dib8000_read_word(state, 596) << 16) | (dib8000_read_word(state, 597));
3105 corm[1] = (dib8000_read_word(state, 598) << 16) | (dib8000_read_word(state, 599));
3106 corm[0] = (dib8000_read_word(state, 600) << 16) | (dib8000_read_word(state, 601));
3107 } else {
3108 corm[2] = (dib8000_read_word(state, 594) << 16) | (dib8000_read_word(state, 595));
3109 corm[1] = (dib8000_read_word(state, 596) << 16) | (dib8000_read_word(state, 597));
3110 corm[0] = (dib8000_read_word(state, 598) << 16) | (dib8000_read_word(state, 599));
3111 }
Mauro Carvalho Chehab8af16ad2016-10-14 10:05:46 -03003112 /* dprintk("corm fft: %u %u %u\n", corm[0], corm[1], corm[2]); */
Mauro Carvalho Chehab7fa676c2014-07-04 14:15:29 -03003113
3114 max_value = 0;
3115 for (find_index = 1 ; find_index < 3 ; find_index++) {
3116 if (corm[max_value] < corm[find_index])
3117 max_value = find_index ;
3118 }
3119
3120 switch (max_value) {
3121 case 0:
3122 state->found_nfft = TRANSMISSION_MODE_2K;
3123 break;
3124 case 1:
3125 state->found_nfft = TRANSMISSION_MODE_4K;
3126 break;
3127 case 2:
3128 default:
3129 state->found_nfft = TRANSMISSION_MODE_8K;
3130 break;
3131 }
Mauro Carvalho Chehab8af16ad2016-10-14 10:05:46 -03003132 /* dprintk("Autosearch FFT has found Mode %d\n", max_value + 1); */
Mauro Carvalho Chehab7fa676c2014-07-04 14:15:29 -03003133
3134 *tune_state = CT_DEMOD_SEARCH_NEXT;
3135 state->autosearch_state = AS_SEARCHING_GUARD;
Patrick Boettcher173a64c2013-04-22 12:45:52 -03003136 if (state->revision == 0x8090)
3137 ret = 50;
3138 else
Mauro Carvalho Chehab7fa676c2014-07-04 14:15:29 -03003139 ret = 10;
Patrick Boettcher173a64c2013-04-22 12:45:52 -03003140 break;
Mauro Carvalho Chehab7fa676c2014-07-04 14:15:29 -03003141 case AS_SEARCHING_GUARD:
3142 /* searching for the correct guard interval */
3143 if (state->revision == 0x8090)
3144 state->found_guard = dib8000_read_word(state, 572) & 0x3;
3145 else
3146 state->found_guard = dib8000_read_word(state, 570) & 0x3;
Mauro Carvalho Chehab8af16ad2016-10-14 10:05:46 -03003147 /* dprintk("guard interval found=%i\n", state->found_guard); */
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003148
Mauro Carvalho Chehab7fa676c2014-07-04 14:15:29 -03003149 *tune_state = CT_DEMOD_STEP_3;
Patrick Boettcher173a64c2013-04-22 12:45:52 -03003150 break;
Mauro Carvalho Chehab7fa676c2014-07-04 14:15:29 -03003151 default:
3152 /* the demod should never be in this state */
3153 state->status = FE_STATUS_TUNE_FAILED;
3154 state->autosearch_state = AS_DONE;
3155 *tune_state = CT_DEMOD_STOP; /* else we are done here */
Patrick Boettcher173a64c2013-04-22 12:45:52 -03003156 break;
Mauro Carvalho Chehab7fa676c2014-07-04 14:15:29 -03003157 }
3158 break;
Patrick Boettcher173a64c2013-04-22 12:45:52 -03003159
3160 case CT_DEMOD_STEP_3: /* 33 */
Mauro Carvalho Chehab7fa676c2014-07-04 14:15:29 -03003161 dib8000_set_isdbt_loop_params(state, LOOP_TUNE_1);
3162 dib8000_set_isdbt_common_channel(state, 0, 0);/* setting the known channel parameters here */
3163 *tune_state = CT_DEMOD_STEP_4;
3164 break;
Patrick Boettcher173a64c2013-04-22 12:45:52 -03003165
3166 case CT_DEMOD_STEP_4: /* (34) */
Mauro Carvalho Chehab7fa676c2014-07-04 14:15:29 -03003167 dib8000_demod_restart(state);
Patrick Boettcher173a64c2013-04-22 12:45:52 -03003168
Mauro Carvalho Chehab7fa676c2014-07-04 14:15:29 -03003169 dib8000_set_sync_wait(state);
3170 dib8000_set_diversity_in(state->fe[0], state->diversity_onoff);
Patrick Boettcher173a64c2013-04-22 12:45:52 -03003171
Mauro Carvalho Chehab7fa676c2014-07-04 14:15:29 -03003172 locks = (dib8000_read_word(state, 180) >> 6) & 0x3f; /* P_coff_winlen ? */
3173 /* coff should lock over P_coff_winlen ofdm symbols : give 3 times this length to lock */
3174 *timeout = dib8000_get_timeout(state, 2 * locks, SYMBOL_DEPENDENT_ON);
3175 *tune_state = CT_DEMOD_STEP_5;
3176 break;
Patrick Boettcher173a64c2013-04-22 12:45:52 -03003177
3178 case CT_DEMOD_STEP_5: /* (35) */
Mauro Carvalho Chehab7fa676c2014-07-04 14:15:29 -03003179 locks = dib8000_read_lock(fe);
3180 if (locks & (0x3 << 11)) { /* coff-lock and off_cpil_lock achieved */
3181 dib8000_update_timf(state); /* we achieved a coff_cpil_lock - it's time to update the timf */
3182 if (!state->differential_constellation) {
3183 /* 2 times lmod4_win_len + 10 symbols (pipe delay after coff + nb to compute a 1st correlation) */
3184 *timeout = dib8000_get_timeout(state, (20 * ((dib8000_read_word(state, 188)>>5)&0x1f)), SYMBOL_DEPENDENT_ON);
3185 *tune_state = CT_DEMOD_STEP_7;
3186 } else {
3187 *tune_state = CT_DEMOD_STEP_8;
Patrick Boettcher173a64c2013-04-22 12:45:52 -03003188 }
Mauro Carvalho Chehabd6c62b72014-07-04 14:15:37 -03003189 } else if (time_after(now, *timeout)) {
Mauro Carvalho Chehab7fa676c2014-07-04 14:15:29 -03003190 *tune_state = CT_DEMOD_STEP_6; /* goto check for diversity input connection */
3191 }
3192 break;
Patrick Boettcher173a64c2013-04-22 12:45:52 -03003193
3194 case CT_DEMOD_STEP_6: /* (36) if there is an input (diversity) */
Mauro Carvalho Chehab7fa676c2014-07-04 14:15:29 -03003195 if ((state->fe[1] != NULL) && (state->output_mode != OUTMODE_DIVERSITY)) {
3196 /* if there is a diversity fe in input and this fe is has not already failled : wait here until this this fe has succedeed or failled */
3197 if (dib8000_get_status(state->fe[1]) <= FE_STATUS_STD_SUCCESS) /* Something is locked on the input fe */
3198 *tune_state = CT_DEMOD_STEP_8; /* go for mpeg */
3199 else if (dib8000_get_status(state->fe[1]) >= FE_STATUS_TUNE_TIME_TOO_SHORT) { /* fe in input failled also, break the current one */
3200 *tune_state = CT_DEMOD_STOP; /* else we are done here ; step 8 will close the loops and exit */
Patrick Boettcher173a64c2013-04-22 12:45:52 -03003201 dib8000_viterbi_state(state, 1); /* start viterbi chandec */
3202 dib8000_set_isdbt_loop_params(state, LOOP_TUNE_2);
Patrick Boettcher173a64c2013-04-22 12:45:52 -03003203 state->status = FE_STATUS_TUNE_FAILED;
3204 }
Mauro Carvalho Chehab7fa676c2014-07-04 14:15:29 -03003205 } else {
Patrick Boettcher173a64c2013-04-22 12:45:52 -03003206 dib8000_viterbi_state(state, 1); /* start viterbi chandec */
3207 dib8000_set_isdbt_loop_params(state, LOOP_TUNE_2);
Mauro Carvalho Chehab7fa676c2014-07-04 14:15:29 -03003208 *tune_state = CT_DEMOD_STOP; /* else we are done here ; step 8 will close the loops and exit */
3209 state->status = FE_STATUS_TUNE_FAILED;
3210 }
3211 break;
Patrick Boettcher173a64c2013-04-22 12:45:52 -03003212
Mauro Carvalho Chehab7fa676c2014-07-04 14:15:29 -03003213 case CT_DEMOD_STEP_7: /* 37 */
3214 locks = dib8000_read_lock(fe);
3215 if (locks & (1<<10)) { /* lmod4_lock */
3216 ret = 14; /* wait for 14 symbols */
3217 *tune_state = CT_DEMOD_STEP_8;
Mauro Carvalho Chehabd6c62b72014-07-04 14:15:37 -03003218 } else if (time_after(now, *timeout))
Mauro Carvalho Chehab7fa676c2014-07-04 14:15:29 -03003219 *tune_state = CT_DEMOD_STEP_6; /* goto check for diversity input connection */
3220 break;
3221
3222 case CT_DEMOD_STEP_8: /* 38 */
3223 dib8000_viterbi_state(state, 1); /* start viterbi chandec */
3224 dib8000_set_isdbt_loop_params(state, LOOP_TUNE_2);
3225
3226 /* mpeg will never lock on this condition because init_prbs is not set : search for it !*/
3227 if (c->isdbt_sb_mode
3228 && c->isdbt_sb_subchannel < 14
3229 && !state->differential_constellation) {
3230 state->subchannel = 0;
3231 *tune_state = CT_DEMOD_STEP_11;
3232 } else {
3233 *tune_state = CT_DEMOD_STEP_9;
3234 state->status = FE_STATUS_LOCKED;
3235 }
3236 break;
Patrick Boettcher173a64c2013-04-22 12:45:52 -03003237
3238 case CT_DEMOD_STEP_9: /* 39 */
Mauro Carvalho Chehab7fa676c2014-07-04 14:15:29 -03003239 if ((state->revision == 0x8090) || ((dib8000_read_word(state, 1291) >> 9) & 0x1)) { /* fe capable of deinterleaving : esram */
3240 /* defines timeout for mpeg lock depending on interleaver length of longest layer */
3241 for (i = 0; i < 3; i++) {
3242 if (c->layer[i].interleaving >= deeper_interleaver) {
Mauro Carvalho Chehab8af16ad2016-10-14 10:05:46 -03003243 dprintk("layer%i: time interleaver = %d\n", i, c->layer[i].interleaving);
Mauro Carvalho Chehab7fa676c2014-07-04 14:15:29 -03003244 if (c->layer[i].segment_count > 0) { /* valid layer */
3245 deeper_interleaver = c->layer[0].interleaving;
3246 state->longest_intlv_layer = i;
Patrick Boettcher173a64c2013-04-22 12:45:52 -03003247 }
3248 }
Mauro Carvalho Chehab7fa676c2014-07-04 14:15:29 -03003249 }
Patrick Boettcher173a64c2013-04-22 12:45:52 -03003250
Mauro Carvalho Chehab7fa676c2014-07-04 14:15:29 -03003251 if (deeper_interleaver == 0)
3252 locks = 2; /* locks is the tmp local variable name */
3253 else if (deeper_interleaver == 3)
3254 locks = 8;
3255 else
3256 locks = 2 * deeper_interleaver;
Patrick Boettcher173a64c2013-04-22 12:45:52 -03003257
Mauro Carvalho Chehab7fa676c2014-07-04 14:15:29 -03003258 if (state->diversity_onoff != 0) /* because of diversity sync */
3259 locks *= 2;
Patrick Boettcher173a64c2013-04-22 12:45:52 -03003260
Mauro Carvalho Chehabd6c62b72014-07-04 14:15:37 -03003261 *timeout = now + msecs_to_jiffies(200 * locks); /* give the mpeg lock 800ms if sram is present */
Mauro Carvalho Chehab8af16ad2016-10-14 10:05:46 -03003262 dprintk("Deeper interleaver mode = %d on layer %d : timeout mult factor = %d => will use timeout = %ld\n",
Mauro Carvalho Chehabd6c62b72014-07-04 14:15:37 -03003263 deeper_interleaver, state->longest_intlv_layer, locks, *timeout);
Patrick Boettcher173a64c2013-04-22 12:45:52 -03003264
Mauro Carvalho Chehab7fa676c2014-07-04 14:15:29 -03003265 *tune_state = CT_DEMOD_STEP_10;
3266 } else
3267 *tune_state = CT_DEMOD_STOP;
3268 break;
Patrick Boettcher173a64c2013-04-22 12:45:52 -03003269
3270 case CT_DEMOD_STEP_10: /* 40 */
Mauro Carvalho Chehab7fa676c2014-07-04 14:15:29 -03003271 locks = dib8000_read_lock(fe);
3272 if (locks&(1<<(7-state->longest_intlv_layer))) { /* mpeg lock : check the longest one */
Mauro Carvalho Chehab8af16ad2016-10-14 10:05:46 -03003273 dprintk("ISDB-T layer locks: Layer A %s, Layer B %s, Layer C %s\n",
Mauro Carvalho Chehab3c0d3942014-07-04 14:15:40 -03003274 c->layer[0].segment_count ? (locks >> 7) & 0x1 ? "locked" : "NOT LOCKED" : "not enabled",
3275 c->layer[1].segment_count ? (locks >> 6) & 0x1 ? "locked" : "NOT LOCKED" : "not enabled",
3276 c->layer[2].segment_count ? (locks >> 5) & 0x1 ? "locked" : "NOT LOCKED" : "not enabled");
Mauro Carvalho Chehab7fa676c2014-07-04 14:15:29 -03003277 if (c->isdbt_sb_mode
3278 && c->isdbt_sb_subchannel < 14
3279 && !state->differential_constellation)
3280 /* signal to the upper layer, that there was a channel found and the parameters can be read */
3281 state->status = FE_STATUS_DEMOD_SUCCESS;
3282 else
3283 state->status = FE_STATUS_DATA_LOCKED;
3284 *tune_state = CT_DEMOD_STOP;
Mauro Carvalho Chehabd6c62b72014-07-04 14:15:37 -03003285 } else if (time_after(now, *timeout)) {
Mauro Carvalho Chehab7fa676c2014-07-04 14:15:29 -03003286 if (c->isdbt_sb_mode
3287 && c->isdbt_sb_subchannel < 14
3288 && !state->differential_constellation) { /* continue to try init prbs autosearch */
3289 state->subchannel += 3;
3290 *tune_state = CT_DEMOD_STEP_11;
3291 } else { /* we are done mpeg of the longest interleaver xas not locking but let's try if an other layer has locked in the same time */
Mauro Carvalho Chehab3c0d3942014-07-04 14:15:40 -03003292 if (locks & (0x7 << 5)) {
Mauro Carvalho Chehab8af16ad2016-10-14 10:05:46 -03003293 dprintk("Not all ISDB-T layers locked in %d ms: Layer A %s, Layer B %s, Layer C %s\n",
Mauro Carvalho Chehab3c0d3942014-07-04 14:15:40 -03003294 jiffies_to_msecs(now - *timeout),
3295 c->layer[0].segment_count ? (locks >> 7) & 0x1 ? "locked" : "NOT LOCKED" : "not enabled",
3296 c->layer[1].segment_count ? (locks >> 6) & 0x1 ? "locked" : "NOT LOCKED" : "not enabled",
3297 c->layer[2].segment_count ? (locks >> 5) & 0x1 ? "locked" : "NOT LOCKED" : "not enabled");
3298
Patrick Boettcher173a64c2013-04-22 12:45:52 -03003299 state->status = FE_STATUS_DATA_LOCKED;
Mauro Carvalho Chehab7fa676c2014-07-04 14:15:29 -03003300 } else
3301 state->status = FE_STATUS_TUNE_FAILED;
Patrick Boettcher173a64c2013-04-22 12:45:52 -03003302 *tune_state = CT_DEMOD_STOP;
Patrick Boettcher173a64c2013-04-22 12:45:52 -03003303 }
Mauro Carvalho Chehab7fa676c2014-07-04 14:15:29 -03003304 }
3305 break;
Patrick Boettcher173a64c2013-04-22 12:45:52 -03003306
3307 case CT_DEMOD_STEP_11: /* 41 : init prbs autosearch */
Mauro Carvalho Chehab7fa676c2014-07-04 14:15:29 -03003308 if (state->subchannel <= 41) {
3309 dib8000_set_subchannel_prbs(state, dib8000_get_init_prbs(state, state->subchannel));
3310 *tune_state = CT_DEMOD_STEP_9;
3311 } else {
3312 *tune_state = CT_DEMOD_STOP;
3313 state->status = FE_STATUS_TUNE_FAILED;
3314 }
3315 break;
Patrick Boettcher173a64c2013-04-22 12:45:52 -03003316
3317 default:
Mauro Carvalho Chehab7fa676c2014-07-04 14:15:29 -03003318 break;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003319 }
3320
Patrick Boettcher173a64c2013-04-22 12:45:52 -03003321 /* tuning is finished - cleanup the demod */
3322 switch (*tune_state) {
3323 case CT_DEMOD_STOP: /* (42) */
3324#ifdef DIB8000_AGC_FREEZE
Mauro Carvalho Chehab7fa676c2014-07-04 14:15:29 -03003325 if ((state->revision != 0x8090) && (state->agc1_max != 0)) {
3326 dib8000_write_word(state, 108, state->agc1_max);
3327 dib8000_write_word(state, 109, state->agc1_min);
3328 dib8000_write_word(state, 110, state->agc2_max);
3329 dib8000_write_word(state, 111, state->agc2_min);
3330 state->agc1_max = 0;
3331 state->agc1_min = 0;
3332 state->agc2_max = 0;
3333 state->agc2_min = 0;
3334 }
Patrick Boettcher173a64c2013-04-22 12:45:52 -03003335#endif
Mauro Carvalho Chehabd6c62b72014-07-04 14:15:37 -03003336 ret = 0;
Mauro Carvalho Chehab7fa676c2014-07-04 14:15:29 -03003337 break;
Patrick Boettcher173a64c2013-04-22 12:45:52 -03003338 default:
Mauro Carvalho Chehab7fa676c2014-07-04 14:15:29 -03003339 break;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003340 }
3341
Patrick Boettcher173a64c2013-04-22 12:45:52 -03003342 if ((ret > 0) && (*tune_state > CT_DEMOD_STEP_3))
3343 return ret * state->symbol_duration;
3344 if ((ret > 0) && (ret < state->symbol_duration))
3345 return state->symbol_duration; /* at least one symbol */
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003346 return ret;
3347}
3348
3349static int dib8000_wakeup(struct dvb_frontend *fe)
3350{
3351 struct dib8000_state *state = fe->demodulator_priv;
Olivier Grenie4c70e072011-01-03 15:33:37 -03003352 u8 index_frontend;
3353 int ret;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003354
Olivier Grenie0c32dbd2011-08-10 05:17:18 -03003355 dib8000_set_power_mode(state, DIB8000_POWER_ALL);
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003356 dib8000_set_adc_state(state, DIBX000_ADC_ON);
3357 if (dib8000_set_adc_state(state, DIBX000_SLOW_ADC_ON) != 0)
Mauro Carvalho Chehab8af16ad2016-10-14 10:05:46 -03003358 dprintk("could not start Slow ADC\n");
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003359
Patrick Boettcher173a64c2013-04-22 12:45:52 -03003360 if (state->revision == 0x8090)
Olivier Grenie0c32dbd2011-08-10 05:17:18 -03003361 dib8000_sad_calib(state);
3362
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03003363 for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
Olivier Grenie4c70e072011-01-03 15:33:37 -03003364 ret = state->fe[index_frontend]->ops.init(state->fe[index_frontend]);
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03003365 if (ret < 0)
Olivier Grenie4c70e072011-01-03 15:33:37 -03003366 return ret;
3367 }
3368
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003369 return 0;
3370}
3371
3372static int dib8000_sleep(struct dvb_frontend *fe)
3373{
Olivier Grenie4c70e072011-01-03 15:33:37 -03003374 struct dib8000_state *state = fe->demodulator_priv;
3375 u8 index_frontend;
3376 int ret;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003377
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03003378 for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
Olivier Grenie4c70e072011-01-03 15:33:37 -03003379 ret = state->fe[index_frontend]->ops.sleep(state->fe[index_frontend]);
3380 if (ret < 0)
3381 return ret;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003382 }
Olivier Grenie4c70e072011-01-03 15:33:37 -03003383
Olivier Grenie0c32dbd2011-08-10 05:17:18 -03003384 if (state->revision != 0x8090)
3385 dib8000_set_output_mode(fe, OUTMODE_HIGH_Z);
3386 dib8000_set_power_mode(state, DIB8000_POWER_INTERFACE_ONLY);
Olivier Grenie4c70e072011-01-03 15:33:37 -03003387 return dib8000_set_adc_state(state, DIBX000_SLOW_ADC_OFF) | dib8000_set_adc_state(state, DIBX000_ADC_OFF);
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003388}
3389
Mauro Carvalho Chehab0df289a2015-06-07 14:53:52 -03003390static int dib8000_read_status(struct dvb_frontend *fe, enum fe_status *stat);
Mauro Carvalho Chehab70315b32013-12-15 07:41:20 -02003391
Mauro Carvalho Chehab7e3e68b2016-02-04 12:58:30 -02003392static int dib8000_get_frontend(struct dvb_frontend *fe,
3393 struct dtv_frontend_properties *c)
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003394{
3395 struct dib8000_state *state = fe->demodulator_priv;
3396 u16 i, val = 0;
Mauro Carvalho Chehab0df289a2015-06-07 14:53:52 -03003397 enum fe_status stat = 0;
Olivier Grenie4c70e072011-01-03 15:33:37 -03003398 u8 index_frontend, sub_index_frontend;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003399
Mauro Carvalho Chehab7e3e68b2016-02-04 12:58:30 -02003400 c->bandwidth_hz = 6000000;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003401
Mauro Carvalho Chehab70315b32013-12-15 07:41:20 -02003402 /*
3403 * If called to early, get_frontend makes dib8000_tune to either
3404 * not lock or not sync. This causes dvbv5-scan/dvbv5-zap to fail.
3405 * So, let's just return if frontend 0 has not locked.
3406 */
3407 dib8000_read_status(fe, &stat);
3408 if (!(stat & FE_HAS_SYNC))
3409 return 0;
3410
Mauro Carvalho Chehab8af16ad2016-10-14 10:05:46 -03003411 dprintk("dib8000_get_frontend: TMCC lock\n");
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03003412 for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
Olivier Grenie4c70e072011-01-03 15:33:37 -03003413 state->fe[index_frontend]->ops.read_status(state->fe[index_frontend], &stat);
3414 if (stat&FE_HAS_SYNC) {
Mauro Carvalho Chehab8af16ad2016-10-14 10:05:46 -03003415 dprintk("TMCC lock on the slave%i\n", index_frontend);
Olivier Grenie4c70e072011-01-03 15:33:37 -03003416 /* synchronize the cache with the other frontends */
Mauro Carvalho Chehab7e3e68b2016-02-04 12:58:30 -02003417 state->fe[index_frontend]->ops.get_frontend(state->fe[index_frontend], c);
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03003418 for (sub_index_frontend = 0; (sub_index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[sub_index_frontend] != NULL); sub_index_frontend++) {
Olivier Grenie4c70e072011-01-03 15:33:37 -03003419 if (sub_index_frontend != index_frontend) {
3420 state->fe[sub_index_frontend]->dtv_property_cache.isdbt_sb_mode = state->fe[index_frontend]->dtv_property_cache.isdbt_sb_mode;
3421 state->fe[sub_index_frontend]->dtv_property_cache.inversion = state->fe[index_frontend]->dtv_property_cache.inversion;
3422 state->fe[sub_index_frontend]->dtv_property_cache.transmission_mode = state->fe[index_frontend]->dtv_property_cache.transmission_mode;
3423 state->fe[sub_index_frontend]->dtv_property_cache.guard_interval = state->fe[index_frontend]->dtv_property_cache.guard_interval;
3424 state->fe[sub_index_frontend]->dtv_property_cache.isdbt_partial_reception = state->fe[index_frontend]->dtv_property_cache.isdbt_partial_reception;
3425 for (i = 0; i < 3; i++) {
3426 state->fe[sub_index_frontend]->dtv_property_cache.layer[i].segment_count = state->fe[index_frontend]->dtv_property_cache.layer[i].segment_count;
3427 state->fe[sub_index_frontend]->dtv_property_cache.layer[i].interleaving = state->fe[index_frontend]->dtv_property_cache.layer[i].interleaving;
3428 state->fe[sub_index_frontend]->dtv_property_cache.layer[i].fec = state->fe[index_frontend]->dtv_property_cache.layer[i].fec;
3429 state->fe[sub_index_frontend]->dtv_property_cache.layer[i].modulation = state->fe[index_frontend]->dtv_property_cache.layer[i].modulation;
3430 }
3431 }
3432 }
3433 return 0;
3434 }
3435 }
3436
Mauro Carvalho Chehab7e3e68b2016-02-04 12:58:30 -02003437 c->isdbt_sb_mode = dib8000_read_word(state, 508) & 0x1;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003438
Olivier Grenie0c32dbd2011-08-10 05:17:18 -03003439 if (state->revision == 0x8090)
3440 val = dib8000_read_word(state, 572);
3441 else
3442 val = dib8000_read_word(state, 570);
Mauro Carvalho Chehab7e3e68b2016-02-04 12:58:30 -02003443 c->inversion = (val & 0x40) >> 6;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003444 switch ((val & 0x30) >> 4) {
3445 case 1:
Mauro Carvalho Chehab7e3e68b2016-02-04 12:58:30 -02003446 c->transmission_mode = TRANSMISSION_MODE_2K;
Mauro Carvalho Chehab8af16ad2016-10-14 10:05:46 -03003447 dprintk("dib8000_get_frontend: transmission mode 2K\n");
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003448 break;
Mauro Carvalho Chehab7fec1c82014-07-04 14:15:30 -03003449 case 2:
Mauro Carvalho Chehab7e3e68b2016-02-04 12:58:30 -02003450 c->transmission_mode = TRANSMISSION_MODE_4K;
Mauro Carvalho Chehab8af16ad2016-10-14 10:05:46 -03003451 dprintk("dib8000_get_frontend: transmission mode 4K\n");
Mauro Carvalho Chehab7fec1c82014-07-04 14:15:30 -03003452 break;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003453 case 3:
3454 default:
Mauro Carvalho Chehab7e3e68b2016-02-04 12:58:30 -02003455 c->transmission_mode = TRANSMISSION_MODE_8K;
Mauro Carvalho Chehab8af16ad2016-10-14 10:05:46 -03003456 dprintk("dib8000_get_frontend: transmission mode 8K\n");
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003457 break;
3458 }
3459
3460 switch (val & 0x3) {
3461 case 0:
Mauro Carvalho Chehab7e3e68b2016-02-04 12:58:30 -02003462 c->guard_interval = GUARD_INTERVAL_1_32;
Mauro Carvalho Chehab8af16ad2016-10-14 10:05:46 -03003463 dprintk("dib8000_get_frontend: Guard Interval = 1/32\n");
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003464 break;
3465 case 1:
Mauro Carvalho Chehab7e3e68b2016-02-04 12:58:30 -02003466 c->guard_interval = GUARD_INTERVAL_1_16;
Mauro Carvalho Chehab8af16ad2016-10-14 10:05:46 -03003467 dprintk("dib8000_get_frontend: Guard Interval = 1/16\n");
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003468 break;
3469 case 2:
Mauro Carvalho Chehab8af16ad2016-10-14 10:05:46 -03003470 dprintk("dib8000_get_frontend: Guard Interval = 1/8\n");
Mauro Carvalho Chehab7e3e68b2016-02-04 12:58:30 -02003471 c->guard_interval = GUARD_INTERVAL_1_8;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003472 break;
3473 case 3:
Mauro Carvalho Chehab8af16ad2016-10-14 10:05:46 -03003474 dprintk("dib8000_get_frontend: Guard Interval = 1/4\n");
Mauro Carvalho Chehab7e3e68b2016-02-04 12:58:30 -02003475 c->guard_interval = GUARD_INTERVAL_1_4;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003476 break;
3477 }
3478
3479 val = dib8000_read_word(state, 505);
Mauro Carvalho Chehab7e3e68b2016-02-04 12:58:30 -02003480 c->isdbt_partial_reception = val & 1;
Mauro Carvalho Chehab8af16ad2016-10-14 10:05:46 -03003481 dprintk("dib8000_get_frontend: partial_reception = %d\n", c->isdbt_partial_reception);
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003482
3483 for (i = 0; i < 3; i++) {
Mauro Carvalho Chehabecc31d52014-07-04 14:15:39 -03003484 int show;
3485
3486 val = dib8000_read_word(state, 493 + i) & 0x0f;
Mauro Carvalho Chehab7e3e68b2016-02-04 12:58:30 -02003487 c->layer[i].segment_count = val;
Mauro Carvalho Chehabecc31d52014-07-04 14:15:39 -03003488
3489 if (val == 0 || val > 13)
3490 show = 0;
3491 else
3492 show = 1;
3493
3494 if (show)
Mauro Carvalho Chehab8af16ad2016-10-14 10:05:46 -03003495 dprintk("dib8000_get_frontend: Layer %d segments = %d\n",
Mauro Carvalho Chehab7e3e68b2016-02-04 12:58:30 -02003496 i, c->layer[i].segment_count);
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003497
Mauro Carvalho Chehab51fea112013-12-16 04:16:59 -03003498 val = dib8000_read_word(state, 499 + i) & 0x3;
3499 /* Interleaving can be 0, 1, 2 or 4 */
3500 if (val == 3)
3501 val = 4;
Mauro Carvalho Chehab7e3e68b2016-02-04 12:58:30 -02003502 c->layer[i].interleaving = val;
Mauro Carvalho Chehabecc31d52014-07-04 14:15:39 -03003503 if (show)
Mauro Carvalho Chehab8af16ad2016-10-14 10:05:46 -03003504 dprintk("dib8000_get_frontend: Layer %d time_intlv = %d\n",
Mauro Carvalho Chehab7e3e68b2016-02-04 12:58:30 -02003505 i, c->layer[i].interleaving);
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003506
3507 val = dib8000_read_word(state, 481 + i);
3508 switch (val & 0x7) {
3509 case 1:
Mauro Carvalho Chehab7e3e68b2016-02-04 12:58:30 -02003510 c->layer[i].fec = FEC_1_2;
Mauro Carvalho Chehabecc31d52014-07-04 14:15:39 -03003511 if (show)
Mauro Carvalho Chehab8af16ad2016-10-14 10:05:46 -03003512 dprintk("dib8000_get_frontend: Layer %d Code Rate = 1/2\n", i);
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003513 break;
3514 case 2:
Mauro Carvalho Chehab7e3e68b2016-02-04 12:58:30 -02003515 c->layer[i].fec = FEC_2_3;
Mauro Carvalho Chehabecc31d52014-07-04 14:15:39 -03003516 if (show)
Mauro Carvalho Chehab8af16ad2016-10-14 10:05:46 -03003517 dprintk("dib8000_get_frontend: Layer %d Code Rate = 2/3\n", i);
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003518 break;
3519 case 3:
Mauro Carvalho Chehab7e3e68b2016-02-04 12:58:30 -02003520 c->layer[i].fec = FEC_3_4;
Mauro Carvalho Chehabecc31d52014-07-04 14:15:39 -03003521 if (show)
Mauro Carvalho Chehab8af16ad2016-10-14 10:05:46 -03003522 dprintk("dib8000_get_frontend: Layer %d Code Rate = 3/4\n", i);
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003523 break;
3524 case 5:
Mauro Carvalho Chehab7e3e68b2016-02-04 12:58:30 -02003525 c->layer[i].fec = FEC_5_6;
Mauro Carvalho Chehabecc31d52014-07-04 14:15:39 -03003526 if (show)
Mauro Carvalho Chehab8af16ad2016-10-14 10:05:46 -03003527 dprintk("dib8000_get_frontend: Layer %d Code Rate = 5/6\n", i);
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003528 break;
3529 default:
Mauro Carvalho Chehab7e3e68b2016-02-04 12:58:30 -02003530 c->layer[i].fec = FEC_7_8;
Mauro Carvalho Chehabecc31d52014-07-04 14:15:39 -03003531 if (show)
Mauro Carvalho Chehab8af16ad2016-10-14 10:05:46 -03003532 dprintk("dib8000_get_frontend: Layer %d Code Rate = 7/8\n", i);
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003533 break;
3534 }
3535
3536 val = dib8000_read_word(state, 487 + i);
3537 switch (val & 0x3) {
3538 case 0:
Mauro Carvalho Chehab7e3e68b2016-02-04 12:58:30 -02003539 c->layer[i].modulation = DQPSK;
Mauro Carvalho Chehabecc31d52014-07-04 14:15:39 -03003540 if (show)
Mauro Carvalho Chehab8af16ad2016-10-14 10:05:46 -03003541 dprintk("dib8000_get_frontend: Layer %d DQPSK\n", i);
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003542 break;
3543 case 1:
Mauro Carvalho Chehab7e3e68b2016-02-04 12:58:30 -02003544 c->layer[i].modulation = QPSK;
Mauro Carvalho Chehabecc31d52014-07-04 14:15:39 -03003545 if (show)
Mauro Carvalho Chehab8af16ad2016-10-14 10:05:46 -03003546 dprintk("dib8000_get_frontend: Layer %d QPSK\n", i);
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003547 break;
3548 case 2:
Mauro Carvalho Chehab7e3e68b2016-02-04 12:58:30 -02003549 c->layer[i].modulation = QAM_16;
Mauro Carvalho Chehabecc31d52014-07-04 14:15:39 -03003550 if (show)
Mauro Carvalho Chehab8af16ad2016-10-14 10:05:46 -03003551 dprintk("dib8000_get_frontend: Layer %d QAM16\n", i);
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003552 break;
3553 case 3:
3554 default:
Mauro Carvalho Chehab7e3e68b2016-02-04 12:58:30 -02003555 c->layer[i].modulation = QAM_64;
Mauro Carvalho Chehabecc31d52014-07-04 14:15:39 -03003556 if (show)
Mauro Carvalho Chehab8af16ad2016-10-14 10:05:46 -03003557 dprintk("dib8000_get_frontend: Layer %d QAM64\n", i);
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003558 break;
3559 }
3560 }
Olivier Grenie4c70e072011-01-03 15:33:37 -03003561
3562 /* synchronize the cache with the other frontends */
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03003563 for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
Mauro Carvalho Chehab7e3e68b2016-02-04 12:58:30 -02003564 state->fe[index_frontend]->dtv_property_cache.isdbt_sb_mode = c->isdbt_sb_mode;
3565 state->fe[index_frontend]->dtv_property_cache.inversion = c->inversion;
3566 state->fe[index_frontend]->dtv_property_cache.transmission_mode = c->transmission_mode;
3567 state->fe[index_frontend]->dtv_property_cache.guard_interval = c->guard_interval;
3568 state->fe[index_frontend]->dtv_property_cache.isdbt_partial_reception = c->isdbt_partial_reception;
Olivier Grenie4c70e072011-01-03 15:33:37 -03003569 for (i = 0; i < 3; i++) {
Mauro Carvalho Chehab7e3e68b2016-02-04 12:58:30 -02003570 state->fe[index_frontend]->dtv_property_cache.layer[i].segment_count = c->layer[i].segment_count;
3571 state->fe[index_frontend]->dtv_property_cache.layer[i].interleaving = c->layer[i].interleaving;
3572 state->fe[index_frontend]->dtv_property_cache.layer[i].fec = c->layer[i].fec;
3573 state->fe[index_frontend]->dtv_property_cache.layer[i].modulation = c->layer[i].modulation;
Olivier Grenie4c70e072011-01-03 15:33:37 -03003574 }
3575 }
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003576 return 0;
3577}
3578
Mauro Carvalho Chehab490ecd62011-12-22 20:38:27 -03003579static int dib8000_set_frontend(struct dvb_frontend *fe)
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003580{
3581 struct dib8000_state *state = fe->demodulator_priv;
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03003582 struct dtv_frontend_properties *c = &state->fe[0]->dtv_property_cache;
Mauro Carvalho Chehabd6c62b72014-07-04 14:15:37 -03003583 int l, i, active, time, time_slave = 0;
Patrick Boettcher173a64c2013-04-22 12:45:52 -03003584 u8 exit_condition, index_frontend;
Mauro Carvalho Chehabd6c62b72014-07-04 14:15:37 -03003585 unsigned long delay, callback_time;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003586
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03003587 if (c->frequency == 0) {
Mauro Carvalho Chehab8af16ad2016-10-14 10:05:46 -03003588 dprintk("dib8000: must at least specify frequency\n");
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003589 return 0;
3590 }
3591
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03003592 if (c->bandwidth_hz == 0) {
Mauro Carvalho Chehab8af16ad2016-10-14 10:05:46 -03003593 dprintk("dib8000: no bandwidth specified, set to default\n");
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03003594 c->bandwidth_hz = 6000000;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003595 }
3596
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03003597 for (index_frontend = 0; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
Olivier Grenie4c70e072011-01-03 15:33:37 -03003598 /* synchronization of the cache */
3599 state->fe[index_frontend]->dtv_property_cache.delivery_system = SYS_ISDBT;
3600 memcpy(&state->fe[index_frontend]->dtv_property_cache, &fe->dtv_property_cache, sizeof(struct dtv_frontend_properties));
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003601
Patrick Boettcher173a64c2013-04-22 12:45:52 -03003602 /* set output mode and diversity input */
3603 if (state->revision != 0x8090) {
3604 dib8000_set_diversity_in(state->fe[index_frontend], 1);
3605 if (index_frontend != 0)
3606 dib8000_set_output_mode(state->fe[index_frontend],
3607 OUTMODE_DIVERSITY);
3608 else
3609 dib8000_set_output_mode(state->fe[0], OUTMODE_HIGH_Z);
3610 } else {
3611 dib8096p_set_diversity_in(state->fe[index_frontend], 1);
3612 if (index_frontend != 0)
3613 dib8096p_set_output_mode(state->fe[index_frontend],
3614 OUTMODE_DIVERSITY);
3615 else
3616 dib8096p_set_output_mode(state->fe[0], OUTMODE_HIGH_Z);
3617 }
3618
3619 /* tune the tuner */
Olivier Grenie4c70e072011-01-03 15:33:37 -03003620 if (state->fe[index_frontend]->ops.tuner_ops.set_params)
Mauro Carvalho Chehab14d24d12011-12-24 12:24:33 -03003621 state->fe[index_frontend]->ops.tuner_ops.set_params(state->fe[index_frontend]);
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003622
Olivier Grenie4c70e072011-01-03 15:33:37 -03003623 dib8000_set_tune_state(state->fe[index_frontend], CT_AGC_START);
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003624 }
3625
Patrick Boettcher173a64c2013-04-22 12:45:52 -03003626 /* turn off the diversity of the last chip */
3627 if (state->revision != 0x8090)
3628 dib8000_set_diversity_in(state->fe[index_frontend - 1], 0);
3629 else
3630 dib8096p_set_diversity_in(state->fe[index_frontend - 1], 0);
3631
Olivier Grenie4c70e072011-01-03 15:33:37 -03003632 /* start up the AGC */
3633 do {
3634 time = dib8000_agc_startup(state->fe[0]);
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03003635 for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
Olivier Grenie4c70e072011-01-03 15:33:37 -03003636 time_slave = dib8000_agc_startup(state->fe[index_frontend]);
Mauro Carvalho Chehabd6c62b72014-07-04 14:15:37 -03003637 if (time == 0)
Olivier Grenie4c70e072011-01-03 15:33:37 -03003638 time = time_slave;
Mauro Carvalho Chehabd6c62b72014-07-04 14:15:37 -03003639 else if ((time_slave != 0) && (time_slave > time))
Olivier Grenie4c70e072011-01-03 15:33:37 -03003640 time = time_slave;
3641 }
Mauro Carvalho Chehabd6c62b72014-07-04 14:15:37 -03003642 if (time == 0)
Olivier Grenie4c70e072011-01-03 15:33:37 -03003643 break;
Mauro Carvalho Chehab4607bb72014-07-04 14:15:35 -03003644
3645 /*
3646 * Despite dib8000_agc_startup returns time at a 0.1 ms range,
3647 * the actual sleep time depends on CONFIG_HZ. The worse case
3648 * is when CONFIG_HZ=100. In such case, the minimum granularity
3649 * is 10ms. On some real field tests, the tuner sometimes don't
3650 * lock when this timer is lower than 10ms. So, enforce a 10ms
3651 * granularity.
3652 */
3653 time = 10 * (time + 99)/100;
3654 usleep_range(time * 1000, (time + 1) * 1000);
Olivier Grenie4c70e072011-01-03 15:33:37 -03003655 exit_condition = 1;
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03003656 for (index_frontend = 0; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
Olivier Grenie4c70e072011-01-03 15:33:37 -03003657 if (dib8000_get_tune_state(state->fe[index_frontend]) != CT_AGC_STOP) {
3658 exit_condition = 0;
3659 break;
3660 }
3661 }
3662 } while (exit_condition == 0);
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003663
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03003664 for (index_frontend = 0; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++)
Olivier Grenie4c70e072011-01-03 15:33:37 -03003665 dib8000_set_tune_state(state->fe[index_frontend], CT_DEMOD_START);
3666
Patrick Boettcher173a64c2013-04-22 12:45:52 -03003667 active = 1;
3668 do {
Mauro Carvalho Chehabd6c62b72014-07-04 14:15:37 -03003669 callback_time = 0;
Mauro Carvalho Chehab2c2c4412011-01-16 13:02:52 -02003670 for (index_frontend = 0; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
Patrick Boettcher173a64c2013-04-22 12:45:52 -03003671 delay = dib8000_tune(state->fe[index_frontend]);
Mauro Carvalho Chehabd6c62b72014-07-04 14:15:37 -03003672 if (delay != 0) {
3673 delay = jiffies + usecs_to_jiffies(100 * delay);
3674 if (!callback_time || delay < callback_time)
3675 callback_time = delay;
3676 }
Olivier Grenie4c70e072011-01-03 15:33:37 -03003677
Patrick Boettcher173a64c2013-04-22 12:45:52 -03003678 /* we are in autosearch */
3679 if (state->channel_parameters_set == 0) { /* searching */
3680 if ((dib8000_get_status(state->fe[index_frontend]) == FE_STATUS_DEMOD_SUCCESS) || (dib8000_get_status(state->fe[index_frontend]) == FE_STATUS_FFT_SUCCESS)) {
Mauro Carvalho Chehab8af16ad2016-10-14 10:05:46 -03003681 dprintk("autosearch succeeded on fe%i\n", index_frontend);
Mauro Carvalho Chehab7e3e68b2016-02-04 12:58:30 -02003682 dib8000_get_frontend(state->fe[index_frontend], c); /* we read the channel parameters from the frontend which was successful */
Patrick Boettcher173a64c2013-04-22 12:45:52 -03003683 state->channel_parameters_set = 1;
3684
3685 for (l = 0; (l < MAX_NUMBER_OF_FRONTENDS) && (state->fe[l] != NULL); l++) {
3686 if (l != index_frontend) { /* and for all frontend except the successful one */
Mauro Carvalho Chehabecc31d52014-07-04 14:15:39 -03003687 dprintk("Restarting frontend %d\n", l);
Patrick Boettcher173a64c2013-04-22 12:45:52 -03003688 dib8000_tune_restart_from_demod(state->fe[l]);
3689
3690 state->fe[l]->dtv_property_cache.isdbt_sb_mode = state->fe[index_frontend]->dtv_property_cache.isdbt_sb_mode;
3691 state->fe[l]->dtv_property_cache.inversion = state->fe[index_frontend]->dtv_property_cache.inversion;
3692 state->fe[l]->dtv_property_cache.transmission_mode = state->fe[index_frontend]->dtv_property_cache.transmission_mode;
3693 state->fe[l]->dtv_property_cache.guard_interval = state->fe[index_frontend]->dtv_property_cache.guard_interval;
3694 state->fe[l]->dtv_property_cache.isdbt_partial_reception = state->fe[index_frontend]->dtv_property_cache.isdbt_partial_reception;
3695 for (i = 0; i < 3; i++) {
3696 state->fe[l]->dtv_property_cache.layer[i].segment_count = state->fe[index_frontend]->dtv_property_cache.layer[i].segment_count;
3697 state->fe[l]->dtv_property_cache.layer[i].interleaving = state->fe[index_frontend]->dtv_property_cache.layer[i].interleaving;
3698 state->fe[l]->dtv_property_cache.layer[i].fec = state->fe[index_frontend]->dtv_property_cache.layer[i].fec;
3699 state->fe[l]->dtv_property_cache.layer[i].modulation = state->fe[index_frontend]->dtv_property_cache.layer[i].modulation;
3700 }
3701
3702 }
Mauro Carvalho Chehab2c2c4412011-01-16 13:02:52 -02003703 }
3704 }
3705 }
Patrick Boettcher173a64c2013-04-22 12:45:52 -03003706 }
3707 /* tuning is done when the master frontend is done (failed or success) */
3708 if (dib8000_get_status(state->fe[0]) == FE_STATUS_TUNE_FAILED ||
3709 dib8000_get_status(state->fe[0]) == FE_STATUS_LOCKED ||
3710 dib8000_get_status(state->fe[0]) == FE_STATUS_DATA_LOCKED) {
3711 active = 0;
3712 /* we need to wait for all frontends to be finished */
3713 for (index_frontend = 0; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
3714 if (dib8000_get_tune_state(state->fe[index_frontend]) != CT_DEMOD_STOP)
3715 active = 1;
3716 }
3717 if (active == 0)
Mauro Carvalho Chehab8af16ad2016-10-14 10:05:46 -03003718 dprintk("tuning done with status %d\n", dib8000_get_status(state->fe[0]));
Mauro Carvalho Chehab2c2c4412011-01-16 13:02:52 -02003719 }
Olivier Grenie4c70e072011-01-03 15:33:37 -03003720
Mauro Carvalho Chehabd6c62b72014-07-04 14:15:37 -03003721 if ((active == 1) && (callback_time == 0)) {
Mauro Carvalho Chehab8af16ad2016-10-14 10:05:46 -03003722 dprintk("strange callback time something went wrong\n");
Patrick Boettcher173a64c2013-04-22 12:45:52 -03003723 active = 0;
3724 }
Olivier Grenie4c70e072011-01-03 15:33:37 -03003725
Mauro Carvalho Chehabd6c62b72014-07-04 14:15:37 -03003726 while ((active == 1) && (time_before(jiffies, callback_time)))
Patrick Boettcher173a64c2013-04-22 12:45:52 -03003727 msleep(100);
3728 } while (active);
Olivier Grenie4c70e072011-01-03 15:33:37 -03003729
Patrick Boettcher173a64c2013-04-22 12:45:52 -03003730 /* set output mode */
3731 if (state->revision != 0x8090)
Olivier Grenie0c32dbd2011-08-10 05:17:18 -03003732 dib8000_set_output_mode(state->fe[0], state->cfg.output_mode);
Patrick Boettcher173a64c2013-04-22 12:45:52 -03003733 else {
Olivier Grenie0c32dbd2011-08-10 05:17:18 -03003734 dib8096p_set_output_mode(state->fe[0], state->cfg.output_mode);
3735 if (state->cfg.enMpegOutput == 0) {
3736 dib8096p_setDibTxMux(state, MPEG_ON_DIBTX);
3737 dib8096p_setHostBusMux(state, DIBTX_ON_HOSTBUS);
3738 }
Olivier Grenie0c32dbd2011-08-10 05:17:18 -03003739 }
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003740
Geert Uytterhoeven4d8d5d92013-06-02 13:52:17 -03003741 return 0;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003742}
3743
Mauro Carvalho Chehab0df289a2015-06-07 14:53:52 -03003744static int dib8000_get_stats(struct dvb_frontend *fe, enum fe_status stat);
Mauro Carvalho Chehab6ef06e72013-12-16 19:10:59 -03003745
Mauro Carvalho Chehab0df289a2015-06-07 14:53:52 -03003746static int dib8000_read_status(struct dvb_frontend *fe, enum fe_status *stat)
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003747{
3748 struct dib8000_state *state = fe->demodulator_priv;
Olivier Grenie0c32dbd2011-08-10 05:17:18 -03003749 u16 lock_slave = 0, lock;
Olivier Grenie4c70e072011-01-03 15:33:37 -03003750 u8 index_frontend;
3751
Patrick Boettcher173a64c2013-04-22 12:45:52 -03003752 lock = dib8000_read_lock(fe);
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03003753 for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++)
Olivier Grenie4c70e072011-01-03 15:33:37 -03003754 lock_slave |= dib8000_read_lock(state->fe[index_frontend]);
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003755
3756 *stat = 0;
3757
Olivier Grenie4c70e072011-01-03 15:33:37 -03003758 if (((lock >> 13) & 1) || ((lock_slave >> 13) & 1))
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003759 *stat |= FE_HAS_SIGNAL;
3760
Olivier Grenie4c70e072011-01-03 15:33:37 -03003761 if (((lock >> 8) & 1) || ((lock_slave >> 8) & 1)) /* Equal */
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003762 *stat |= FE_HAS_CARRIER;
3763
Olivier Grenie4c70e072011-01-03 15:33:37 -03003764 if ((((lock >> 1) & 0xf) == 0xf) || (((lock_slave >> 1) & 0xf) == 0xf)) /* TMCC_SYNC */
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003765 *stat |= FE_HAS_SYNC;
3766
Olivier Grenie4c70e072011-01-03 15:33:37 -03003767 if ((((lock >> 12) & 1) || ((lock_slave >> 12) & 1)) && ((lock >> 5) & 7)) /* FEC MPEG */
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003768 *stat |= FE_HAS_LOCK;
3769
Olivier Grenie4c70e072011-01-03 15:33:37 -03003770 if (((lock >> 12) & 1) || ((lock_slave >> 12) & 1)) {
Olivier Grenie89dfc552009-11-30 06:38:49 -03003771 lock = dib8000_read_word(state, 554); /* Viterbi Layer A */
3772 if (lock & 0x01)
3773 *stat |= FE_HAS_VITERBI;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003774
Olivier Grenie89dfc552009-11-30 06:38:49 -03003775 lock = dib8000_read_word(state, 555); /* Viterbi Layer B */
3776 if (lock & 0x01)
3777 *stat |= FE_HAS_VITERBI;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003778
Olivier Grenie89dfc552009-11-30 06:38:49 -03003779 lock = dib8000_read_word(state, 556); /* Viterbi Layer C */
3780 if (lock & 0x01)
3781 *stat |= FE_HAS_VITERBI;
3782 }
Mauro Carvalho Chehab6ef06e72013-12-16 19:10:59 -03003783 dib8000_get_stats(fe, *stat);
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003784
3785 return 0;
3786}
3787
3788static int dib8000_read_ber(struct dvb_frontend *fe, u32 * ber)
3789{
3790 struct dib8000_state *state = fe->demodulator_priv;
Olivier Grenie0c32dbd2011-08-10 05:17:18 -03003791
3792 /* 13 segments */
3793 if (state->revision == 0x8090)
3794 *ber = (dib8000_read_word(state, 562) << 16) |
3795 dib8000_read_word(state, 563);
3796 else
3797 *ber = (dib8000_read_word(state, 560) << 16) |
3798 dib8000_read_word(state, 561);
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003799 return 0;
3800}
3801
3802static int dib8000_read_unc_blocks(struct dvb_frontend *fe, u32 * unc)
3803{
3804 struct dib8000_state *state = fe->demodulator_priv;
Olivier Grenie0c32dbd2011-08-10 05:17:18 -03003805
3806 /* packet error on 13 seg */
3807 if (state->revision == 0x8090)
3808 *unc = dib8000_read_word(state, 567);
3809 else
3810 *unc = dib8000_read_word(state, 565);
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003811 return 0;
3812}
3813
3814static int dib8000_read_signal_strength(struct dvb_frontend *fe, u16 * strength)
3815{
3816 struct dib8000_state *state = fe->demodulator_priv;
Olivier Grenie4c70e072011-01-03 15:33:37 -03003817 u8 index_frontend;
3818 u16 val;
3819
3820 *strength = 0;
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03003821 for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
Olivier Grenie4c70e072011-01-03 15:33:37 -03003822 state->fe[index_frontend]->ops.read_signal_strength(state->fe[index_frontend], &val);
3823 if (val > 65535 - *strength)
3824 *strength = 65535;
3825 else
3826 *strength += val;
3827 }
3828
3829 val = 65535 - dib8000_read_word(state, 390);
3830 if (val > 65535 - *strength)
3831 *strength = 65535;
3832 else
3833 *strength += val;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003834 return 0;
3835}
3836
Olivier Grenie4c70e072011-01-03 15:33:37 -03003837static u32 dib8000_get_snr(struct dvb_frontend *fe)
3838{
3839 struct dib8000_state *state = fe->demodulator_priv;
3840 u32 n, s, exp;
3841 u16 val;
3842
Olivier Grenie0c32dbd2011-08-10 05:17:18 -03003843 if (state->revision != 0x8090)
3844 val = dib8000_read_word(state, 542);
3845 else
3846 val = dib8000_read_word(state, 544);
Olivier Grenie4c70e072011-01-03 15:33:37 -03003847 n = (val >> 6) & 0xff;
3848 exp = (val & 0x3f);
3849 if ((exp & 0x20) != 0)
3850 exp -= 0x40;
3851 n <<= exp+16;
3852
Olivier Grenie0c32dbd2011-08-10 05:17:18 -03003853 if (state->revision != 0x8090)
3854 val = dib8000_read_word(state, 543);
3855 else
3856 val = dib8000_read_word(state, 545);
Olivier Grenie4c70e072011-01-03 15:33:37 -03003857 s = (val >> 6) & 0xff;
3858 exp = (val & 0x3f);
3859 if ((exp & 0x20) != 0)
3860 exp -= 0x40;
3861 s <<= exp+16;
3862
3863 if (n > 0) {
3864 u32 t = (s/n) << 16;
3865 return t + ((s << 16) - n*t) / n;
3866 }
3867 return 0xffffffff;
3868}
3869
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003870static int dib8000_read_snr(struct dvb_frontend *fe, u16 * snr)
3871{
3872 struct dib8000_state *state = fe->demodulator_priv;
Olivier Grenie4c70e072011-01-03 15:33:37 -03003873 u8 index_frontend;
3874 u32 snr_master;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003875
Olivier Grenie4c70e072011-01-03 15:33:37 -03003876 snr_master = dib8000_get_snr(fe);
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03003877 for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++)
Olivier Grenie4c70e072011-01-03 15:33:37 -03003878 snr_master += dib8000_get_snr(state->fe[index_frontend]);
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003879
Olivier Grenie1f6bfcc2011-07-04 12:33:54 -03003880 if ((snr_master >> 16) != 0) {
Olivier Grenie4c70e072011-01-03 15:33:37 -03003881 snr_master = 10*intlog10(snr_master>>16);
3882 *snr = snr_master / ((1 << 24) / 10);
3883 }
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003884 else
Olivier Grenie4c70e072011-01-03 15:33:37 -03003885 *snr = 0;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003886
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003887 return 0;
3888}
3889
Mauro Carvalho Chehab6ef06e72013-12-16 19:10:59 -03003890struct per_layer_regs {
3891 u16 lock, ber, per;
3892};
3893
3894static const struct per_layer_regs per_layer_regs[] = {
3895 { 554, 560, 562 },
3896 { 555, 576, 578 },
3897 { 556, 581, 583 },
3898};
3899
Mauro Carvalho Chehab42ff76b2013-12-16 21:45:19 -03003900struct linear_segments {
3901 unsigned x;
3902 signed y;
3903};
3904
3905/*
3906 * Table to estimate signal strength in dBm.
3907 * This table was empirically determinated by measuring the signal
3908 * strength generated by a DTA-2111 RF generator directly connected into
3909 * a dib8076 device (a PixelView PV-D231U stick), using a good quality
3910 * 3 meters RC6 cable and good RC6 connectors.
3911 * The real value can actually be different on other devices, depending
3912 * on several factors, like if LNA is enabled or not, if diversity is
3913 * enabled, type of connectors, etc.
3914 * Yet, it is better to use this measure in dB than a random non-linear
3915 * percentage value, especially for antenna adjustments.
3916 * On my tests, the precision of the measure using this table is about
3917 * 0.5 dB, with sounds reasonable enough.
3918 */
3919static struct linear_segments strength_to_db_table[] = {
3920 { 55953, 108500 }, /* -22.5 dBm */
3921 { 55394, 108000 },
3922 { 53834, 107000 },
3923 { 52863, 106000 },
3924 { 52239, 105000 },
3925 { 52012, 104000 },
3926 { 51803, 103000 },
3927 { 51566, 102000 },
3928 { 51356, 101000 },
3929 { 51112, 100000 },
3930 { 50869, 99000 },
3931 { 50600, 98000 },
3932 { 50363, 97000 },
3933 { 50117, 96000 }, /* -35 dBm */
3934 { 49889, 95000 },
3935 { 49680, 94000 },
3936 { 49493, 93000 },
3937 { 49302, 92000 },
3938 { 48929, 91000 },
3939 { 48416, 90000 },
3940 { 48035, 89000 },
3941 { 47593, 88000 },
3942 { 47282, 87000 },
3943 { 46953, 86000 },
3944 { 46698, 85000 },
3945 { 45617, 84000 },
3946 { 44773, 83000 },
3947 { 43845, 82000 },
3948 { 43020, 81000 },
3949 { 42010, 80000 }, /* -51 dBm */
3950 { 0, 0 },
3951};
3952
3953static u32 interpolate_value(u32 value, struct linear_segments *segments,
3954 unsigned len)
3955{
3956 u64 tmp64;
3957 u32 dx;
3958 s32 dy;
3959 int i, ret;
3960
3961 if (value >= segments[0].x)
3962 return segments[0].y;
3963 if (value < segments[len-1].x)
3964 return segments[len-1].y;
3965
3966 for (i = 1; i < len - 1; i++) {
3967 /* If value is identical, no need to interpolate */
3968 if (value == segments[i].x)
3969 return segments[i].y;
3970 if (value > segments[i].x)
3971 break;
3972 }
3973
3974 /* Linear interpolation between the two (x,y) points */
3975 dy = segments[i - 1].y - segments[i].y;
3976 dx = segments[i - 1].x - segments[i].x;
3977
3978 tmp64 = value - segments[i].x;
3979 tmp64 *= dy;
3980 do_div(tmp64, dx);
3981 ret = segments[i].y + tmp64;
3982
3983 return ret;
3984}
3985
Mauro Carvalho Chehab704f01b2013-12-17 10:08:20 -03003986static u32 dib8000_get_time_us(struct dvb_frontend *fe, int layer)
3987{
3988 struct dib8000_state *state = fe->demodulator_priv;
3989 struct dtv_frontend_properties *c = &state->fe[0]->dtv_property_cache;
3990 int ini_layer, end_layer, i;
Mauro Carvalho Chehab4bf48152013-12-20 08:11:31 -02003991 u64 time_us, tmp64;
Mauro Carvalho Chehab704f01b2013-12-17 10:08:20 -03003992 u32 tmp, denom;
Mauro Carvalho Chehabe4a3bc12014-01-13 15:14:33 -02003993 int guard, rate_num, rate_denum = 1, bits_per_symbol, nsegs;
3994 int interleaving = 0, fft_div;
Mauro Carvalho Chehab704f01b2013-12-17 10:08:20 -03003995
3996 if (layer >= 0) {
3997 ini_layer = layer;
3998 end_layer = layer + 1;
3999 } else {
4000 ini_layer = 0;
4001 end_layer = 3;
4002 }
4003
4004 switch (c->guard_interval) {
4005 case GUARD_INTERVAL_1_4:
4006 guard = 4;
4007 break;
4008 case GUARD_INTERVAL_1_8:
4009 guard = 8;
4010 break;
4011 case GUARD_INTERVAL_1_16:
4012 guard = 16;
4013 break;
4014 default:
4015 case GUARD_INTERVAL_1_32:
4016 guard = 32;
4017 break;
4018 }
4019
4020 switch (c->transmission_mode) {
4021 case TRANSMISSION_MODE_2K:
4022 fft_div = 4;
4023 break;
4024 case TRANSMISSION_MODE_4K:
4025 fft_div = 2;
4026 break;
4027 default:
4028 case TRANSMISSION_MODE_8K:
4029 fft_div = 1;
4030 break;
4031 }
4032
4033 denom = 0;
4034 for (i = ini_layer; i < end_layer; i++) {
4035 nsegs = c->layer[i].segment_count;
4036 if (nsegs == 0 || nsegs > 13)
4037 continue;
4038
4039 switch (c->layer[i].modulation) {
4040 case DQPSK:
4041 case QPSK:
4042 bits_per_symbol = 2;
4043 break;
4044 case QAM_16:
4045 bits_per_symbol = 4;
4046 break;
4047 default:
4048 case QAM_64:
4049 bits_per_symbol = 6;
4050 break;
4051 }
4052
4053 switch (c->layer[i].fec) {
4054 case FEC_1_2:
4055 rate_num = 1;
4056 rate_denum = 2;
4057 break;
4058 case FEC_2_3:
4059 rate_num = 2;
4060 rate_denum = 3;
4061 break;
4062 case FEC_3_4:
4063 rate_num = 3;
4064 rate_denum = 4;
4065 break;
4066 case FEC_5_6:
4067 rate_num = 5;
4068 rate_denum = 6;
4069 break;
4070 default:
4071 case FEC_7_8:
4072 rate_num = 7;
4073 rate_denum = 8;
4074 break;
4075 }
4076
4077 interleaving = c->layer[i].interleaving;
4078
4079 denom += bits_per_symbol * rate_num * fft_div * nsegs * 384;
4080 }
4081
4082 /* If all goes wrong, wait for 1s for the next stats */
4083 if (!denom)
4084 return 0;
4085
4086 /* Estimate the period for the total bit rate */
4087 time_us = rate_denum * (1008 * 1562500L);
Mauro Carvalho Chehab4bf48152013-12-20 08:11:31 -02004088 tmp64 = time_us;
4089 do_div(tmp64, guard);
4090 time_us = time_us + tmp64;
Mauro Carvalho Chehab704f01b2013-12-17 10:08:20 -03004091 time_us += denom / 2;
4092 do_div(time_us, denom);
4093
4094 tmp = 1008 * 96 * interleaving;
4095 time_us += tmp + tmp / guard;
4096
4097 return time_us;
4098}
4099
Mauro Carvalho Chehab0df289a2015-06-07 14:53:52 -03004100static int dib8000_get_stats(struct dvb_frontend *fe, enum fe_status stat)
Mauro Carvalho Chehab6ef06e72013-12-16 19:10:59 -03004101{
4102 struct dib8000_state *state = fe->demodulator_priv;
4103 struct dtv_frontend_properties *c = &state->fe[0]->dtv_property_cache;
Mauro Carvalho Chehab704f01b2013-12-17 10:08:20 -03004104 int i;
Mauro Carvalho Chehab0400c532013-12-17 11:34:22 -03004105 int show_per_stats = 0;
4106 u32 time_us = 0, snr, val;
4107 u64 blocks;
Mauro Carvalho Chehab42ff76b2013-12-16 21:45:19 -03004108 s32 db;
Mauro Carvalho Chehab6ef06e72013-12-16 19:10:59 -03004109 u16 strength;
4110
4111 /* Get Signal strength */
4112 dib8000_read_signal_strength(fe, &strength);
Mauro Carvalho Chehab42ff76b2013-12-16 21:45:19 -03004113 val = strength;
4114 db = interpolate_value(val,
4115 strength_to_db_table,
4116 ARRAY_SIZE(strength_to_db_table)) - 131000;
4117 c->strength.stat[0].svalue = db;
Mauro Carvalho Chehab6ef06e72013-12-16 19:10:59 -03004118
Mauro Carvalho Chehab704f01b2013-12-17 10:08:20 -03004119 /* UCB/BER/CNR measures require lock */
Mauro Carvalho Chehab6ef06e72013-12-16 19:10:59 -03004120 if (!(stat & FE_HAS_LOCK)) {
Mauro Carvalho Chehab704f01b2013-12-17 10:08:20 -03004121 c->cnr.len = 1;
Mauro Carvalho Chehab0400c532013-12-17 11:34:22 -03004122 c->block_count.len = 1;
Mauro Carvalho Chehab6ef06e72013-12-16 19:10:59 -03004123 c->block_error.len = 1;
4124 c->post_bit_error.len = 1;
4125 c->post_bit_count.len = 1;
Mauro Carvalho Chehab704f01b2013-12-17 10:08:20 -03004126 c->cnr.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
Mauro Carvalho Chehab6ef06e72013-12-16 19:10:59 -03004127 c->post_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
4128 c->post_bit_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
4129 c->block_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
Mauro Carvalho Chehab0400c532013-12-17 11:34:22 -03004130 c->block_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
Mauro Carvalho Chehab6ef06e72013-12-16 19:10:59 -03004131 return 0;
4132 }
4133
Mauro Carvalho Chehab704f01b2013-12-17 10:08:20 -03004134 /* Check if time for stats was elapsed */
Mauro Carvalho Chehab0400c532013-12-17 11:34:22 -03004135 if (time_after(jiffies, state->per_jiffies_stats)) {
4136 state->per_jiffies_stats = jiffies + msecs_to_jiffies(1000);
Mauro Carvalho Chehab6ef06e72013-12-16 19:10:59 -03004137
Mauro Carvalho Chehab704f01b2013-12-17 10:08:20 -03004138 /* Get SNR */
4139 snr = dib8000_get_snr(fe);
4140 for (i = 1; i < MAX_NUMBER_OF_FRONTENDS; i++) {
4141 if (state->fe[i])
4142 snr += dib8000_get_snr(state->fe[i]);
4143 }
4144 snr = snr >> 16;
Mauro Carvalho Chehab6ef06e72013-12-16 19:10:59 -03004145
Mauro Carvalho Chehab704f01b2013-12-17 10:08:20 -03004146 if (snr) {
4147 snr = 10 * intlog10(snr);
4148 snr = (1000L * snr) >> 24;
4149 } else {
4150 snr = 0;
4151 }
4152 c->cnr.stat[0].svalue = snr;
4153 c->cnr.stat[0].scale = FE_SCALE_DECIBEL;
Mauro Carvalho Chehab6ef06e72013-12-16 19:10:59 -03004154
Mauro Carvalho Chehab0400c532013-12-17 11:34:22 -03004155 /* Get UCB measures */
4156 dib8000_read_unc_blocks(fe, &val);
4157 if (val < state->init_ucb)
Mauro Carvalho Chehab5dc85262014-01-13 15:05:44 -02004158 state->init_ucb += 0x100000000LL;
Mauro Carvalho Chehab0400c532013-12-17 11:34:22 -03004159
4160 c->block_error.stat[0].scale = FE_SCALE_COUNTER;
4161 c->block_error.stat[0].uvalue = val + state->init_ucb;
4162
4163 /* Estimate the number of packets based on bitrate */
4164 if (!time_us)
4165 time_us = dib8000_get_time_us(fe, -1);
4166
4167 if (time_us) {
Mauro Carvalho Chehab5dc85262014-01-13 15:05:44 -02004168 blocks = 1250000ULL * 1000000ULL;
Mauro Carvalho Chehab0400c532013-12-17 11:34:22 -03004169 do_div(blocks, time_us * 8 * 204);
4170 c->block_count.stat[0].scale = FE_SCALE_COUNTER;
4171 c->block_count.stat[0].uvalue += blocks;
4172 }
4173
4174 show_per_stats = 1;
4175 }
4176
4177 /* Get post-BER measures */
4178 if (time_after(jiffies, state->ber_jiffies_stats)) {
4179 time_us = dib8000_get_time_us(fe, -1);
4180 state->ber_jiffies_stats = jiffies + msecs_to_jiffies((time_us + 500) / 1000);
4181
Mauro Carvalho Chehab8af16ad2016-10-14 10:05:46 -03004182 dprintk("Next all layers stats available in %u us.\n", time_us);
Mauro Carvalho Chehab704f01b2013-12-17 10:08:20 -03004183
4184 dib8000_read_ber(fe, &val);
4185 c->post_bit_error.stat[0].scale = FE_SCALE_COUNTER;
4186 c->post_bit_error.stat[0].uvalue += val;
4187
4188 c->post_bit_count.stat[0].scale = FE_SCALE_COUNTER;
4189 c->post_bit_count.stat[0].uvalue += 100000000;
Mauro Carvalho Chehab704f01b2013-12-17 10:08:20 -03004190 }
Mauro Carvalho Chehab6ef06e72013-12-16 19:10:59 -03004191
4192 if (state->revision < 0x8002)
4193 return 0;
4194
4195 c->block_error.len = 4;
4196 c->post_bit_error.len = 4;
4197 c->post_bit_count.len = 4;
4198
4199 for (i = 0; i < 3; i++) {
Mauro Carvalho Chehab0400c532013-12-17 11:34:22 -03004200 unsigned nsegs = c->layer[i].segment_count;
4201
4202 if (nsegs == 0 || nsegs > 13)
Mauro Carvalho Chehab704f01b2013-12-17 10:08:20 -03004203 continue;
Mauro Carvalho Chehab6ef06e72013-12-16 19:10:59 -03004204
Mauro Carvalho Chehab0400c532013-12-17 11:34:22 -03004205 time_us = 0;
Mauro Carvalho Chehab6ef06e72013-12-16 19:10:59 -03004206
Mauro Carvalho Chehab0400c532013-12-17 11:34:22 -03004207 if (time_after(jiffies, state->ber_jiffies_stats_layer[i])) {
4208 time_us = dib8000_get_time_us(fe, i);
Mauro Carvalho Chehab6ef06e72013-12-16 19:10:59 -03004209
Mauro Carvalho Chehab0400c532013-12-17 11:34:22 -03004210 state->ber_jiffies_stats_layer[i] = jiffies + msecs_to_jiffies((time_us + 500) / 1000);
4211 dprintk("Next layer %c stats will be available in %u us\n",
4212 'A' + i, time_us);
Mauro Carvalho Chehab704f01b2013-12-17 10:08:20 -03004213
Mauro Carvalho Chehab0400c532013-12-17 11:34:22 -03004214 val = dib8000_read_word(state, per_layer_regs[i].ber);
4215 c->post_bit_error.stat[1 + i].scale = FE_SCALE_COUNTER;
4216 c->post_bit_error.stat[1 + i].uvalue += val;
Mauro Carvalho Chehab704f01b2013-12-17 10:08:20 -03004217
Mauro Carvalho Chehab0400c532013-12-17 11:34:22 -03004218 c->post_bit_count.stat[1 + i].scale = FE_SCALE_COUNTER;
4219 c->post_bit_count.stat[1 + i].uvalue += 100000000;
4220 }
4221
4222 if (show_per_stats) {
4223 val = dib8000_read_word(state, per_layer_regs[i].per);
4224
4225 c->block_error.stat[1 + i].scale = FE_SCALE_COUNTER;
4226 c->block_error.stat[1 + i].uvalue += val;
4227
4228 if (!time_us)
4229 time_us = dib8000_get_time_us(fe, i);
4230 if (time_us) {
Mauro Carvalho Chehab5dc85262014-01-13 15:05:44 -02004231 blocks = 1250000ULL * 1000000ULL;
Mauro Carvalho Chehab0400c532013-12-17 11:34:22 -03004232 do_div(blocks, time_us * 8 * 204);
4233 c->block_count.stat[0].scale = FE_SCALE_COUNTER;
4234 c->block_count.stat[0].uvalue += blocks;
4235 }
4236 }
Mauro Carvalho Chehab6ef06e72013-12-16 19:10:59 -03004237 }
4238 return 0;
4239}
4240
Mauro Carvalho Chehabd44913c2014-05-29 09:20:17 -03004241static int dib8000_set_slave_frontend(struct dvb_frontend *fe, struct dvb_frontend *fe_slave)
Olivier Grenie4c70e072011-01-03 15:33:37 -03004242{
4243 struct dib8000_state *state = fe->demodulator_priv;
4244 u8 index_frontend = 1;
4245
4246 while ((index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL))
4247 index_frontend++;
4248 if (index_frontend < MAX_NUMBER_OF_FRONTENDS) {
Mauro Carvalho Chehab8af16ad2016-10-14 10:05:46 -03004249 dprintk("set slave fe %p to index %i\n", fe_slave, index_frontend);
Olivier Grenie4c70e072011-01-03 15:33:37 -03004250 state->fe[index_frontend] = fe_slave;
4251 return 0;
4252 }
4253
Mauro Carvalho Chehab8af16ad2016-10-14 10:05:46 -03004254 dprintk("too many slave frontend\n");
Olivier Grenie4c70e072011-01-03 15:33:37 -03004255 return -ENOMEM;
4256}
Olivier Grenie4c70e072011-01-03 15:33:37 -03004257
Mauro Carvalho Chehabd44913c2014-05-29 09:20:17 -03004258static int dib8000_remove_slave_frontend(struct dvb_frontend *fe)
Olivier Grenie4c70e072011-01-03 15:33:37 -03004259{
4260 struct dib8000_state *state = fe->demodulator_priv;
4261 u8 index_frontend = 1;
4262
4263 while ((index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL))
4264 index_frontend++;
4265 if (index_frontend != 1) {
Mauro Carvalho Chehab8af16ad2016-10-14 10:05:46 -03004266 dprintk("remove slave fe %p (index %i)\n", state->fe[index_frontend-1], index_frontend-1);
Olivier Grenie4c70e072011-01-03 15:33:37 -03004267 state->fe[index_frontend] = NULL;
4268 return 0;
4269 }
4270
Mauro Carvalho Chehab8af16ad2016-10-14 10:05:46 -03004271 dprintk("no frontend to be removed\n");
Olivier Grenie4c70e072011-01-03 15:33:37 -03004272 return -ENODEV;
4273}
Olivier Grenie4c70e072011-01-03 15:33:37 -03004274
Mauro Carvalho Chehabd44913c2014-05-29 09:20:17 -03004275static struct dvb_frontend *dib8000_get_slave_frontend(struct dvb_frontend *fe, int slave_index)
Olivier Grenie4c70e072011-01-03 15:33:37 -03004276{
4277 struct dib8000_state *state = fe->demodulator_priv;
4278
4279 if (slave_index >= MAX_NUMBER_OF_FRONTENDS)
4280 return NULL;
4281 return state->fe[slave_index];
4282}
Olivier Grenie4c70e072011-01-03 15:33:37 -03004283
Mauro Carvalho Chehabd44913c2014-05-29 09:20:17 -03004284static int dib8000_i2c_enumeration(struct i2c_adapter *host, int no_of_demods,
Olivier Grenie0c32dbd2011-08-10 05:17:18 -03004285 u8 default_addr, u8 first_addr, u8 is_dib8096p)
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03004286{
Olivier Grenie5a0deee2011-05-03 12:27:33 -03004287 int k = 0, ret = 0;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03004288 u8 new_addr = 0;
4289 struct i2c_device client = {.adap = host };
4290
Olivier Grenie5a0deee2011-05-03 12:27:33 -03004291 client.i2c_write_buffer = kzalloc(4 * sizeof(u8), GFP_KERNEL);
4292 if (!client.i2c_write_buffer) {
Mauro Carvalho Chehab8af16ad2016-10-14 10:05:46 -03004293 dprintk("%s: not enough memory\n", __func__);
Olivier Grenie5a0deee2011-05-03 12:27:33 -03004294 return -ENOMEM;
4295 }
4296 client.i2c_read_buffer = kzalloc(4 * sizeof(u8), GFP_KERNEL);
4297 if (!client.i2c_read_buffer) {
Mauro Carvalho Chehab8af16ad2016-10-14 10:05:46 -03004298 dprintk("%s: not enough memory\n", __func__);
Olivier Grenie5a0deee2011-05-03 12:27:33 -03004299 ret = -ENOMEM;
Patrick Boettcher79fcce32011-08-03 12:08:21 -03004300 goto error_memory_read;
Olivier Grenie5a0deee2011-05-03 12:27:33 -03004301 }
Patrick Boettcher79fcce32011-08-03 12:08:21 -03004302 client.i2c_buffer_lock = kzalloc(sizeof(struct mutex), GFP_KERNEL);
4303 if (!client.i2c_buffer_lock) {
Mauro Carvalho Chehab8af16ad2016-10-14 10:05:46 -03004304 dprintk("%s: not enough memory\n", __func__);
Patrick Boettcher79fcce32011-08-03 12:08:21 -03004305 ret = -ENOMEM;
4306 goto error_memory_lock;
4307 }
4308 mutex_init(client.i2c_buffer_lock);
Olivier Grenie5a0deee2011-05-03 12:27:33 -03004309
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03004310 for (k = no_of_demods - 1; k >= 0; k--) {
4311 /* designated i2c address */
4312 new_addr = first_addr + (k << 1);
4313
4314 client.addr = new_addr;
Olivier Grenie0c32dbd2011-08-10 05:17:18 -03004315 if (!is_dib8096p)
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03004316 dib8000_i2c_write16(&client, 1287, 0x0003); /* sram lead in, rdy */
Olivier Grenie0c32dbd2011-08-10 05:17:18 -03004317 if (dib8000_identify(&client) == 0) {
4318 /* sram lead in, rdy */
4319 if (!is_dib8096p)
4320 dib8000_i2c_write16(&client, 1287, 0x0003);
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03004321 client.addr = default_addr;
4322 if (dib8000_identify(&client) == 0) {
Mauro Carvalho Chehab8af16ad2016-10-14 10:05:46 -03004323 dprintk("#%d: not identified\n", k);
Olivier Grenie5a0deee2011-05-03 12:27:33 -03004324 ret = -EINVAL;
4325 goto error;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03004326 }
4327 }
4328
4329 /* start diversity to pull_down div_str - just for i2c-enumeration */
4330 dib8000_i2c_write16(&client, 1286, (1 << 10) | (4 << 6));
4331
4332 /* set new i2c address and force divstart */
4333 dib8000_i2c_write16(&client, 1285, (new_addr << 2) | 0x2);
4334 client.addr = new_addr;
4335 dib8000_identify(&client);
4336
Mauro Carvalho Chehab8af16ad2016-10-14 10:05:46 -03004337 dprintk("IC %d initialized (to i2c_address 0x%x)\n", k, new_addr);
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03004338 }
4339
4340 for (k = 0; k < no_of_demods; k++) {
4341 new_addr = first_addr | (k << 1);
4342 client.addr = new_addr;
4343
4344 // unforce divstr
4345 dib8000_i2c_write16(&client, 1285, new_addr << 2);
4346
4347 /* deactivate div - it was just for i2c-enumeration */
4348 dib8000_i2c_write16(&client, 1286, 0);
4349 }
4350
Olivier Grenie5a0deee2011-05-03 12:27:33 -03004351error:
Patrick Boettcher79fcce32011-08-03 12:08:21 -03004352 kfree(client.i2c_buffer_lock);
4353error_memory_lock:
Olivier Grenie5a0deee2011-05-03 12:27:33 -03004354 kfree(client.i2c_read_buffer);
Patrick Boettcher79fcce32011-08-03 12:08:21 -03004355error_memory_read:
Olivier Grenie5a0deee2011-05-03 12:27:33 -03004356 kfree(client.i2c_write_buffer);
4357
4358 return ret;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03004359}
4360
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03004361static int dib8000_fe_get_tune_settings(struct dvb_frontend *fe, struct dvb_frontend_tune_settings *tune)
4362{
4363 tune->min_delay_ms = 1000;
4364 tune->step_size = 0;
4365 tune->max_drift = 0;
4366 return 0;
4367}
4368
4369static void dib8000_release(struct dvb_frontend *fe)
4370{
4371 struct dib8000_state *st = fe->demodulator_priv;
Olivier Grenie4c70e072011-01-03 15:33:37 -03004372 u8 index_frontend;
4373
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03004374 for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (st->fe[index_frontend] != NULL); index_frontend++)
Olivier Grenie4c70e072011-01-03 15:33:37 -03004375 dvb_frontend_detach(st->fe[index_frontend]);
4376
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03004377 dibx000_exit_i2c_master(&st->i2c_master);
Olivier Grenie0c32dbd2011-08-10 05:17:18 -03004378 i2c_del_adapter(&st->dib8096p_tuner_adap);
Olivier Grenie4c70e072011-01-03 15:33:37 -03004379 kfree(st->fe[0]);
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03004380 kfree(st);
4381}
4382
Mauro Carvalho Chehabd44913c2014-05-29 09:20:17 -03004383static struct i2c_adapter *dib8000_get_i2c_master(struct dvb_frontend *fe, enum dibx000_i2c_interface intf, int gating)
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03004384{
4385 struct dib8000_state *st = fe->demodulator_priv;
4386 return dibx000_get_i2c_adapter(&st->i2c_master, intf, gating);
4387}
4388
Mauro Carvalho Chehabd44913c2014-05-29 09:20:17 -03004389static int dib8000_pid_filter_ctrl(struct dvb_frontend *fe, u8 onoff)
Olivier Grenief8731f42009-09-18 04:08:43 -03004390{
4391 struct dib8000_state *st = fe->demodulator_priv;
Olivier Grenie4c70e072011-01-03 15:33:37 -03004392 u16 val = dib8000_read_word(st, 299) & 0xffef;
4393 val |= (onoff & 0x1) << 4;
Olivier Grenief8731f42009-09-18 04:08:43 -03004394
Mauro Carvalho Chehab8af16ad2016-10-14 10:05:46 -03004395 dprintk("pid filter enabled %d\n", onoff);
Olivier Grenie4c70e072011-01-03 15:33:37 -03004396 return dib8000_write_word(st, 299, val);
Olivier Grenief8731f42009-09-18 04:08:43 -03004397}
Olivier Grenief8731f42009-09-18 04:08:43 -03004398
Mauro Carvalho Chehabd44913c2014-05-29 09:20:17 -03004399static int dib8000_pid_filter(struct dvb_frontend *fe, u8 id, u16 pid, u8 onoff)
Olivier Grenief8731f42009-09-18 04:08:43 -03004400{
4401 struct dib8000_state *st = fe->demodulator_priv;
Mauro Carvalho Chehab8af16ad2016-10-14 10:05:46 -03004402 dprintk("Index %x, PID %d, OnOff %d\n", id, pid, onoff);
Olivier Grenie4c70e072011-01-03 15:33:37 -03004403 return dib8000_write_word(st, 305 + id, onoff ? (1 << 13) | pid : 0);
Olivier Grenief8731f42009-09-18 04:08:43 -03004404}
Olivier Grenief8731f42009-09-18 04:08:43 -03004405
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03004406static const struct dvb_frontend_ops dib8000_ops = {
Mauro Carvalho Chehab490ecd62011-12-22 20:38:27 -03004407 .delsys = { SYS_ISDBT },
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03004408 .info = {
4409 .name = "DiBcom 8000 ISDB-T",
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03004410 .frequency_min = 44250000,
4411 .frequency_max = 867250000,
4412 .frequency_stepsize = 62500,
4413 .caps = FE_CAN_INVERSION_AUTO |
4414 FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
4415 FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
4416 FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO |
4417 FE_CAN_TRANSMISSION_MODE_AUTO | FE_CAN_GUARD_INTERVAL_AUTO | FE_CAN_RECOVER | FE_CAN_HIERARCHY_AUTO,
4418 },
4419
4420 .release = dib8000_release,
4421
4422 .init = dib8000_wakeup,
4423 .sleep = dib8000_sleep,
4424
Mauro Carvalho Chehab490ecd62011-12-22 20:38:27 -03004425 .set_frontend = dib8000_set_frontend,
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03004426 .get_tune_settings = dib8000_fe_get_tune_settings,
Mauro Carvalho Chehab490ecd62011-12-22 20:38:27 -03004427 .get_frontend = dib8000_get_frontend,
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03004428
4429 .read_status = dib8000_read_status,
4430 .read_ber = dib8000_read_ber,
4431 .read_signal_strength = dib8000_read_signal_strength,
4432 .read_snr = dib8000_read_snr,
4433 .read_ucblocks = dib8000_read_unc_blocks,
4434};
4435
Mauro Carvalho Chehabd44913c2014-05-29 09:20:17 -03004436static struct dvb_frontend *dib8000_init(struct i2c_adapter *i2c_adap, u8 i2c_addr, struct dib8000_config *cfg)
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03004437{
4438 struct dvb_frontend *fe;
4439 struct dib8000_state *state;
4440
Mauro Carvalho Chehab8af16ad2016-10-14 10:05:46 -03004441 dprintk("dib8000_init\n");
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03004442
4443 state = kzalloc(sizeof(struct dib8000_state), GFP_KERNEL);
4444 if (state == NULL)
4445 return NULL;
Olivier Grenie4c70e072011-01-03 15:33:37 -03004446 fe = kzalloc(sizeof(struct dvb_frontend), GFP_KERNEL);
4447 if (fe == NULL)
Dan Carpentered54c0e2011-01-19 11:27:58 -03004448 goto error;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03004449
4450 memcpy(&state->cfg, cfg, sizeof(struct dib8000_config));
4451 state->i2c.adap = i2c_adap;
4452 state->i2c.addr = i2c_addr;
Olivier Grenie5a0deee2011-05-03 12:27:33 -03004453 state->i2c.i2c_write_buffer = state->i2c_write_buffer;
4454 state->i2c.i2c_read_buffer = state->i2c_read_buffer;
Patrick Boettcher79fcce32011-08-03 12:08:21 -03004455 mutex_init(&state->i2c_buffer_lock);
4456 state->i2c.i2c_buffer_lock = &state->i2c_buffer_lock;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03004457 state->gpio_val = cfg->gpio_val;
4458 state->gpio_dir = cfg->gpio_dir;
4459
4460 /* Ensure the output mode remains at the previous default if it's
4461 * not specifically set by the caller.
4462 */
4463 if ((state->cfg.output_mode != OUTMODE_MPEG2_SERIAL) && (state->cfg.output_mode != OUTMODE_MPEG2_PAR_GATED_CLK))
4464 state->cfg.output_mode = OUTMODE_MPEG2_FIFO;
4465
Olivier Grenie4c70e072011-01-03 15:33:37 -03004466 state->fe[0] = fe;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03004467 fe->demodulator_priv = state;
Olivier Grenie4c70e072011-01-03 15:33:37 -03004468 memcpy(&state->fe[0]->ops, &dib8000_ops, sizeof(struct dvb_frontend_ops));
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03004469
4470 state->timf_default = cfg->pll->timf;
4471
4472 if (dib8000_identify(&state->i2c) == 0)
4473 goto error;
4474
4475 dibx000_init_i2c_master(&state->i2c_master, DIB8000, state->i2c.adap, state->i2c.addr);
4476
Olivier Grenie0c32dbd2011-08-10 05:17:18 -03004477 /* init 8096p tuner adapter */
4478 strncpy(state->dib8096p_tuner_adap.name, "DiB8096P tuner interface",
4479 sizeof(state->dib8096p_tuner_adap.name));
4480 state->dib8096p_tuner_adap.algo = &dib8096p_tuner_xfer_algo;
4481 state->dib8096p_tuner_adap.algo_data = NULL;
4482 state->dib8096p_tuner_adap.dev.parent = state->i2c.adap->dev.parent;
4483 i2c_set_adapdata(&state->dib8096p_tuner_adap, state);
4484 i2c_add_adapter(&state->dib8096p_tuner_adap);
4485
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03004486 dib8000_reset(fe);
4487
4488 dib8000_write_word(state, 285, (dib8000_read_word(state, 285) & ~0x60) | (3 << 5)); /* ber_rs_len = 3 */
Patrick Boettcher173a64c2013-04-22 12:45:52 -03004489 state->current_demod_bw = 6000;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03004490
4491 return fe;
4492
Patrick Boettcher173a64c2013-04-22 12:45:52 -03004493error:
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03004494 kfree(state);
4495 return NULL;
4496}
4497
Mauro Carvalho Chehabd44913c2014-05-29 09:20:17 -03004498void *dib8000_attach(struct dib8000_ops *ops)
4499{
4500 if (!ops)
4501 return NULL;
4502
4503 ops->pwm_agc_reset = dib8000_pwm_agc_reset;
4504 ops->get_dc_power = dib8090p_get_dc_power;
4505 ops->set_gpio = dib8000_set_gpio;
4506 ops->get_slave_frontend = dib8000_get_slave_frontend;
4507 ops->set_tune_state = dib8000_set_tune_state;
4508 ops->pid_filter_ctrl = dib8000_pid_filter_ctrl;
4509 ops->remove_slave_frontend = dib8000_remove_slave_frontend;
4510 ops->get_adc_power = dib8000_get_adc_power;
4511 ops->update_pll = dib8000_update_pll;
4512 ops->tuner_sleep = dib8096p_tuner_sleep;
4513 ops->get_tune_state = dib8000_get_tune_state;
4514 ops->get_i2c_tuner = dib8096p_get_i2c_tuner;
4515 ops->set_slave_frontend = dib8000_set_slave_frontend;
4516 ops->pid_filter = dib8000_pid_filter;
4517 ops->ctrl_timf = dib8000_ctrl_timf;
4518 ops->init = dib8000_init;
4519 ops->get_i2c_master = dib8000_get_i2c_master;
4520 ops->i2c_enumeration = dib8000_i2c_enumeration;
4521 ops->set_wbd_ref = dib8000_set_wbd_ref;
4522
4523 return ops;
4524}
4525EXPORT_SYMBOL(dib8000_attach);
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03004526
Patrick Boettcher99e44da2016-01-24 12:56:58 -02004527MODULE_AUTHOR("Olivier Grenie <Olivier.Grenie@parrot.com, Patrick Boettcher <patrick.boettcher@posteo.de>");
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03004528MODULE_DESCRIPTION("Driver for the DiBcom 8000 ISDB-T demodulator");
4529MODULE_LICENSE("GPL");