blob: ddf9c44877a259830f34c802d066fe65f465235d [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 */
10#include <linux/kernel.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090011#include <linux/slab.h>
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -030012#include <linux/i2c.h>
Patrick Boettcher79fcce32011-08-03 12:08:21 -030013#include <linux/mutex.h>
Mauro Carvalho Chehabb4600d72013-12-16 20:00:34 -030014#include <asm/div64.h>
Patrick Boettcher79fcce32011-08-03 12:08:21 -030015
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -030016#include "dvb_math.h"
17
18#include "dvb_frontend.h"
19
20#include "dib8000.h"
21
22#define LAYER_ALL -1
23#define LAYER_A 1
24#define LAYER_B 2
25#define LAYER_C 3
26
Olivier Grenie4c70e072011-01-03 15:33:37 -030027#define MAX_NUMBER_OF_FRONTENDS 6
Patrick Boettcher173a64c2013-04-22 12:45:52 -030028/* #define DIB8000_AGC_FREEZE */
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -030029
Patrick Boettcher78f3bc62009-08-17 12:53:51 -030030static int debug;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -030031module_param(debug, int, 0644);
32MODULE_PARM_DESC(debug, "turn on debugging (default: 0)");
33
34#define dprintk(args...) do { if (debug) { printk(KERN_DEBUG "DiB8000: "); printk(args); printk("\n"); } } while (0)
35
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -030036struct i2c_device {
37 struct i2c_adapter *adap;
38 u8 addr;
Olivier Grenie5a0deee2011-05-03 12:27:33 -030039 u8 *i2c_write_buffer;
40 u8 *i2c_read_buffer;
Patrick Boettcher79fcce32011-08-03 12:08:21 -030041 struct mutex *i2c_buffer_lock;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -030042};
43
Patrick Boettcher173a64c2013-04-22 12:45:52 -030044enum param_loop_step {
45 LOOP_TUNE_1,
46 LOOP_TUNE_2
47};
48
49enum dib8000_autosearch_step {
50 AS_START = 0,
51 AS_SEARCHING_FFT,
52 AS_SEARCHING_GUARD,
53 AS_DONE = 100,
54};
55
56enum timeout_mode {
57 SYMBOL_DEPENDENT_OFF = 0,
58 SYMBOL_DEPENDENT_ON,
59};
60
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -030061struct dib8000_state {
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -030062 struct dib8000_config cfg;
63
64 struct i2c_device i2c;
65
66 struct dibx000_i2c_master i2c_master;
67
68 u16 wbd_ref;
69
70 u8 current_band;
71 u32 current_bandwidth;
72 struct dibx000_agc_config *current_agc;
73 u32 timf;
74 u32 timf_default;
75
76 u8 div_force_off:1;
77 u8 div_state:1;
78 u16 div_sync_wait;
79
80 u8 agc_state;
81 u8 differential_constellation;
82 u8 diversity_onoff;
83
84 s16 ber_monitored_layer;
85 u16 gpio_dir;
86 u16 gpio_val;
87
88 u16 revision;
89 u8 isdbt_cfg_loaded;
90 enum frontend_tune_state tune_state;
Patrick Boettcher173a64c2013-04-22 12:45:52 -030091 s32 status;
Olivier Grenie4c70e072011-01-03 15:33:37 -030092
93 struct dvb_frontend *fe[MAX_NUMBER_OF_FRONTENDS];
Olivier Grenie5a0deee2011-05-03 12:27:33 -030094
95 /* for the I2C transfer */
96 struct i2c_msg msg[2];
97 u8 i2c_write_buffer[4];
98 u8 i2c_read_buffer[2];
Patrick Boettcher79fcce32011-08-03 12:08:21 -030099 struct mutex i2c_buffer_lock;
Olivier Grenie0c32dbd2011-08-10 05:17:18 -0300100 u8 input_mode_mpeg;
101
102 u16 tuner_enable;
103 struct i2c_adapter dib8096p_tuner_adap;
Patrick Boettcher173a64c2013-04-22 12:45:52 -0300104 u16 current_demod_bw;
105
106 u16 seg_mask;
107 u16 seg_diff_mask;
108 u16 mode;
109 u8 layer_b_nb_seg;
110 u8 layer_c_nb_seg;
111
112 u8 channel_parameters_set;
113 u16 autosearch_state;
114 u16 found_nfft;
115 u16 found_guard;
116 u8 subchannel;
117 u8 symbol_duration;
Mauro Carvalho Chehabd6c62b72014-07-04 14:15:37 -0300118 unsigned long timeout;
Patrick Boettcher173a64c2013-04-22 12:45:52 -0300119 u8 longest_intlv_layer;
120 u16 output_mode;
121
Mauro Carvalho Chehab704f01b2013-12-17 10:08:20 -0300122 /* for DVBv5 stats */
Mauro Carvalho Chehab7a9d85d2013-12-17 04:55:26 -0300123 s64 init_ucb;
Mauro Carvalho Chehab0400c532013-12-17 11:34:22 -0300124 unsigned long per_jiffies_stats;
125 unsigned long ber_jiffies_stats;
126 unsigned long ber_jiffies_stats_layer[3];
Mauro Carvalho Chehab704f01b2013-12-17 10:08:20 -0300127
Patrick Boettcher173a64c2013-04-22 12:45:52 -0300128#ifdef DIB8000_AGC_FREEZE
129 u16 agc1_max;
130 u16 agc1_min;
131 u16 agc2_max;
132 u16 agc2_min;
133#endif
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300134};
135
136enum dib8000_power_mode {
Olivier Grenie0c32dbd2011-08-10 05:17:18 -0300137 DIB8000_POWER_ALL = 0,
138 DIB8000_POWER_INTERFACE_ONLY,
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300139};
140
141static u16 dib8000_i2c_read16(struct i2c_device *i2c, u16 reg)
142{
Patrick Boettcher79fcce32011-08-03 12:08:21 -0300143 u16 ret;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300144 struct i2c_msg msg[2] = {
Patrick Boettcher79fcce32011-08-03 12:08:21 -0300145 {.addr = i2c->addr >> 1, .flags = 0, .len = 2},
146 {.addr = i2c->addr >> 1, .flags = I2C_M_RD, .len = 2},
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300147 };
148
Patrick Boettcher79fcce32011-08-03 12:08:21 -0300149 if (mutex_lock_interruptible(i2c->i2c_buffer_lock) < 0) {
150 dprintk("could not acquire lock");
151 return 0;
152 }
153
154 msg[0].buf = i2c->i2c_write_buffer;
Olivier Grenie5a0deee2011-05-03 12:27:33 -0300155 msg[0].buf[0] = reg >> 8;
156 msg[0].buf[1] = reg & 0xff;
Patrick Boettcher79fcce32011-08-03 12:08:21 -0300157 msg[1].buf = i2c->i2c_read_buffer;
Olivier Grenie5a0deee2011-05-03 12:27:33 -0300158
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300159 if (i2c_transfer(i2c->adap, msg, 2) != 2)
160 dprintk("i2c read error on %d", reg);
161
Patrick Boettcher79fcce32011-08-03 12:08:21 -0300162 ret = (msg[1].buf[0] << 8) | msg[1].buf[1];
163 mutex_unlock(i2c->i2c_buffer_lock);
164 return ret;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300165}
166
Mauro Carvalho Chehab5ac64ba2013-12-13 10:35:03 -0300167static u16 __dib8000_read_word(struct dib8000_state *state, u16 reg)
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300168{
Patrick Boettcher79fcce32011-08-03 12:08:21 -0300169 u16 ret;
170
Olivier Grenie5a0deee2011-05-03 12:27:33 -0300171 state->i2c_write_buffer[0] = reg >> 8;
172 state->i2c_write_buffer[1] = reg & 0xff;
173
174 memset(state->msg, 0, 2 * sizeof(struct i2c_msg));
175 state->msg[0].addr = state->i2c.addr >> 1;
176 state->msg[0].flags = 0;
177 state->msg[0].buf = state->i2c_write_buffer;
178 state->msg[0].len = 2;
179 state->msg[1].addr = state->i2c.addr >> 1;
180 state->msg[1].flags = I2C_M_RD;
181 state->msg[1].buf = state->i2c_read_buffer;
182 state->msg[1].len = 2;
183
184 if (i2c_transfer(state->i2c.adap, state->msg, 2) != 2)
185 dprintk("i2c read error on %d", reg);
186
Patrick Boettcher79fcce32011-08-03 12:08:21 -0300187 ret = (state->i2c_read_buffer[0] << 8) | state->i2c_read_buffer[1];
Mauro Carvalho Chehab5ac64ba2013-12-13 10:35:03 -0300188
189 return ret;
190}
191
192static u16 dib8000_read_word(struct dib8000_state *state, u16 reg)
193{
194 u16 ret;
195
196 if (mutex_lock_interruptible(&state->i2c_buffer_lock) < 0) {
197 dprintk("could not acquire lock");
198 return 0;
199 }
200
201 ret = __dib8000_read_word(state, reg);
202
Patrick Boettcher79fcce32011-08-03 12:08:21 -0300203 mutex_unlock(&state->i2c_buffer_lock);
204
205 return ret;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300206}
207
208static u32 dib8000_read32(struct dib8000_state *state, u16 reg)
209{
210 u16 rw[2];
211
Mauro Carvalho Chehab5ac64ba2013-12-13 10:35:03 -0300212 if (mutex_lock_interruptible(&state->i2c_buffer_lock) < 0) {
213 dprintk("could not acquire lock");
214 return 0;
215 }
216
217 rw[0] = __dib8000_read_word(state, reg + 0);
218 rw[1] = __dib8000_read_word(state, reg + 1);
219
220 mutex_unlock(&state->i2c_buffer_lock);
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300221
222 return ((rw[0] << 16) | (rw[1]));
223}
224
225static int dib8000_i2c_write16(struct i2c_device *i2c, u16 reg, u16 val)
226{
Patrick Boettcher79fcce32011-08-03 12:08:21 -0300227 struct i2c_msg msg = {.addr = i2c->addr >> 1, .flags = 0, .len = 4};
Olivier Grenie5a0deee2011-05-03 12:27:33 -0300228 int ret = 0;
229
Patrick Boettcher79fcce32011-08-03 12:08:21 -0300230 if (mutex_lock_interruptible(i2c->i2c_buffer_lock) < 0) {
231 dprintk("could not acquire lock");
232 return -EINVAL;
233 }
234
235 msg.buf = i2c->i2c_write_buffer;
Olivier Grenie5a0deee2011-05-03 12:27:33 -0300236 msg.buf[0] = (reg >> 8) & 0xff;
237 msg.buf[1] = reg & 0xff;
238 msg.buf[2] = (val >> 8) & 0xff;
239 msg.buf[3] = val & 0xff;
240
241 ret = i2c_transfer(i2c->adap, &msg, 1) != 1 ? -EREMOTEIO : 0;
Patrick Boettcher79fcce32011-08-03 12:08:21 -0300242 mutex_unlock(i2c->i2c_buffer_lock);
Olivier Grenie5a0deee2011-05-03 12:27:33 -0300243
244 return ret;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300245}
246
247static int dib8000_write_word(struct dib8000_state *state, u16 reg, u16 val)
248{
Patrick Boettcher79fcce32011-08-03 12:08:21 -0300249 int ret;
250
251 if (mutex_lock_interruptible(&state->i2c_buffer_lock) < 0) {
252 dprintk("could not acquire lock");
253 return -EINVAL;
254 }
255
Olivier Grenie5a0deee2011-05-03 12:27:33 -0300256 state->i2c_write_buffer[0] = (reg >> 8) & 0xff;
257 state->i2c_write_buffer[1] = reg & 0xff;
258 state->i2c_write_buffer[2] = (val >> 8) & 0xff;
259 state->i2c_write_buffer[3] = val & 0xff;
260
261 memset(&state->msg[0], 0, sizeof(struct i2c_msg));
262 state->msg[0].addr = state->i2c.addr >> 1;
263 state->msg[0].flags = 0;
264 state->msg[0].buf = state->i2c_write_buffer;
265 state->msg[0].len = 4;
266
Patrick Boettcher79fcce32011-08-03 12:08:21 -0300267 ret = (i2c_transfer(state->i2c.adap, state->msg, 1) != 1 ?
268 -EREMOTEIO : 0);
269 mutex_unlock(&state->i2c_buffer_lock);
270
271 return ret;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300272}
273
Olivier Grenie4c70e072011-01-03 15:33:37 -0300274static const s16 coeff_2k_sb_1seg_dqpsk[8] = {
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300275 (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 -0300276 (920 << 5) | 0x09
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300277};
278
Olivier Grenie4c70e072011-01-03 15:33:37 -0300279static const s16 coeff_2k_sb_1seg[8] = {
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300280 (692 << 5) | 0x0b, (683 << 5) | 0x01, (519 << 5) | 0x09, (692 << 5) | 0x0b, 0 | 0x1f, 0 | 0x1f, 0 | 0x1f, 0 | 0x1f
281};
282
Olivier Grenie4c70e072011-01-03 15:33:37 -0300283static const s16 coeff_2k_sb_3seg_0dqpsk_1dqpsk[8] = {
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300284 (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 -0300285 (-931 << 5) | 0x0f
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300286};
287
Olivier Grenie4c70e072011-01-03 15:33:37 -0300288static const s16 coeff_2k_sb_3seg_0dqpsk[8] = {
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300289 (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 -0300290 (982 << 5) | 0x0c
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300291};
292
Olivier Grenie4c70e072011-01-03 15:33:37 -0300293static const s16 coeff_2k_sb_3seg_1dqpsk[8] = {
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300294 (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 -0300295 (-720 << 5) | 0x0d
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300296};
297
Olivier Grenie4c70e072011-01-03 15:33:37 -0300298static const s16 coeff_2k_sb_3seg[8] = {
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300299 (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 -0300300 (-610 << 5) | 0x0a
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300301};
302
Olivier Grenie4c70e072011-01-03 15:33:37 -0300303static const s16 coeff_4k_sb_1seg_dqpsk[8] = {
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300304 (-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 -0300305 (-922 << 5) | 0x0d
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300306};
307
Olivier Grenie4c70e072011-01-03 15:33:37 -0300308static const s16 coeff_4k_sb_1seg[8] = {
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300309 (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 -0300310 (-655 << 5) | 0x0a
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300311};
312
Olivier Grenie4c70e072011-01-03 15:33:37 -0300313static const s16 coeff_4k_sb_3seg_0dqpsk_1dqpsk[8] = {
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300314 (-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 -0300315 (-958 << 5) | 0x13
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300316};
317
Olivier Grenie4c70e072011-01-03 15:33:37 -0300318static const s16 coeff_4k_sb_3seg_0dqpsk[8] = {
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300319 (-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 -0300320 (-568 << 5) | 0x0f
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300321};
322
Olivier Grenie4c70e072011-01-03 15:33:37 -0300323static const s16 coeff_4k_sb_3seg_1dqpsk[8] = {
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300324 (-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 -0300325 (-848 << 5) | 0x13
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300326};
327
Olivier Grenie4c70e072011-01-03 15:33:37 -0300328static const s16 coeff_4k_sb_3seg[8] = {
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300329 (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 -0300330 (-869 << 5) | 0x13
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300331};
332
Olivier Grenie4c70e072011-01-03 15:33:37 -0300333static const s16 coeff_8k_sb_1seg_dqpsk[8] = {
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300334 (-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 -0300335 (-598 << 5) | 0x10
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300336};
337
Olivier Grenie4c70e072011-01-03 15:33:37 -0300338static const s16 coeff_8k_sb_1seg[8] = {
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300339 (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 -0300340 (585 << 5) | 0x0f
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300341};
342
Olivier Grenie4c70e072011-01-03 15:33:37 -0300343static const s16 coeff_8k_sb_3seg_0dqpsk_1dqpsk[8] = {
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300344 (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 -0300345 (0 << 5) | 0x14
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300346};
347
Olivier Grenie4c70e072011-01-03 15:33:37 -0300348static const s16 coeff_8k_sb_3seg_0dqpsk[8] = {
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300349 (-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 -0300350 (-877 << 5) | 0x15
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300351};
352
Olivier Grenie4c70e072011-01-03 15:33:37 -0300353static const s16 coeff_8k_sb_3seg_1dqpsk[8] = {
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300354 (-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 -0300355 (-921 << 5) | 0x14
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300356};
357
Olivier Grenie4c70e072011-01-03 15:33:37 -0300358static const s16 coeff_8k_sb_3seg[8] = {
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300359 (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 -0300360 (690 << 5) | 0x14
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300361};
362
Olivier Grenie4c70e072011-01-03 15:33:37 -0300363static const s16 ana_fe_coeff_3seg[24] = {
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300364 81, 80, 78, 74, 68, 61, 54, 45, 37, 28, 19, 11, 4, 1022, 1017, 1013, 1010, 1008, 1008, 1008, 1008, 1010, 1014, 1017
365};
366
Olivier Grenie4c70e072011-01-03 15:33:37 -0300367static const s16 ana_fe_coeff_1seg[24] = {
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300368 249, 226, 164, 82, 5, 981, 970, 988, 1018, 20, 31, 26, 8, 1012, 1000, 1018, 1012, 8, 15, 14, 9, 3, 1017, 1003
369};
370
Olivier Grenie4c70e072011-01-03 15:33:37 -0300371static const s16 ana_fe_coeff_13seg[24] = {
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300372 396, 305, 105, -51, -77, -12, 41, 31, -11, -30, -11, 14, 15, -2, -13, -7, 5, 8, 1, -6, -7, -3, 0, 1
373};
374
375static u16 fft_to_mode(struct dib8000_state *state)
376{
377 u16 mode;
Olivier Grenie4c70e072011-01-03 15:33:37 -0300378 switch (state->fe[0]->dtv_property_cache.transmission_mode) {
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300379 case TRANSMISSION_MODE_2K:
380 mode = 1;
381 break;
382 case TRANSMISSION_MODE_4K:
383 mode = 2;
384 break;
385 default:
386 case TRANSMISSION_MODE_AUTO:
387 case TRANSMISSION_MODE_8K:
388 mode = 3;
389 break;
390 }
391 return mode;
392}
393
394static void dib8000_set_acquisition_mode(struct dib8000_state *state)
395{
396 u16 nud = dib8000_read_word(state, 298);
397 nud |= (1 << 3) | (1 << 0);
398 dprintk("acquisition mode activated");
399 dib8000_write_word(state, 298, nud);
400}
Olivier Grenie4c70e072011-01-03 15:33:37 -0300401static int dib8000_set_output_mode(struct dvb_frontend *fe, int mode)
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300402{
Olivier Grenie4c70e072011-01-03 15:33:37 -0300403 struct dib8000_state *state = fe->demodulator_priv;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300404 u16 outreg, fifo_threshold, smo_mode, sram = 0x0205; /* by default SDRAM deintlv is enabled */
405
Patrick Boettcher173a64c2013-04-22 12:45:52 -0300406 state->output_mode = mode;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300407 outreg = 0;
408 fifo_threshold = 1792;
409 smo_mode = (dib8000_read_word(state, 299) & 0x0050) | (1 << 1);
410
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300411 dprintk("-I- Setting output mode for demod %p to %d",
412 &state->fe[0], mode);
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300413
414 switch (mode) {
415 case OUTMODE_MPEG2_PAR_GATED_CLK: // STBs with parallel gated clock
416 outreg = (1 << 10); /* 0x0400 */
417 break;
418 case OUTMODE_MPEG2_PAR_CONT_CLK: // STBs with parallel continues clock
419 outreg = (1 << 10) | (1 << 6); /* 0x0440 */
420 break;
421 case OUTMODE_MPEG2_SERIAL: // STBs with serial input
422 outreg = (1 << 10) | (2 << 6) | (0 << 1); /* 0x0482 */
423 break;
424 case OUTMODE_DIVERSITY:
425 if (state->cfg.hostbus_diversity) {
426 outreg = (1 << 10) | (4 << 6); /* 0x0500 */
427 sram &= 0xfdff;
428 } else
429 sram |= 0x0c00;
430 break;
431 case OUTMODE_MPEG2_FIFO: // e.g. USB feeding
432 smo_mode |= (3 << 1);
433 fifo_threshold = 512;
434 outreg = (1 << 10) | (5 << 6);
435 break;
436 case OUTMODE_HIGH_Z: // disable
437 outreg = 0;
438 break;
439
440 case OUTMODE_ANALOG_ADC:
441 outreg = (1 << 10) | (3 << 6);
442 dib8000_set_acquisition_mode(state);
443 break;
444
445 default:
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300446 dprintk("Unhandled output_mode passed to be set for demod %p",
447 &state->fe[0]);
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300448 return -EINVAL;
449 }
450
451 if (state->cfg.output_mpeg2_in_188_bytes)
452 smo_mode |= (1 << 5);
453
454 dib8000_write_word(state, 299, smo_mode);
455 dib8000_write_word(state, 300, fifo_threshold); /* synchronous fread */
456 dib8000_write_word(state, 1286, outreg);
457 dib8000_write_word(state, 1291, sram);
458
459 return 0;
460}
461
462static int dib8000_set_diversity_in(struct dvb_frontend *fe, int onoff)
463{
464 struct dib8000_state *state = fe->demodulator_priv;
Patrick Boettcher173a64c2013-04-22 12:45:52 -0300465 u16 tmp, sync_wait = dib8000_read_word(state, 273) & 0xfff0;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300466
Patrick Boettcher173a64c2013-04-22 12:45:52 -0300467 dprintk("set diversity input to %i", onoff);
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300468 if (!state->differential_constellation) {
469 dib8000_write_word(state, 272, 1 << 9); //dvsy_off_lmod4 = 1
470 dib8000_write_word(state, 273, sync_wait | (1 << 2) | 2); // sync_enable = 1; comb_mode = 2
471 } else {
472 dib8000_write_word(state, 272, 0); //dvsy_off_lmod4 = 0
473 dib8000_write_word(state, 273, sync_wait); // sync_enable = 0; comb_mode = 0
474 }
475 state->diversity_onoff = onoff;
476
477 switch (onoff) {
478 case 0: /* only use the internal way - not the diversity input */
479 dib8000_write_word(state, 270, 1);
480 dib8000_write_word(state, 271, 0);
481 break;
482 case 1: /* both ways */
483 dib8000_write_word(state, 270, 6);
484 dib8000_write_word(state, 271, 6);
485 break;
486 case 2: /* only the diversity input */
487 dib8000_write_word(state, 270, 0);
488 dib8000_write_word(state, 271, 1);
489 break;
490 }
Patrick Boettcher173a64c2013-04-22 12:45:52 -0300491
492 if (state->revision == 0x8002) {
493 tmp = dib8000_read_word(state, 903);
494 dib8000_write_word(state, 903, tmp & ~(1 << 3));
495 msleep(30);
496 dib8000_write_word(state, 903, tmp | (1 << 3));
497 }
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300498 return 0;
499}
500
501static void dib8000_set_power_mode(struct dib8000_state *state, enum dib8000_power_mode mode)
502{
503 /* by default everything is going to be powered off */
504 u16 reg_774 = 0x3fff, reg_775 = 0xffff, reg_776 = 0xffff,
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300505 reg_900 = (dib8000_read_word(state, 900) & 0xfffc) | 0x3,
Olivier Grenie0c32dbd2011-08-10 05:17:18 -0300506 reg_1280;
507
508 if (state->revision != 0x8090)
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300509 reg_1280 = (dib8000_read_word(state, 1280) & 0x00ff) | 0xff00;
Olivier Grenie0c32dbd2011-08-10 05:17:18 -0300510 else
511 reg_1280 = (dib8000_read_word(state, 1280) & 0x707f) | 0x8f80;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300512
513 /* now, depending on the requested mode, we power on */
514 switch (mode) {
515 /* power up everything in the demod */
Olivier Grenie0c32dbd2011-08-10 05:17:18 -0300516 case DIB8000_POWER_ALL:
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300517 reg_774 = 0x0000;
518 reg_775 = 0x0000;
519 reg_776 = 0x0000;
520 reg_900 &= 0xfffc;
Olivier Grenie0c32dbd2011-08-10 05:17:18 -0300521 if (state->revision != 0x8090)
522 reg_1280 &= 0x00ff;
523 else
524 reg_1280 &= 0x707f;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300525 break;
Olivier Grenie0c32dbd2011-08-10 05:17:18 -0300526 case DIB8000_POWER_INTERFACE_ONLY:
527 if (state->revision != 0x8090)
528 reg_1280 &= 0x00ff;
529 else
530 reg_1280 &= 0xfa7b;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300531 break;
532 }
533
534 dprintk("powermode : 774 : %x ; 775 : %x; 776 : %x ; 900 : %x; 1280 : %x", reg_774, reg_775, reg_776, reg_900, reg_1280);
535 dib8000_write_word(state, 774, reg_774);
536 dib8000_write_word(state, 775, reg_775);
537 dib8000_write_word(state, 776, reg_776);
538 dib8000_write_word(state, 900, reg_900);
539 dib8000_write_word(state, 1280, reg_1280);
540}
541
542static int dib8000_set_adc_state(struct dib8000_state *state, enum dibx000_adc_states no)
543{
544 int ret = 0;
Olivier Grenie0c32dbd2011-08-10 05:17:18 -0300545 u16 reg, reg_907 = dib8000_read_word(state, 907);
546 u16 reg_908 = dib8000_read_word(state, 908);
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300547
548 switch (no) {
549 case DIBX000_SLOW_ADC_ON:
Olivier Grenie0c32dbd2011-08-10 05:17:18 -0300550 if (state->revision != 0x8090) {
551 reg_908 |= (1 << 1) | (1 << 0);
552 ret |= dib8000_write_word(state, 908, reg_908);
553 reg_908 &= ~(1 << 1);
554 } else {
555 reg = dib8000_read_word(state, 1925);
556 /* en_slowAdc = 1 & reset_sladc = 1 */
557 dib8000_write_word(state, 1925, reg |
558 (1<<4) | (1<<2));
559
560 /* read acces to make it works... strange ... */
561 reg = dib8000_read_word(state, 1925);
562 msleep(20);
563 /* en_slowAdc = 1 & reset_sladc = 0 */
564 dib8000_write_word(state, 1925, reg & ~(1<<4));
565
566 reg = dib8000_read_word(state, 921) & ~((0x3 << 14)
567 | (0x3 << 12));
568 /* ref = Vin1 => Vbg ; sel = Vin0 or Vin3 ;
569 (Vin2 = Vcm) */
570 dib8000_write_word(state, 921, reg | (1 << 14)
571 | (3 << 12));
572 }
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300573 break;
574
575 case DIBX000_SLOW_ADC_OFF:
Olivier Grenie0c32dbd2011-08-10 05:17:18 -0300576 if (state->revision == 0x8090) {
577 reg = dib8000_read_word(state, 1925);
578 /* reset_sladc = 1 en_slowAdc = 0 */
579 dib8000_write_word(state, 1925,
580 (reg & ~(1<<2)) | (1<<4));
581 }
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300582 reg_908 |= (1 << 1) | (1 << 0);
583 break;
584
585 case DIBX000_ADC_ON:
586 reg_907 &= 0x0fff;
587 reg_908 &= 0x0003;
588 break;
589
590 case DIBX000_ADC_OFF: // leave the VBG voltage on
Mauro Carvalho Chehabc063c7c2014-07-04 14:15:28 -0300591 reg_907 = (1 << 13) | (1 << 12);
592 reg_908 = (1 << 6) | (1 << 5) | (1 << 4) | (1 << 3) | (1 << 1);
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300593 break;
594
595 case DIBX000_VBG_ENABLE:
596 reg_907 &= ~(1 << 15);
597 break;
598
599 case DIBX000_VBG_DISABLE:
600 reg_907 |= (1 << 15);
601 break;
602
603 default:
604 break;
605 }
606
607 ret |= dib8000_write_word(state, 907, reg_907);
608 ret |= dib8000_write_word(state, 908, reg_908);
609
610 return ret;
611}
612
Olivier Grenie4c70e072011-01-03 15:33:37 -0300613static int dib8000_set_bandwidth(struct dvb_frontend *fe, u32 bw)
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300614{
Olivier Grenie4c70e072011-01-03 15:33:37 -0300615 struct dib8000_state *state = fe->demodulator_priv;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300616 u32 timf;
617
618 if (bw == 0)
619 bw = 6000;
620
621 if (state->timf == 0) {
622 dprintk("using default timf");
623 timf = state->timf_default;
624 } else {
625 dprintk("using updated timf");
626 timf = state->timf;
627 }
628
629 dib8000_write_word(state, 29, (u16) ((timf >> 16) & 0xffff));
630 dib8000_write_word(state, 30, (u16) ((timf) & 0xffff));
631
632 return 0;
633}
634
635static int dib8000_sad_calib(struct dib8000_state *state)
636{
Patrick Boettcher173a64c2013-04-22 12:45:52 -0300637 u8 sad_sel = 3;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300638
Patrick Boettcher173a64c2013-04-22 12:45:52 -0300639 if (state->revision == 0x8090) {
640 dib8000_write_word(state, 922, (sad_sel << 2));
641 dib8000_write_word(state, 923, 2048);
642
643 dib8000_write_word(state, 922, (sad_sel << 2) | 0x1);
644 dib8000_write_word(state, 922, (sad_sel << 2));
645 } else {
646 /* internal */
647 dib8000_write_word(state, 923, (0 << 1) | (0 << 0));
648 dib8000_write_word(state, 924, 776);
649
650 /* do the calibration */
651 dib8000_write_word(state, 923, (1 << 0));
652 dib8000_write_word(state, 923, (0 << 0));
653 }
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300654
655 msleep(1);
656 return 0;
657}
658
Mauro Carvalho Chehabd44913c2014-05-29 09:20:17 -0300659static int dib8000_set_wbd_ref(struct dvb_frontend *fe, u16 value)
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300660{
661 struct dib8000_state *state = fe->demodulator_priv;
662 if (value > 4095)
663 value = 4095;
664 state->wbd_ref = value;
665 return dib8000_write_word(state, 106, value);
666}
Patrick Boettcher173a64c2013-04-22 12:45:52 -0300667
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300668static void dib8000_reset_pll_common(struct dib8000_state *state, const struct dibx000_bandwidth_config *bw)
669{
670 dprintk("ifreq: %d %x, inversion: %d", bw->ifreq, bw->ifreq, bw->ifreq >> 25);
Olivier Grenie0c32dbd2011-08-10 05:17:18 -0300671 if (state->revision != 0x8090) {
672 dib8000_write_word(state, 23,
673 (u16) (((bw->internal * 1000) >> 16) & 0xffff));
674 dib8000_write_word(state, 24,
675 (u16) ((bw->internal * 1000) & 0xffff));
676 } else {
677 dib8000_write_word(state, 23, (u16) (((bw->internal / 2 * 1000) >> 16) & 0xffff));
678 dib8000_write_word(state, 24,
679 (u16) ((bw->internal / 2 * 1000) & 0xffff));
680 }
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300681 dib8000_write_word(state, 27, (u16) ((bw->ifreq >> 16) & 0x01ff));
682 dib8000_write_word(state, 28, (u16) (bw->ifreq & 0xffff));
683 dib8000_write_word(state, 26, (u16) ((bw->ifreq >> 25) & 0x0003));
684
Olivier Grenie0c32dbd2011-08-10 05:17:18 -0300685 if (state->revision != 0x8090)
686 dib8000_write_word(state, 922, bw->sad_cfg);
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300687}
688
689static void dib8000_reset_pll(struct dib8000_state *state)
690{
691 const struct dibx000_bandwidth_config *pll = state->cfg.pll;
Olivier Grenie0c32dbd2011-08-10 05:17:18 -0300692 u16 clk_cfg1, reg;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300693
Olivier Grenie0c32dbd2011-08-10 05:17:18 -0300694 if (state->revision != 0x8090) {
695 dib8000_write_word(state, 901,
696 (pll->pll_prediv << 8) | (pll->pll_ratio << 0));
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300697
Olivier Grenie0c32dbd2011-08-10 05:17:18 -0300698 clk_cfg1 = (1 << 10) | (0 << 9) | (pll->IO_CLK_en_core << 8) |
699 (pll->bypclk_div << 5) | (pll->enable_refdiv << 4) |
700 (1 << 3) | (pll->pll_range << 1) |
701 (pll->pll_reset << 0);
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300702
Olivier Grenie0c32dbd2011-08-10 05:17:18 -0300703 dib8000_write_word(state, 902, clk_cfg1);
704 clk_cfg1 = (clk_cfg1 & 0xfff7) | (pll->pll_bypass << 3);
705 dib8000_write_word(state, 902, clk_cfg1);
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300706
Olivier Grenie0c32dbd2011-08-10 05:17:18 -0300707 dprintk("clk_cfg1: 0x%04x", clk_cfg1);
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300708
Olivier Grenie0c32dbd2011-08-10 05:17:18 -0300709 /* smpl_cfg: P_refclksel=2, P_ensmplsel=1 nodivsmpl=1 */
710 if (state->cfg.pll->ADClkSrc == 0)
711 dib8000_write_word(state, 904,
712 (0 << 15) | (0 << 12) | (0 << 10) |
713 (pll->modulo << 8) |
714 (pll->ADClkSrc << 7) | (0 << 1));
715 else if (state->cfg.refclksel != 0)
716 dib8000_write_word(state, 904, (0 << 15) | (1 << 12) |
717 ((state->cfg.refclksel & 0x3) << 10) |
718 (pll->modulo << 8) |
719 (pll->ADClkSrc << 7) | (0 << 1));
720 else
721 dib8000_write_word(state, 904, (0 << 15) | (1 << 12) |
722 (3 << 10) | (pll->modulo << 8) |
723 (pll->ADClkSrc << 7) | (0 << 1));
724 } else {
725 dib8000_write_word(state, 1856, (!pll->pll_reset<<13) |
726 (pll->pll_range<<12) | (pll->pll_ratio<<6) |
727 (pll->pll_prediv));
728
729 reg = dib8000_read_word(state, 1857);
730 dib8000_write_word(state, 1857, reg|(!pll->pll_bypass<<15));
731
732 reg = dib8000_read_word(state, 1858); /* Force clk out pll /2 */
733 dib8000_write_word(state, 1858, reg | 1);
734
735 dib8000_write_word(state, 904, (pll->modulo << 8));
736 }
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300737
738 dib8000_reset_pll_common(state, pll);
739}
740
Mauro Carvalho Chehabd44913c2014-05-29 09:20:17 -0300741static int dib8000_update_pll(struct dvb_frontend *fe,
Patrick Boettcher173a64c2013-04-22 12:45:52 -0300742 struct dibx000_bandwidth_config *pll, u32 bw, u8 ratio)
Olivier Grenie0c32dbd2011-08-10 05:17:18 -0300743{
744 struct dib8000_state *state = fe->demodulator_priv;
745 u16 reg_1857, reg_1856 = dib8000_read_word(state, 1856);
Patrick Boettcher173a64c2013-04-22 12:45:52 -0300746 u8 loopdiv, prediv, oldprediv = state->cfg.pll->pll_prediv ;
Olivier Grenie0c32dbd2011-08-10 05:17:18 -0300747 u32 internal, xtal;
748
749 /* get back old values */
750 prediv = reg_1856 & 0x3f;
751 loopdiv = (reg_1856 >> 6) & 0x3f;
752
Patrick Boettcher173a64c2013-04-22 12:45:52 -0300753 if ((pll == NULL) || (pll->pll_prediv == prediv &&
754 pll->pll_ratio == loopdiv))
755 return -EINVAL;
756
757 dprintk("Updating pll (prediv: old = %d new = %d ; loopdiv : old = %d new = %d)", prediv, pll->pll_prediv, loopdiv, pll->pll_ratio);
758 if (state->revision == 0x8090) {
Olivier Grenie0c32dbd2011-08-10 05:17:18 -0300759 reg_1856 &= 0xf000;
760 reg_1857 = dib8000_read_word(state, 1857);
761 /* disable PLL */
762 dib8000_write_word(state, 1857, reg_1857 & ~(1 << 15));
763
764 dib8000_write_word(state, 1856, reg_1856 |
765 ((pll->pll_ratio & 0x3f) << 6) |
766 (pll->pll_prediv & 0x3f));
767
768 /* write new system clk into P_sec_len */
769 internal = dib8000_read32(state, 23) / 1000;
770 dprintk("Old Internal = %d", internal);
771 xtal = 2 * (internal / loopdiv) * prediv;
772 internal = 1000 * (xtal/pll->pll_prediv) * pll->pll_ratio;
773 dprintk("Xtal = %d , New Fmem = %d New Fdemod = %d, New Fsampling = %d", xtal, internal/1000, internal/2000, internal/8000);
774 dprintk("New Internal = %d", internal);
775
776 dib8000_write_word(state, 23,
777 (u16) (((internal / 2) >> 16) & 0xffff));
778 dib8000_write_word(state, 24, (u16) ((internal / 2) & 0xffff));
779 /* enable PLL */
780 dib8000_write_word(state, 1857, reg_1857 | (1 << 15));
781
782 while (((dib8000_read_word(state, 1856)>>15)&0x1) != 1)
783 dprintk("Waiting for PLL to lock");
784
785 /* verify */
786 reg_1856 = dib8000_read_word(state, 1856);
787 dprintk("PLL Updated with prediv = %d and loopdiv = %d",
788 reg_1856&0x3f, (reg_1856>>6)&0x3f);
Patrick Boettcher173a64c2013-04-22 12:45:52 -0300789 } else {
790 if (bw != state->current_demod_bw) {
791 /** Bandwidth change => force PLL update **/
792 dprintk("PLL: Bandwidth Change %d MHz -> %d MHz (prediv: %d->%d)", state->current_demod_bw / 1000, bw / 1000, oldprediv, state->cfg.pll->pll_prediv);
Olivier Grenie0c32dbd2011-08-10 05:17:18 -0300793
Patrick Boettcher173a64c2013-04-22 12:45:52 -0300794 if (state->cfg.pll->pll_prediv != oldprediv) {
795 /** Full PLL change only if prediv is changed **/
796
797 /** full update => bypass and reconfigure **/
798 dprintk("PLL: New Setting for %d MHz Bandwidth (prediv: %d, ratio: %d)", bw/1000, state->cfg.pll->pll_prediv, state->cfg.pll->pll_ratio);
799 dib8000_write_word(state, 902, dib8000_read_word(state, 902) | (1<<3)); /* bypass PLL */
800 dib8000_reset_pll(state);
801 dib8000_write_word(state, 898, 0x0004); /* sad */
802 } else
803 ratio = state->cfg.pll->pll_ratio;
804
805 state->current_demod_bw = bw;
806 }
807
808 if (ratio != 0) {
809 /** ratio update => only change ratio **/
810 dprintk("PLL: Update ratio (prediv: %d, ratio: %d)", state->cfg.pll->pll_prediv, ratio);
811 dib8000_write_word(state, 901, (state->cfg.pll->pll_prediv << 8) | (ratio << 0)); /* only the PLL ratio is updated. */
812 }
Mauro Carvalho Chehab6ef06e72013-12-16 19:10:59 -0300813 }
Patrick Boettcher173a64c2013-04-22 12:45:52 -0300814
815 return 0;
Olivier Grenie0c32dbd2011-08-10 05:17:18 -0300816}
Olivier Grenie0c32dbd2011-08-10 05:17:18 -0300817
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300818static int dib8000_reset_gpio(struct dib8000_state *st)
819{
820 /* reset the GPIOs */
821 dib8000_write_word(st, 1029, st->cfg.gpio_dir);
822 dib8000_write_word(st, 1030, st->cfg.gpio_val);
823
824 /* TODO 782 is P_gpio_od */
825
826 dib8000_write_word(st, 1032, st->cfg.gpio_pwm_pos);
827
828 dib8000_write_word(st, 1037, st->cfg.pwm_freq_div);
829 return 0;
830}
831
832static int dib8000_cfg_gpio(struct dib8000_state *st, u8 num, u8 dir, u8 val)
833{
834 st->cfg.gpio_dir = dib8000_read_word(st, 1029);
835 st->cfg.gpio_dir &= ~(1 << num); /* reset the direction bit */
836 st->cfg.gpio_dir |= (dir & 0x1) << num; /* set the new direction */
837 dib8000_write_word(st, 1029, st->cfg.gpio_dir);
838
839 st->cfg.gpio_val = dib8000_read_word(st, 1030);
840 st->cfg.gpio_val &= ~(1 << num); /* reset the direction bit */
841 st->cfg.gpio_val |= (val & 0x01) << num; /* set the new value */
842 dib8000_write_word(st, 1030, st->cfg.gpio_val);
843
844 dprintk("gpio dir: %x: gpio val: %x", st->cfg.gpio_dir, st->cfg.gpio_val);
845
846 return 0;
847}
848
Mauro Carvalho Chehabd44913c2014-05-29 09:20:17 -0300849static int dib8000_set_gpio(struct dvb_frontend *fe, u8 num, u8 dir, u8 val)
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300850{
851 struct dib8000_state *state = fe->demodulator_priv;
852 return dib8000_cfg_gpio(state, num, dir, val);
853}
854
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300855static const u16 dib8000_defaults[] = {
856 /* auto search configuration - lock0 by default waiting
857 * for cpil_lock; lock1 cpil_lock; lock2 tmcc_sync_lock */
858 3, 7,
859 0x0004,
860 0x0400,
861 0x0814,
862
863 12, 11,
864 0x001b,
865 0x7740,
866 0x005b,
867 0x8d80,
868 0x01c9,
869 0xc380,
870 0x0000,
871 0x0080,
872 0x0000,
873 0x0090,
874 0x0001,
875 0xd4c0,
876
877 /*1, 32,
Olivier Grenie4c70e072011-01-03 15:33:37 -0300878 0x6680 // P_corm_thres Lock algorithms configuration */
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300879
880 11, 80, /* set ADC level to -16 */
881 (1 << 13) - 825 - 117,
882 (1 << 13) - 837 - 117,
883 (1 << 13) - 811 - 117,
884 (1 << 13) - 766 - 117,
885 (1 << 13) - 737 - 117,
886 (1 << 13) - 693 - 117,
887 (1 << 13) - 648 - 117,
888 (1 << 13) - 619 - 117,
889 (1 << 13) - 575 - 117,
890 (1 << 13) - 531 - 117,
891 (1 << 13) - 501 - 117,
892
893 4, 108,
894 0,
895 0,
896 0,
897 0,
898
899 1, 175,
900 0x0410,
901 1, 179,
902 8192, // P_fft_nb_to_cut
903
904 6, 181,
905 0x2800, // P_coff_corthres_ ( 2k 4k 8k ) 0x2800
906 0x2800,
907 0x2800,
908 0x2800, // P_coff_cpilthres_ ( 2k 4k 8k ) 0x2800
909 0x2800,
910 0x2800,
911
912 2, 193,
913 0x0666, // P_pha3_thres
914 0x0000, // P_cti_use_cpe, P_cti_use_prog
915
916 2, 205,
917 0x200f, // P_cspu_regul, P_cspu_win_cut
918 0x000f, // P_des_shift_work
919
920 5, 215,
921 0x023d, // P_adp_regul_cnt
922 0x00a4, // P_adp_noise_cnt
923 0x00a4, // P_adp_regul_ext
924 0x7ff0, // P_adp_noise_ext
925 0x3ccc, // P_adp_fil
926
927 1, 230,
928 0x0000, // P_2d_byp_ti_num
929
930 1, 263,
931 0x800, //P_equal_thres_wgn
932
933 1, 268,
934 (2 << 9) | 39, // P_equal_ctrl_synchro, P_equal_speedmode
935
936 1, 270,
937 0x0001, // P_div_lock0_wait
938 1, 285,
939 0x0020, //p_fec_
940 1, 299,
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300941 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 -0300942
943 1, 338,
944 (1 << 12) | // P_ctrl_corm_thres4pre_freq_inh=1
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300945 (1 << 10) |
946 (0 << 9) | /* P_ctrl_pre_freq_inh=0 */
947 (3 << 5) | /* P_ctrl_pre_freq_step=3 */
948 (1 << 0), /* P_pre_freq_win_len=1 */
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300949
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300950 0,
951};
952
953static u16 dib8000_identify(struct i2c_device *client)
954{
955 u16 value;
956
957 //because of glitches sometimes
958 value = dib8000_i2c_read16(client, 896);
959
960 if ((value = dib8000_i2c_read16(client, 896)) != 0x01b3) {
961 dprintk("wrong Vendor ID (read=0x%x)", value);
962 return 0;
963 }
964
965 value = dib8000_i2c_read16(client, 897);
Olivier Grenie0c32dbd2011-08-10 05:17:18 -0300966 if (value != 0x8000 && value != 0x8001 &&
967 value != 0x8002 && value != 0x8090) {
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300968 dprintk("wrong Device ID (%x)", value);
969 return 0;
970 }
971
972 switch (value) {
973 case 0x8000:
974 dprintk("found DiB8000A");
975 break;
976 case 0x8001:
977 dprintk("found DiB8000B");
978 break;
979 case 0x8002:
980 dprintk("found DiB8000C");
981 break;
Olivier Grenie0c32dbd2011-08-10 05:17:18 -0300982 case 0x8090:
983 dprintk("found DiB8096P");
984 break;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300985 }
986 return value;
987}
988
Mauro Carvalho Chehab7a9d85d2013-12-17 04:55:26 -0300989static int dib8000_read_unc_blocks(struct dvb_frontend *fe, u32 *unc);
990
Mauro Carvalho Chehab6ef06e72013-12-16 19:10:59 -0300991static void dib8000_reset_stats(struct dvb_frontend *fe)
992{
993 struct dib8000_state *state = fe->demodulator_priv;
994 struct dtv_frontend_properties *c = &state->fe[0]->dtv_property_cache;
Mauro Carvalho Chehab7a9d85d2013-12-17 04:55:26 -0300995 u32 ucb;
Mauro Carvalho Chehab6ef06e72013-12-16 19:10:59 -0300996
997 memset(&c->strength, 0, sizeof(c->strength));
998 memset(&c->cnr, 0, sizeof(c->cnr));
999 memset(&c->post_bit_error, 0, sizeof(c->post_bit_error));
1000 memset(&c->post_bit_count, 0, sizeof(c->post_bit_count));
1001 memset(&c->block_error, 0, sizeof(c->block_error));
1002
1003 c->strength.len = 1;
1004 c->cnr.len = 1;
1005 c->block_error.len = 1;
Mauro Carvalho Chehab0400c532013-12-17 11:34:22 -03001006 c->block_count.len = 1;
Mauro Carvalho Chehab6ef06e72013-12-16 19:10:59 -03001007 c->post_bit_error.len = 1;
1008 c->post_bit_count.len = 1;
1009
Mauro Carvalho Chehabb4600d72013-12-16 20:00:34 -03001010 c->strength.stat[0].scale = FE_SCALE_DECIBEL;
Mauro Carvalho Chehab6ef06e72013-12-16 19:10:59 -03001011 c->strength.stat[0].uvalue = 0;
1012
1013 c->cnr.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
1014 c->block_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
Mauro Carvalho Chehab0400c532013-12-17 11:34:22 -03001015 c->block_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
Mauro Carvalho Chehab6ef06e72013-12-16 19:10:59 -03001016 c->post_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
1017 c->post_bit_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
Mauro Carvalho Chehab7a9d85d2013-12-17 04:55:26 -03001018
1019 dib8000_read_unc_blocks(fe, &ucb);
Mauro Carvalho Chehab704f01b2013-12-17 10:08:20 -03001020
Mauro Carvalho Chehab7a9d85d2013-12-17 04:55:26 -03001021 state->init_ucb = -ucb;
Mauro Carvalho Chehab0400c532013-12-17 11:34:22 -03001022 state->ber_jiffies_stats = 0;
1023 state->per_jiffies_stats = 0;
1024 memset(&state->ber_jiffies_stats_layer, 0,
1025 sizeof(state->ber_jiffies_stats_layer));
Mauro Carvalho Chehab6ef06e72013-12-16 19:10:59 -03001026}
1027
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001028static int dib8000_reset(struct dvb_frontend *fe)
1029{
1030 struct dib8000_state *state = fe->demodulator_priv;
1031
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001032 if ((state->revision = dib8000_identify(&state->i2c)) == 0)
1033 return -EINVAL;
1034
Olivier Grenie0c32dbd2011-08-10 05:17:18 -03001035 /* sram lead in, rdy */
1036 if (state->revision != 0x8090)
1037 dib8000_write_word(state, 1287, 0x0003);
1038
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001039 if (state->revision == 0x8000)
1040 dprintk("error : dib8000 MA not supported");
1041
1042 dibx000_reset_i2c_master(&state->i2c_master);
1043
Olivier Grenie0c32dbd2011-08-10 05:17:18 -03001044 dib8000_set_power_mode(state, DIB8000_POWER_ALL);
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001045
1046 /* always leave the VBG voltage on - it consumes almost nothing but takes a long time to start */
Patrick Boettcher173a64c2013-04-22 12:45:52 -03001047 dib8000_set_adc_state(state, DIBX000_ADC_OFF);
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001048
1049 /* restart all parts */
1050 dib8000_write_word(state, 770, 0xffff);
1051 dib8000_write_word(state, 771, 0xffff);
1052 dib8000_write_word(state, 772, 0xfffc);
Mauro Carvalho Chehab6d384542014-07-04 14:15:33 -03001053 dib8000_write_word(state, 898, 0x000c); /* restart sad */
Olivier Grenie0c32dbd2011-08-10 05:17:18 -03001054 if (state->revision == 0x8090)
1055 dib8000_write_word(state, 1280, 0x0045);
1056 else
1057 dib8000_write_word(state, 1280, 0x004d);
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001058 dib8000_write_word(state, 1281, 0x000c);
1059
1060 dib8000_write_word(state, 770, 0x0000);
1061 dib8000_write_word(state, 771, 0x0000);
1062 dib8000_write_word(state, 772, 0x0000);
1063 dib8000_write_word(state, 898, 0x0004); // sad
1064 dib8000_write_word(state, 1280, 0x0000);
1065 dib8000_write_word(state, 1281, 0x0000);
1066
1067 /* drives */
Olivier Grenie0c32dbd2011-08-10 05:17:18 -03001068 if (state->revision != 0x8090) {
1069 if (state->cfg.drives)
1070 dib8000_write_word(state, 906, state->cfg.drives);
1071 else {
1072 dprintk("using standard PAD-drive-settings, please adjust settings in config-struct to be optimal.");
1073 /* min drive SDRAM - not optimal - adjust */
1074 dib8000_write_word(state, 906, 0x2d98);
1075 }
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001076 }
1077
1078 dib8000_reset_pll(state);
Olivier Grenie0c32dbd2011-08-10 05:17:18 -03001079 if (state->revision != 0x8090)
1080 dib8000_write_word(state, 898, 0x0004);
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001081
1082 if (dib8000_reset_gpio(state) != 0)
1083 dprintk("GPIO reset was not successful.");
1084
Olivier Grenie0c32dbd2011-08-10 05:17:18 -03001085 if ((state->revision != 0x8090) &&
1086 (dib8000_set_output_mode(fe, OUTMODE_HIGH_Z) != 0))
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001087 dprintk("OUTPUT_MODE could not be resetted.");
1088
1089 state->current_agc = NULL;
1090
1091 // P_iqc_alpha_pha, P_iqc_alpha_amp, P_iqc_dcc_alpha, ...
1092 /* P_iqc_ca2 = 0; P_iqc_impnc_on = 0; P_iqc_mode = 0; */
1093 if (state->cfg.pll->ifreq == 0)
1094 dib8000_write_word(state, 40, 0x0755); /* P_iqc_corr_inh = 0 enable IQcorr block */
1095 else
1096 dib8000_write_word(state, 40, 0x1f55); /* P_iqc_corr_inh = 1 disable IQcorr block */
1097
1098 {
1099 u16 l = 0, r;
1100 const u16 *n;
1101 n = dib8000_defaults;
1102 l = *n++;
1103 while (l) {
1104 r = *n++;
1105 do {
1106 dib8000_write_word(state, r, *n++);
1107 r++;
1108 } while (--l);
1109 l = *n++;
1110 }
1111 }
Patrick Boettcher173a64c2013-04-22 12:45:52 -03001112
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001113 state->isdbt_cfg_loaded = 0;
1114
1115 //div_cfg override for special configs
Patrick Boettcher173a64c2013-04-22 12:45:52 -03001116 if ((state->revision != 8090) && (state->cfg.div_cfg != 0))
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001117 dib8000_write_word(state, 903, state->cfg.div_cfg);
1118
1119 /* unforce divstr regardless whether i2c enumeration was done or not */
1120 dib8000_write_word(state, 1285, dib8000_read_word(state, 1285) & ~(1 << 1));
1121
Olivier Grenie4c70e072011-01-03 15:33:37 -03001122 dib8000_set_bandwidth(fe, 6000);
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001123
1124 dib8000_set_adc_state(state, DIBX000_SLOW_ADC_ON);
Patrick Boettcher173a64c2013-04-22 12:45:52 -03001125 dib8000_sad_calib(state);
1126 if (state->revision != 0x8090)
Olivier Grenie0c32dbd2011-08-10 05:17:18 -03001127 dib8000_set_adc_state(state, DIBX000_SLOW_ADC_OFF);
Patrick Boettcher173a64c2013-04-22 12:45:52 -03001128
1129 /* ber_rs_len = 3 */
1130 dib8000_write_word(state, 285, (dib8000_read_word(state, 285) & ~0x60) | (3 << 5));
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001131
Olivier Grenie0c32dbd2011-08-10 05:17:18 -03001132 dib8000_set_power_mode(state, DIB8000_POWER_INTERFACE_ONLY);
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001133
Mauro Carvalho Chehab6ef06e72013-12-16 19:10:59 -03001134 dib8000_reset_stats(fe);
1135
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001136 return 0;
1137}
1138
1139static void dib8000_restart_agc(struct dib8000_state *state)
1140{
1141 // P_restart_iqc & P_restart_agc
1142 dib8000_write_word(state, 770, 0x0a00);
1143 dib8000_write_word(state, 770, 0x0000);
1144}
1145
1146static int dib8000_update_lna(struct dib8000_state *state)
1147{
1148 u16 dyn_gain;
1149
1150 if (state->cfg.update_lna) {
1151 // read dyn_gain here (because it is demod-dependent and not tuner)
1152 dyn_gain = dib8000_read_word(state, 390);
1153
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001154 if (state->cfg.update_lna(state->fe[0], dyn_gain)) {
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001155 dib8000_restart_agc(state);
1156 return 1;
1157 }
1158 }
1159 return 0;
1160}
1161
1162static int dib8000_set_agc_config(struct dib8000_state *state, u8 band)
1163{
1164 struct dibx000_agc_config *agc = NULL;
1165 int i;
Olivier Grenie0c32dbd2011-08-10 05:17:18 -03001166 u16 reg;
1167
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001168 if (state->current_band == band && state->current_agc != NULL)
1169 return 0;
1170 state->current_band = band;
1171
1172 for (i = 0; i < state->cfg.agc_config_count; i++)
1173 if (state->cfg.agc[i].band_caps & band) {
1174 agc = &state->cfg.agc[i];
1175 break;
1176 }
1177
1178 if (agc == NULL) {
1179 dprintk("no valid AGC configuration found for band 0x%02x", band);
1180 return -EINVAL;
1181 }
1182
1183 state->current_agc = agc;
1184
1185 /* AGC */
1186 dib8000_write_word(state, 76, agc->setup);
1187 dib8000_write_word(state, 77, agc->inv_gain);
1188 dib8000_write_word(state, 78, agc->time_stabiliz);
1189 dib8000_write_word(state, 101, (agc->alpha_level << 12) | agc->thlock);
1190
1191 // Demod AGC loop configuration
1192 dib8000_write_word(state, 102, (agc->alpha_mant << 5) | agc->alpha_exp);
1193 dib8000_write_word(state, 103, (agc->beta_mant << 6) | agc->beta_exp);
1194
1195 dprintk("WBD: ref: %d, sel: %d, active: %d, alpha: %d",
1196 state->wbd_ref != 0 ? state->wbd_ref : agc->wbd_ref, agc->wbd_sel, !agc->perform_agc_softsplit, agc->wbd_sel);
1197
1198 /* AGC continued */
1199 if (state->wbd_ref != 0)
1200 dib8000_write_word(state, 106, state->wbd_ref);
1201 else // use default
1202 dib8000_write_word(state, 106, agc->wbd_ref);
Olivier Grenie0c32dbd2011-08-10 05:17:18 -03001203
1204 if (state->revision == 0x8090) {
1205 reg = dib8000_read_word(state, 922) & (0x3 << 2);
1206 dib8000_write_word(state, 922, reg | (agc->wbd_sel << 2));
1207 }
1208
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001209 dib8000_write_word(state, 107, (agc->wbd_alpha << 9) | (agc->perform_agc_softsplit << 8));
1210 dib8000_write_word(state, 108, agc->agc1_max);
1211 dib8000_write_word(state, 109, agc->agc1_min);
1212 dib8000_write_word(state, 110, agc->agc2_max);
1213 dib8000_write_word(state, 111, agc->agc2_min);
1214 dib8000_write_word(state, 112, (agc->agc1_pt1 << 8) | agc->agc1_pt2);
1215 dib8000_write_word(state, 113, (agc->agc1_slope1 << 8) | agc->agc1_slope2);
1216 dib8000_write_word(state, 114, (agc->agc2_pt1 << 8) | agc->agc2_pt2);
1217 dib8000_write_word(state, 115, (agc->agc2_slope1 << 8) | agc->agc2_slope2);
1218
1219 dib8000_write_word(state, 75, agc->agc1_pt3);
Olivier Grenie0c32dbd2011-08-10 05:17:18 -03001220 if (state->revision != 0x8090)
1221 dib8000_write_word(state, 923,
1222 (dib8000_read_word(state, 923) & 0xffe3) |
1223 (agc->wbd_inv << 4) | (agc->wbd_sel << 2));
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001224
1225 return 0;
1226}
1227
Mauro Carvalho Chehabd44913c2014-05-29 09:20:17 -03001228static void dib8000_pwm_agc_reset(struct dvb_frontend *fe)
Olivier Grenie03245a52009-12-04 13:27:57 -03001229{
1230 struct dib8000_state *state = fe->demodulator_priv;
1231 dib8000_set_adc_state(state, DIBX000_ADC_ON);
1232 dib8000_set_agc_config(state, (unsigned char)(BAND_OF_FREQUENCY(fe->dtv_property_cache.frequency / 1000)));
1233}
Olivier Grenie03245a52009-12-04 13:27:57 -03001234
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001235static int dib8000_agc_soft_split(struct dib8000_state *state)
1236{
1237 u16 agc, split_offset;
1238
1239 if (!state->current_agc || !state->current_agc->perform_agc_softsplit || state->current_agc->split.max == 0)
Mauro Carvalho Chehabd6c62b72014-07-04 14:15:37 -03001240 return 0;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001241
1242 // n_agc_global
1243 agc = dib8000_read_word(state, 390);
1244
1245 if (agc > state->current_agc->split.min_thres)
1246 split_offset = state->current_agc->split.min;
1247 else if (agc < state->current_agc->split.max_thres)
1248 split_offset = state->current_agc->split.max;
1249 else
1250 split_offset = state->current_agc->split.max *
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001251 (agc - state->current_agc->split.min_thres) /
1252 (state->current_agc->split.max_thres - state->current_agc->split.min_thres);
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001253
1254 dprintk("AGC split_offset: %d", split_offset);
1255
1256 // P_agc_force_split and P_agc_split_offset
1257 dib8000_write_word(state, 107, (dib8000_read_word(state, 107) & 0xff00) | split_offset);
1258 return 5000;
1259}
1260
1261static int dib8000_agc_startup(struct dvb_frontend *fe)
1262{
1263 struct dib8000_state *state = fe->demodulator_priv;
1264 enum frontend_tune_state *tune_state = &state->tune_state;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001265 int ret = 0;
Mauro Carvalho Chehab901c4ad2014-12-23 11:21:12 -03001266 u16 reg;
1267 u32 upd_demod_gain_period = 0x8000;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001268
1269 switch (*tune_state) {
1270 case CT_AGC_START:
1271 // set power-up level: interf+analog+AGC
1272
Olivier Grenie0c32dbd2011-08-10 05:17:18 -03001273 if (state->revision != 0x8090)
1274 dib8000_set_adc_state(state, DIBX000_ADC_ON);
1275 else {
1276 dib8000_set_power_mode(state, DIB8000_POWER_ALL);
1277
1278 reg = dib8000_read_word(state, 1947)&0xff00;
1279 dib8000_write_word(state, 1946,
1280 upd_demod_gain_period & 0xFFFF);
1281 /* bit 14 = enDemodGain */
1282 dib8000_write_word(state, 1947, reg | (1<<14) |
1283 ((upd_demod_gain_period >> 16) & 0xFF));
1284
1285 /* enable adc i & q */
1286 reg = dib8000_read_word(state, 1920);
1287 dib8000_write_word(state, 1920, (reg | 0x3) &
1288 (~(1 << 7)));
1289 }
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001290
1291 if (dib8000_set_agc_config(state, (unsigned char)(BAND_OF_FREQUENCY(fe->dtv_property_cache.frequency / 1000))) != 0) {
1292 *tune_state = CT_AGC_STOP;
1293 state->status = FE_STATUS_TUNE_FAILED;
1294 break;
1295 }
1296
1297 ret = 70;
1298 *tune_state = CT_AGC_STEP_0;
1299 break;
1300
1301 case CT_AGC_STEP_0:
1302 //AGC initialization
1303 if (state->cfg.agc_control)
Olivier Grenie4c70e072011-01-03 15:33:37 -03001304 state->cfg.agc_control(fe, 1);
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001305
1306 dib8000_restart_agc(state);
1307
1308 // wait AGC rough lock time
1309 ret = 50;
1310 *tune_state = CT_AGC_STEP_1;
1311 break;
1312
1313 case CT_AGC_STEP_1:
1314 // wait AGC accurate lock time
1315 ret = 70;
1316
1317 if (dib8000_update_lna(state))
1318 // wait only AGC rough lock time
1319 ret = 50;
1320 else
1321 *tune_state = CT_AGC_STEP_2;
1322 break;
1323
1324 case CT_AGC_STEP_2:
1325 dib8000_agc_soft_split(state);
1326
1327 if (state->cfg.agc_control)
Olivier Grenie4c70e072011-01-03 15:33:37 -03001328 state->cfg.agc_control(fe, 0);
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001329
1330 *tune_state = CT_AGC_STOP;
1331 break;
1332 default:
1333 ret = dib8000_agc_soft_split(state);
1334 break;
1335 }
1336 return ret;
1337
1338}
1339
Olivier Grenie0c32dbd2011-08-10 05:17:18 -03001340static void dib8096p_host_bus_drive(struct dib8000_state *state, u8 drive)
1341{
1342 u16 reg;
1343
1344 drive &= 0x7;
1345
1346 /* drive host bus 2, 3, 4 */
1347 reg = dib8000_read_word(state, 1798) &
1348 ~(0x7 | (0x7 << 6) | (0x7 << 12));
1349 reg |= (drive<<12) | (drive<<6) | drive;
1350 dib8000_write_word(state, 1798, reg);
1351
1352 /* drive host bus 5,6 */
1353 reg = dib8000_read_word(state, 1799) & ~((0x7 << 2) | (0x7 << 8));
1354 reg |= (drive<<8) | (drive<<2);
1355 dib8000_write_word(state, 1799, reg);
1356
1357 /* drive host bus 7, 8, 9 */
1358 reg = dib8000_read_word(state, 1800) &
1359 ~(0x7 | (0x7 << 6) | (0x7 << 12));
1360 reg |= (drive<<12) | (drive<<6) | drive;
1361 dib8000_write_word(state, 1800, reg);
1362
1363 /* drive host bus 10, 11 */
1364 reg = dib8000_read_word(state, 1801) & ~((0x7 << 2) | (0x7 << 8));
1365 reg |= (drive<<8) | (drive<<2);
1366 dib8000_write_word(state, 1801, reg);
1367
1368 /* drive host bus 12, 13, 14 */
1369 reg = dib8000_read_word(state, 1802) &
1370 ~(0x7 | (0x7 << 6) | (0x7 << 12));
1371 reg |= (drive<<12) | (drive<<6) | drive;
1372 dib8000_write_word(state, 1802, reg);
1373}
1374
1375static u32 dib8096p_calcSyncFreq(u32 P_Kin, u32 P_Kout,
1376 u32 insertExtSynchro, u32 syncSize)
1377{
1378 u32 quantif = 3;
1379 u32 nom = (insertExtSynchro * P_Kin+syncSize);
1380 u32 denom = P_Kout;
1381 u32 syncFreq = ((nom << quantif) / denom);
1382
1383 if ((syncFreq & ((1 << quantif) - 1)) != 0)
1384 syncFreq = (syncFreq >> quantif) + 1;
1385 else
1386 syncFreq = (syncFreq >> quantif);
1387
1388 if (syncFreq != 0)
1389 syncFreq = syncFreq - 1;
1390
1391 return syncFreq;
1392}
1393
1394static void dib8096p_cfg_DibTx(struct dib8000_state *state, u32 P_Kin,
1395 u32 P_Kout, u32 insertExtSynchro, u32 synchroMode,
1396 u32 syncWord, u32 syncSize)
1397{
1398 dprintk("Configure DibStream Tx");
1399
1400 dib8000_write_word(state, 1615, 1);
1401 dib8000_write_word(state, 1603, P_Kin);
1402 dib8000_write_word(state, 1605, P_Kout);
1403 dib8000_write_word(state, 1606, insertExtSynchro);
1404 dib8000_write_word(state, 1608, synchroMode);
1405 dib8000_write_word(state, 1609, (syncWord >> 16) & 0xffff);
1406 dib8000_write_word(state, 1610, syncWord & 0xffff);
1407 dib8000_write_word(state, 1612, syncSize);
1408 dib8000_write_word(state, 1615, 0);
1409}
1410
1411static void dib8096p_cfg_DibRx(struct dib8000_state *state, u32 P_Kin,
1412 u32 P_Kout, u32 synchroMode, u32 insertExtSynchro,
1413 u32 syncWord, u32 syncSize, u32 dataOutRate)
1414{
1415 u32 syncFreq;
1416
1417 dprintk("Configure DibStream Rx synchroMode = %d", synchroMode);
1418
1419 if ((P_Kin != 0) && (P_Kout != 0)) {
1420 syncFreq = dib8096p_calcSyncFreq(P_Kin, P_Kout,
1421 insertExtSynchro, syncSize);
1422 dib8000_write_word(state, 1542, syncFreq);
1423 }
1424
1425 dib8000_write_word(state, 1554, 1);
1426 dib8000_write_word(state, 1536, P_Kin);
1427 dib8000_write_word(state, 1537, P_Kout);
1428 dib8000_write_word(state, 1539, synchroMode);
1429 dib8000_write_word(state, 1540, (syncWord >> 16) & 0xffff);
1430 dib8000_write_word(state, 1541, syncWord & 0xffff);
1431 dib8000_write_word(state, 1543, syncSize);
1432 dib8000_write_word(state, 1544, dataOutRate);
1433 dib8000_write_word(state, 1554, 0);
1434}
1435
1436static void dib8096p_enMpegMux(struct dib8000_state *state, int onoff)
1437{
1438 u16 reg_1287;
1439
1440 reg_1287 = dib8000_read_word(state, 1287);
1441
1442 switch (onoff) {
1443 case 1:
1444 reg_1287 &= ~(1 << 8);
1445 break;
1446 case 0:
1447 reg_1287 |= (1 << 8);
1448 break;
1449 }
1450
1451 dib8000_write_word(state, 1287, reg_1287);
1452}
1453
1454static void dib8096p_configMpegMux(struct dib8000_state *state,
1455 u16 pulseWidth, u16 enSerialMode, u16 enSerialClkDiv2)
1456{
1457 u16 reg_1287;
1458
1459 dprintk("Enable Mpeg mux");
1460
1461 dib8096p_enMpegMux(state, 0);
1462
1463 /* If the input mode is MPEG do not divide the serial clock */
1464 if ((enSerialMode == 1) && (state->input_mode_mpeg == 1))
1465 enSerialClkDiv2 = 0;
1466
1467 reg_1287 = ((pulseWidth & 0x1f) << 3) |
1468 ((enSerialMode & 0x1) << 2) | (enSerialClkDiv2 & 0x1);
1469 dib8000_write_word(state, 1287, reg_1287);
1470
1471 dib8096p_enMpegMux(state, 1);
1472}
1473
1474static void dib8096p_setDibTxMux(struct dib8000_state *state, int mode)
1475{
1476 u16 reg_1288 = dib8000_read_word(state, 1288) & ~(0x7 << 7);
1477
1478 switch (mode) {
1479 case MPEG_ON_DIBTX:
1480 dprintk("SET MPEG ON DIBSTREAM TX");
1481 dib8096p_cfg_DibTx(state, 8, 5, 0, 0, 0, 0);
1482 reg_1288 |= (1 << 9); break;
1483 case DIV_ON_DIBTX:
1484 dprintk("SET DIV_OUT ON DIBSTREAM TX");
1485 dib8096p_cfg_DibTx(state, 5, 5, 0, 0, 0, 0);
1486 reg_1288 |= (1 << 8); break;
1487 case ADC_ON_DIBTX:
1488 dprintk("SET ADC_OUT ON DIBSTREAM TX");
1489 dib8096p_cfg_DibTx(state, 20, 5, 10, 0, 0, 0);
1490 reg_1288 |= (1 << 7); break;
1491 default:
1492 break;
1493 }
1494 dib8000_write_word(state, 1288, reg_1288);
1495}
1496
1497static void dib8096p_setHostBusMux(struct dib8000_state *state, int mode)
1498{
1499 u16 reg_1288 = dib8000_read_word(state, 1288) & ~(0x7 << 4);
1500
1501 switch (mode) {
1502 case DEMOUT_ON_HOSTBUS:
1503 dprintk("SET DEM OUT OLD INTERF ON HOST BUS");
1504 dib8096p_enMpegMux(state, 0);
1505 reg_1288 |= (1 << 6);
1506 break;
1507 case DIBTX_ON_HOSTBUS:
1508 dprintk("SET DIBSTREAM TX ON HOST BUS");
1509 dib8096p_enMpegMux(state, 0);
1510 reg_1288 |= (1 << 5);
1511 break;
1512 case MPEG_ON_HOSTBUS:
1513 dprintk("SET MPEG MUX ON HOST BUS");
1514 reg_1288 |= (1 << 4);
1515 break;
1516 default:
1517 break;
1518 }
1519 dib8000_write_word(state, 1288, reg_1288);
1520}
1521
1522static int dib8096p_set_diversity_in(struct dvb_frontend *fe, int onoff)
1523{
1524 struct dib8000_state *state = fe->demodulator_priv;
1525 u16 reg_1287;
1526
1527 switch (onoff) {
1528 case 0: /* only use the internal way - not the diversity input */
1529 dprintk("%s mode OFF : by default Enable Mpeg INPUT",
1530 __func__);
1531 /* outputRate = 8 */
1532 dib8096p_cfg_DibRx(state, 8, 5, 0, 0, 0, 8, 0);
1533
1534 /* Do not divide the serial clock of MPEG MUX in
1535 SERIAL MODE in case input mode MPEG is used */
1536 reg_1287 = dib8000_read_word(state, 1287);
1537 /* enSerialClkDiv2 == 1 ? */
1538 if ((reg_1287 & 0x1) == 1) {
1539 /* force enSerialClkDiv2 = 0 */
1540 reg_1287 &= ~0x1;
1541 dib8000_write_word(state, 1287, reg_1287);
1542 }
1543 state->input_mode_mpeg = 1;
1544 break;
1545 case 1: /* both ways */
1546 case 2: /* only the diversity input */
1547 dprintk("%s ON : Enable diversity INPUT", __func__);
1548 dib8096p_cfg_DibRx(state, 5, 5, 0, 0, 0, 0, 0);
1549 state->input_mode_mpeg = 0;
1550 break;
1551 }
1552
1553 dib8000_set_diversity_in(state->fe[0], onoff);
1554 return 0;
1555}
1556
1557static int dib8096p_set_output_mode(struct dvb_frontend *fe, int mode)
1558{
1559 struct dib8000_state *state = fe->demodulator_priv;
1560 u16 outreg, smo_mode, fifo_threshold;
1561 u8 prefer_mpeg_mux_use = 1;
1562 int ret = 0;
1563
Patrick Boettcher173a64c2013-04-22 12:45:52 -03001564 state->output_mode = mode;
Olivier Grenie0c32dbd2011-08-10 05:17:18 -03001565 dib8096p_host_bus_drive(state, 1);
1566
1567 fifo_threshold = 1792;
1568 smo_mode = (dib8000_read_word(state, 299) & 0x0050) | (1 << 1);
1569 outreg = dib8000_read_word(state, 1286) &
1570 ~((1 << 10) | (0x7 << 6) | (1 << 1));
1571
1572 switch (mode) {
1573 case OUTMODE_HIGH_Z:
1574 outreg = 0;
1575 break;
1576
1577 case OUTMODE_MPEG2_SERIAL:
1578 if (prefer_mpeg_mux_use) {
1579 dprintk("dib8096P setting output mode TS_SERIAL using Mpeg Mux");
1580 dib8096p_configMpegMux(state, 3, 1, 1);
1581 dib8096p_setHostBusMux(state, MPEG_ON_HOSTBUS);
1582 } else {/* Use Smooth block */
1583 dprintk("dib8096P setting output mode TS_SERIAL using Smooth bloc");
1584 dib8096p_setHostBusMux(state,
1585 DEMOUT_ON_HOSTBUS);
1586 outreg |= (2 << 6) | (0 << 1);
1587 }
1588 break;
1589
1590 case OUTMODE_MPEG2_PAR_GATED_CLK:
1591 if (prefer_mpeg_mux_use) {
1592 dprintk("dib8096P setting output mode TS_PARALLEL_GATED using Mpeg Mux");
1593 dib8096p_configMpegMux(state, 2, 0, 0);
1594 dib8096p_setHostBusMux(state, MPEG_ON_HOSTBUS);
1595 } else { /* Use Smooth block */
1596 dprintk("dib8096P setting output mode TS_PARALLEL_GATED using Smooth block");
1597 dib8096p_setHostBusMux(state,
1598 DEMOUT_ON_HOSTBUS);
1599 outreg |= (0 << 6);
1600 }
1601 break;
1602
1603 case OUTMODE_MPEG2_PAR_CONT_CLK: /* Using Smooth block only */
1604 dprintk("dib8096P setting output mode TS_PARALLEL_CONT using Smooth block");
1605 dib8096p_setHostBusMux(state, DEMOUT_ON_HOSTBUS);
1606 outreg |= (1 << 6);
1607 break;
1608
1609 case OUTMODE_MPEG2_FIFO:
1610 /* Using Smooth block because not supported
1611 by new Mpeg Mux bloc */
1612 dprintk("dib8096P setting output mode TS_FIFO using Smooth block");
1613 dib8096p_setHostBusMux(state, DEMOUT_ON_HOSTBUS);
1614 outreg |= (5 << 6);
1615 smo_mode |= (3 << 1);
1616 fifo_threshold = 512;
1617 break;
1618
1619 case OUTMODE_DIVERSITY:
1620 dprintk("dib8096P setting output mode MODE_DIVERSITY");
1621 dib8096p_setDibTxMux(state, DIV_ON_DIBTX);
1622 dib8096p_setHostBusMux(state, DIBTX_ON_HOSTBUS);
1623 break;
1624
1625 case OUTMODE_ANALOG_ADC:
1626 dprintk("dib8096P setting output mode MODE_ANALOG_ADC");
1627 dib8096p_setDibTxMux(state, ADC_ON_DIBTX);
1628 dib8096p_setHostBusMux(state, DIBTX_ON_HOSTBUS);
1629 break;
1630 }
1631
1632 if (mode != OUTMODE_HIGH_Z)
1633 outreg |= (1<<10);
1634
1635 dprintk("output_mpeg2_in_188_bytes = %d",
1636 state->cfg.output_mpeg2_in_188_bytes);
1637 if (state->cfg.output_mpeg2_in_188_bytes)
1638 smo_mode |= (1 << 5);
1639
1640 ret |= dib8000_write_word(state, 299, smo_mode);
1641 /* synchronous fread */
1642 ret |= dib8000_write_word(state, 299 + 1, fifo_threshold);
1643 ret |= dib8000_write_word(state, 1286, outreg);
1644
1645 return ret;
1646}
1647
1648static int map_addr_to_serpar_number(struct i2c_msg *msg)
1649{
1650 if (msg->buf[0] <= 15)
1651 msg->buf[0] -= 1;
1652 else if (msg->buf[0] == 17)
1653 msg->buf[0] = 15;
1654 else if (msg->buf[0] == 16)
1655 msg->buf[0] = 17;
1656 else if (msg->buf[0] == 19)
1657 msg->buf[0] = 16;
1658 else if (msg->buf[0] >= 21 && msg->buf[0] <= 25)
1659 msg->buf[0] -= 3;
1660 else if (msg->buf[0] == 28)
1661 msg->buf[0] = 23;
1662 else if (msg->buf[0] == 99)
1663 msg->buf[0] = 99;
1664 else
1665 return -EINVAL;
1666 return 0;
1667}
1668
1669static int dib8096p_tuner_write_serpar(struct i2c_adapter *i2c_adap,
1670 struct i2c_msg msg[], int num)
1671{
1672 struct dib8000_state *state = i2c_get_adapdata(i2c_adap);
1673 u8 n_overflow = 1;
1674 u16 i = 1000;
1675 u16 serpar_num = msg[0].buf[0];
1676
1677 while (n_overflow == 1 && i) {
1678 n_overflow = (dib8000_read_word(state, 1984) >> 1) & 0x1;
1679 i--;
1680 if (i == 0)
1681 dprintk("Tuner ITF: write busy (overflow)");
1682 }
1683 dib8000_write_word(state, 1985, (1 << 6) | (serpar_num & 0x3f));
1684 dib8000_write_word(state, 1986, (msg[0].buf[1] << 8) | msg[0].buf[2]);
1685
1686 return num;
1687}
1688
1689static int dib8096p_tuner_read_serpar(struct i2c_adapter *i2c_adap,
1690 struct i2c_msg msg[], int num)
1691{
1692 struct dib8000_state *state = i2c_get_adapdata(i2c_adap);
1693 u8 n_overflow = 1, n_empty = 1;
1694 u16 i = 1000;
1695 u16 serpar_num = msg[0].buf[0];
1696 u16 read_word;
1697
1698 while (n_overflow == 1 && i) {
1699 n_overflow = (dib8000_read_word(state, 1984) >> 1) & 0x1;
1700 i--;
1701 if (i == 0)
1702 dprintk("TunerITF: read busy (overflow)");
1703 }
1704 dib8000_write_word(state, 1985, (0<<6) | (serpar_num&0x3f));
1705
1706 i = 1000;
1707 while (n_empty == 1 && i) {
1708 n_empty = dib8000_read_word(state, 1984)&0x1;
1709 i--;
1710 if (i == 0)
1711 dprintk("TunerITF: read busy (empty)");
1712 }
1713
1714 read_word = dib8000_read_word(state, 1987);
1715 msg[1].buf[0] = (read_word >> 8) & 0xff;
1716 msg[1].buf[1] = (read_word) & 0xff;
1717
1718 return num;
1719}
1720
1721static int dib8096p_tuner_rw_serpar(struct i2c_adapter *i2c_adap,
1722 struct i2c_msg msg[], int num)
1723{
1724 if (map_addr_to_serpar_number(&msg[0]) == 0) {
1725 if (num == 1) /* write */
1726 return dib8096p_tuner_write_serpar(i2c_adap, msg, 1);
1727 else /* read */
1728 return dib8096p_tuner_read_serpar(i2c_adap, msg, 2);
1729 }
1730 return num;
1731}
1732
1733static int dib8096p_rw_on_apb(struct i2c_adapter *i2c_adap,
1734 struct i2c_msg msg[], int num, u16 apb_address)
1735{
1736 struct dib8000_state *state = i2c_get_adapdata(i2c_adap);
1737 u16 word;
1738
1739 if (num == 1) { /* write */
1740 dib8000_write_word(state, apb_address,
1741 ((msg[0].buf[1] << 8) | (msg[0].buf[2])));
1742 } else {
1743 word = dib8000_read_word(state, apb_address);
1744 msg[1].buf[0] = (word >> 8) & 0xff;
1745 msg[1].buf[1] = (word) & 0xff;
1746 }
1747 return num;
1748}
1749
1750static int dib8096p_tuner_xfer(struct i2c_adapter *i2c_adap,
1751 struct i2c_msg msg[], int num)
1752{
1753 struct dib8000_state *state = i2c_get_adapdata(i2c_adap);
1754 u16 apb_address = 0, word;
1755 int i = 0;
1756
1757 switch (msg[0].buf[0]) {
1758 case 0x12:
1759 apb_address = 1920;
1760 break;
1761 case 0x14:
1762 apb_address = 1921;
1763 break;
1764 case 0x24:
1765 apb_address = 1922;
1766 break;
1767 case 0x1a:
1768 apb_address = 1923;
1769 break;
1770 case 0x22:
1771 apb_address = 1924;
1772 break;
1773 case 0x33:
1774 apb_address = 1926;
1775 break;
1776 case 0x34:
1777 apb_address = 1927;
1778 break;
1779 case 0x35:
1780 apb_address = 1928;
1781 break;
1782 case 0x36:
1783 apb_address = 1929;
1784 break;
1785 case 0x37:
1786 apb_address = 1930;
1787 break;
1788 case 0x38:
1789 apb_address = 1931;
1790 break;
1791 case 0x39:
1792 apb_address = 1932;
1793 break;
1794 case 0x2a:
1795 apb_address = 1935;
1796 break;
1797 case 0x2b:
1798 apb_address = 1936;
1799 break;
1800 case 0x2c:
1801 apb_address = 1937;
1802 break;
1803 case 0x2d:
1804 apb_address = 1938;
1805 break;
1806 case 0x2e:
1807 apb_address = 1939;
1808 break;
1809 case 0x2f:
1810 apb_address = 1940;
1811 break;
1812 case 0x30:
1813 apb_address = 1941;
1814 break;
1815 case 0x31:
1816 apb_address = 1942;
1817 break;
1818 case 0x32:
1819 apb_address = 1943;
1820 break;
1821 case 0x3e:
1822 apb_address = 1944;
1823 break;
1824 case 0x3f:
1825 apb_address = 1945;
1826 break;
1827 case 0x40:
1828 apb_address = 1948;
1829 break;
1830 case 0x25:
1831 apb_address = 936;
1832 break;
1833 case 0x26:
1834 apb_address = 937;
1835 break;
1836 case 0x27:
1837 apb_address = 938;
1838 break;
1839 case 0x28:
1840 apb_address = 939;
1841 break;
1842 case 0x1d:
1843 /* get sad sel request */
1844 i = ((dib8000_read_word(state, 921) >> 12)&0x3);
1845 word = dib8000_read_word(state, 924+i);
1846 msg[1].buf[0] = (word >> 8) & 0xff;
1847 msg[1].buf[1] = (word) & 0xff;
1848 return num;
1849 case 0x1f:
1850 if (num == 1) { /* write */
1851 word = (u16) ((msg[0].buf[1] << 8) |
1852 msg[0].buf[2]);
1853 /* in the VGAMODE Sel are located on bit 0/1 */
1854 word &= 0x3;
1855 word = (dib8000_read_word(state, 921) &
1856 ~(3<<12)) | (word<<12);
1857 /* Set the proper input */
1858 dib8000_write_word(state, 921, word);
1859 return num;
1860 }
1861 }
1862
1863 if (apb_address != 0) /* R/W acces via APB */
1864 return dib8096p_rw_on_apb(i2c_adap, msg, num, apb_address);
1865 else /* R/W access via SERPAR */
1866 return dib8096p_tuner_rw_serpar(i2c_adap, msg, num);
1867
1868 return 0;
1869}
1870
1871static u32 dib8096p_i2c_func(struct i2c_adapter *adapter)
1872{
1873 return I2C_FUNC_I2C;
1874}
1875
1876static struct i2c_algorithm dib8096p_tuner_xfer_algo = {
1877 .master_xfer = dib8096p_tuner_xfer,
1878 .functionality = dib8096p_i2c_func,
1879};
1880
Mauro Carvalho Chehabd44913c2014-05-29 09:20:17 -03001881static struct i2c_adapter *dib8096p_get_i2c_tuner(struct dvb_frontend *fe)
Olivier Grenie0c32dbd2011-08-10 05:17:18 -03001882{
1883 struct dib8000_state *st = fe->demodulator_priv;
1884 return &st->dib8096p_tuner_adap;
1885}
Olivier Grenie0c32dbd2011-08-10 05:17:18 -03001886
Mauro Carvalho Chehabd44913c2014-05-29 09:20:17 -03001887static int dib8096p_tuner_sleep(struct dvb_frontend *fe, int onoff)
Olivier Grenie0c32dbd2011-08-10 05:17:18 -03001888{
1889 struct dib8000_state *state = fe->demodulator_priv;
1890 u16 en_cur_state;
1891
1892 dprintk("sleep dib8096p: %d", onoff);
1893
1894 en_cur_state = dib8000_read_word(state, 1922);
1895
1896 /* LNAs and MIX are ON and therefore it is a valid configuration */
1897 if (en_cur_state > 0xff)
1898 state->tuner_enable = en_cur_state ;
1899
1900 if (onoff)
1901 en_cur_state &= 0x00ff;
1902 else {
1903 if (state->tuner_enable != 0)
1904 en_cur_state = state->tuner_enable;
1905 }
1906
1907 dib8000_write_word(state, 1922, en_cur_state);
1908
1909 return 0;
1910}
Olivier Grenie0c32dbd2011-08-10 05:17:18 -03001911
Olivier Grenie4c70e072011-01-03 15:33:37 -03001912static const s32 lut_1000ln_mant[] =
Olivier Grenie03245a52009-12-04 13:27:57 -03001913{
Olivier Grenie9c783032009-12-07 07:49:40 -03001914 908, 7003, 7090, 7170, 7244, 7313, 7377, 7438, 7495, 7549, 7600
Olivier Grenie03245a52009-12-04 13:27:57 -03001915};
1916
Mauro Carvalho Chehabd44913c2014-05-29 09:20:17 -03001917static s32 dib8000_get_adc_power(struct dvb_frontend *fe, u8 mode)
Olivier Grenie03245a52009-12-04 13:27:57 -03001918{
Olivier Grenie4c70e072011-01-03 15:33:37 -03001919 struct dib8000_state *state = fe->demodulator_priv;
1920 u32 ix = 0, tmp_val = 0, exp = 0, mant = 0;
1921 s32 val;
Olivier Grenie03245a52009-12-04 13:27:57 -03001922
Olivier Grenie4c70e072011-01-03 15:33:37 -03001923 val = dib8000_read32(state, 384);
Olivier Grenie4c70e072011-01-03 15:33:37 -03001924 if (mode) {
1925 tmp_val = val;
1926 while (tmp_val >>= 1)
1927 exp++;
1928 mant = (val * 1000 / (1<<exp));
1929 ix = (u8)((mant-1000)/100); /* index of the LUT */
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001930 val = (lut_1000ln_mant[ix] + 693*(exp-20) - 6908);
Olivier Grenie4c70e072011-01-03 15:33:37 -03001931 val = (val*256)/1000;
1932 }
1933 return val;
Olivier Grenie03245a52009-12-04 13:27:57 -03001934}
Olivier Grenie03245a52009-12-04 13:27:57 -03001935
Mauro Carvalho Chehabd44913c2014-05-29 09:20:17 -03001936static int dib8090p_get_dc_power(struct dvb_frontend *fe, u8 IQ)
Olivier Grenie0c32dbd2011-08-10 05:17:18 -03001937{
1938 struct dib8000_state *state = fe->demodulator_priv;
1939 int val = 0;
1940
1941 switch (IQ) {
1942 case 1:
1943 val = dib8000_read_word(state, 403);
1944 break;
1945 case 0:
1946 val = dib8000_read_word(state, 404);
1947 break;
1948 }
1949 if (val & 0x200)
1950 val -= 1024;
1951
1952 return val;
1953}
Olivier Grenie0c32dbd2011-08-10 05:17:18 -03001954
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001955static void dib8000_update_timf(struct dib8000_state *state)
1956{
1957 u32 timf = state->timf = dib8000_read32(state, 435);
1958
1959 dib8000_write_word(state, 29, (u16) (timf >> 16));
1960 dib8000_write_word(state, 30, (u16) (timf & 0xffff));
1961 dprintk("Updated timing frequency: %d (default: %d)", state->timf, state->timf_default);
1962}
1963
Mauro Carvalho Chehabd44913c2014-05-29 09:20:17 -03001964static u32 dib8000_ctrl_timf(struct dvb_frontend *fe, uint8_t op, uint32_t timf)
Olivier Grenie0c32dbd2011-08-10 05:17:18 -03001965{
1966 struct dib8000_state *state = fe->demodulator_priv;
1967
1968 switch (op) {
1969 case DEMOD_TIMF_SET:
1970 state->timf = timf;
1971 break;
1972 case DEMOD_TIMF_UPDATE:
1973 dib8000_update_timf(state);
1974 break;
1975 case DEMOD_TIMF_GET:
1976 break;
1977 }
1978 dib8000_set_bandwidth(state->fe[0], 6000);
1979
1980 return state->timf;
1981}
Olivier Grenie0c32dbd2011-08-10 05:17:18 -03001982
Olivier Grenie5a0deee2011-05-03 12:27:33 -03001983static const u16 adc_target_16dB[11] = {
Mauro Carvalho Chehaba768f902014-07-04 14:15:38 -03001984 7250, 7238, 7264, 7309, 7338, 7382, 7427, 7456, 7500, 7544, 7574
Olivier Grenie5a0deee2011-05-03 12:27:33 -03001985};
Mauro Carvalho Chehaba768f902014-07-04 14:15:38 -03001986
Olivier Grenie5a0deee2011-05-03 12:27:33 -03001987static const u8 permu_seg[] = { 6, 5, 7, 4, 8, 3, 9, 2, 10, 1, 11, 0, 12 };
1988
Patrick Boettcher173a64c2013-04-22 12:45:52 -03001989static u16 dib8000_set_layer(struct dib8000_state *state, u8 layer_index, u16 max_constellation)
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001990{
Patrick Boettcher173a64c2013-04-22 12:45:52 -03001991 u8 cr, constellation, time_intlv;
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03001992 struct dtv_frontend_properties *c = &state->fe[0]->dtv_property_cache;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001993
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03001994 switch (c->layer[layer_index].modulation) {
Patrick Boettcher173a64c2013-04-22 12:45:52 -03001995 case DQPSK:
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001996 constellation = 0;
1997 break;
Patrick Boettcher173a64c2013-04-22 12:45:52 -03001998 case QPSK:
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001999 constellation = 1;
2000 break;
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002001 case QAM_16:
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002002 constellation = 2;
2003 break;
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002004 case QAM_64:
2005 default:
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002006 constellation = 3;
2007 break;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002008 }
2009
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03002010 switch (c->layer[layer_index].fec) {
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002011 case FEC_1_2:
2012 cr = 1;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002013 break;
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002014 case FEC_2_3:
2015 cr = 2;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002016 break;
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002017 case FEC_3_4:
2018 cr = 3;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002019 break;
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002020 case FEC_5_6:
2021 cr = 5;
2022 break;
2023 case FEC_7_8:
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002024 default:
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002025 cr = 7;
2026 break;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002027 }
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002028
Mauro Carvalho Chehab34ba2e62014-07-04 14:15:27 -03002029 time_intlv = fls(c->layer[layer_index].interleaving);
2030 if (time_intlv > 3 && !(time_intlv == 4 && c->isdbt_sb_mode == 1))
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002031 time_intlv = 0;
2032
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03002033 dib8000_write_word(state, 2 + layer_index, (constellation << 10) | ((c->layer[layer_index].segment_count & 0xf) << 6) | (cr << 3) | time_intlv);
2034 if (c->layer[layer_index].segment_count > 0) {
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002035 switch (max_constellation) {
2036 case DQPSK:
2037 case QPSK:
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03002038 if (c->layer[layer_index].modulation == QAM_16 || c->layer[layer_index].modulation == QAM_64)
2039 max_constellation = c->layer[layer_index].modulation;
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002040 break;
2041 case QAM_16:
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03002042 if (c->layer[layer_index].modulation == QAM_64)
2043 max_constellation = c->layer[layer_index].modulation;
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002044 break;
2045 }
2046 }
2047
2048 return max_constellation;
2049}
2050
2051static 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 */
2052static 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 */
2053static 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 */
2054static u16 dib8000_adp_fine_tune(struct dib8000_state *state, u16 max_constellation)
2055{
2056 u16 i, ana_gain = 0;
2057 const u16 *adp;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002058
2059 /* channel estimation fine configuration */
2060 switch (max_constellation) {
2061 case QAM_64:
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002062 ana_gain = 0x7;
2063 adp = &adp_Q64[0];
2064 break;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002065 case QAM_16:
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002066 ana_gain = 0x7;
2067 adp = &adp_Q16[0];
2068 break;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002069 default:
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002070 ana_gain = 0;
2071 adp = &adp_Qdefault[0];
2072 break;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002073 }
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002074
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002075 for (i = 0; i < 4; i++)
2076 dib8000_write_word(state, 215 + i, adp[i]);
2077
2078 return ana_gain;
2079}
2080
2081static void dib8000_update_ana_gain(struct dib8000_state *state, u16 ana_gain)
2082{
2083 u16 i;
2084
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002085 dib8000_write_word(state, 116, ana_gain);
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002086
2087 /* update ADC target depending on ana_gain */
2088 if (ana_gain) { /* set -16dB ADC target for ana_gain=-1 */
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002089 for (i = 0; i < 10; i++)
2090 dib8000_write_word(state, 80 + i, adc_target_16dB[i]);
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002091 } else { /* set -22dB ADC target for ana_gain=0 */
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002092 for (i = 0; i < 10; i++)
2093 dib8000_write_word(state, 80 + i, adc_target_16dB[i] - 355);
2094 }
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002095}
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002096
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002097static void dib8000_load_ana_fe_coefs(struct dib8000_state *state, const s16 *ana_fe)
2098{
2099 u16 mode = 0;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002100
2101 if (state->isdbt_cfg_loaded == 0)
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002102 for (mode = 0; mode < 24; mode++)
2103 dib8000_write_word(state, 117 + mode, ana_fe[mode]);
2104}
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002105
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002106static const u16 lut_prbs_2k[14] = {
2107 0, 0x423, 0x009, 0x5C7, 0x7A6, 0x3D8, 0x527, 0x7FF, 0x79B, 0x3D6, 0x3A2, 0x53B, 0x2F4, 0x213
2108};
2109static const u16 lut_prbs_4k[14] = {
2110 0, 0x208, 0x0C3, 0x7B9, 0x423, 0x5C7, 0x3D8, 0x7FF, 0x3D6, 0x53B, 0x213, 0x029, 0x0D0, 0x48E
2111};
2112static const u16 lut_prbs_8k[14] = {
2113 0, 0x740, 0x069, 0x7DD, 0x208, 0x7B9, 0x5C7, 0x7FF, 0x53B, 0x029, 0x48E, 0x4C4, 0x367, 0x684
2114};
2115
2116static u16 dib8000_get_init_prbs(struct dib8000_state *state, u16 subchannel)
2117{
2118 int sub_channel_prbs_group = 0;
2119
2120 sub_channel_prbs_group = (subchannel / 3) + 1;
2121 dprintk("sub_channel_prbs_group = %d , subchannel =%d prbs = 0x%04x", sub_channel_prbs_group, subchannel, lut_prbs_8k[sub_channel_prbs_group]);
2122
2123 switch (state->fe[0]->dtv_property_cache.transmission_mode) {
2124 case TRANSMISSION_MODE_2K:
2125 return lut_prbs_2k[sub_channel_prbs_group];
2126 case TRANSMISSION_MODE_4K:
2127 return lut_prbs_4k[sub_channel_prbs_group];
2128 default:
2129 case TRANSMISSION_MODE_8K:
2130 return lut_prbs_8k[sub_channel_prbs_group];
2131 }
2132}
2133
2134static void dib8000_set_13seg_channel(struct dib8000_state *state)
2135{
2136 u16 i;
2137 u16 coff_pow = 0x2800;
2138
2139 state->seg_mask = 0x1fff; /* All 13 segments enabled */
2140
2141 /* ---- COFF ---- Carloff, the most robust --- */
2142 if (state->isdbt_cfg_loaded == 0) { /* if not Sound Broadcasting mode : put default values for 13 segments */
2143 dib8000_write_word(state, 180, (16 << 6) | 9);
2144 dib8000_write_word(state, 187, (4 << 12) | (8 << 5) | 0x2);
2145 coff_pow = 0x2800;
2146 for (i = 0; i < 6; i++)
2147 dib8000_write_word(state, 181+i, coff_pow);
2148
2149 /* P_ctrl_corm_thres4pre_freq_inh=1, P_ctrl_pre_freq_mode_sat=1 */
2150 /* 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 */
2151 dib8000_write_word(state, 338, (1 << 12) | (1 << 10) | (0 << 9) | (3 << 5) | 1);
2152
2153 /* P_ctrl_pre_freq_win_len=8, P_ctrl_pre_freq_thres_lockin=6 */
2154 dib8000_write_word(state, 340, (8 << 6) | (6 << 0));
2155 /* P_ctrl_pre_freq_thres_lockout=4, P_small_use_tmcc/ac/cp=1 */
2156 dib8000_write_word(state, 341, (4 << 3) | (1 << 2) | (1 << 1) | (1 << 0));
2157
2158 dib8000_write_word(state, 228, 0); /* default value */
2159 dib8000_write_word(state, 265, 31); /* default value */
2160 dib8000_write_word(state, 205, 0x200f); /* init value */
2161 }
2162
2163 /*
2164 * make the cpil_coff_lock more robust but slower p_coff_winlen
2165 * 6bits; p_coff_thres_lock 6bits (for coff lock if needed)
2166 */
2167
2168 if (state->cfg.pll->ifreq == 0)
2169 dib8000_write_word(state, 266, ~state->seg_mask | state->seg_diff_mask | 0x40); /* P_equal_noise_seg_inh */
2170
2171 dib8000_load_ana_fe_coefs(state, ana_fe_coeff_13seg);
2172}
2173
2174static void dib8000_set_subchannel_prbs(struct dib8000_state *state, u16 init_prbs)
2175{
2176 u16 reg_1;
2177
2178 reg_1 = dib8000_read_word(state, 1);
2179 dib8000_write_word(state, 1, (init_prbs << 2) | (reg_1 & 0x3)); /* ADDR 1 */
2180}
2181
2182static void dib8000_small_fine_tune(struct dib8000_state *state)
2183{
2184 u16 i;
2185 const s16 *ncoeff;
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03002186 struct dtv_frontend_properties *c = &state->fe[0]->dtv_property_cache;
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002187
2188 dib8000_write_word(state, 352, state->seg_diff_mask);
2189 dib8000_write_word(state, 353, state->seg_mask);
2190
2191 /* 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 -03002192 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 -03002193
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03002194 if (c->isdbt_sb_mode) {
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002195 /* ---- SMALL ---- */
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03002196 switch (c->transmission_mode) {
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002197 case TRANSMISSION_MODE_2K:
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03002198 if (c->isdbt_partial_reception == 0) { /* 1-seg */
2199 if (c->layer[0].modulation == DQPSK) /* DQPSK */
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002200 ncoeff = coeff_2k_sb_1seg_dqpsk;
2201 else /* QPSK or QAM */
2202 ncoeff = coeff_2k_sb_1seg;
2203 } else { /* 3-segments */
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03002204 if (c->layer[0].modulation == DQPSK) { /* DQPSK on central segment */
2205 if (c->layer[1].modulation == DQPSK) /* DQPSK on external segments */
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002206 ncoeff = coeff_2k_sb_3seg_0dqpsk_1dqpsk;
2207 else /* QPSK or QAM on external segments */
2208 ncoeff = coeff_2k_sb_3seg_0dqpsk;
2209 } else { /* QPSK or QAM on central segment */
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03002210 if (c->layer[1].modulation == DQPSK) /* DQPSK on external segments */
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002211 ncoeff = coeff_2k_sb_3seg_1dqpsk;
2212 else /* QPSK or QAM on external segments */
2213 ncoeff = coeff_2k_sb_3seg;
2214 }
2215 }
2216 break;
2217 case TRANSMISSION_MODE_4K:
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03002218 if (c->isdbt_partial_reception == 0) { /* 1-seg */
2219 if (c->layer[0].modulation == DQPSK) /* DQPSK */
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002220 ncoeff = coeff_4k_sb_1seg_dqpsk;
2221 else /* QPSK or QAM */
2222 ncoeff = coeff_4k_sb_1seg;
2223 } else { /* 3-segments */
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03002224 if (c->layer[0].modulation == DQPSK) { /* DQPSK on central segment */
2225 if (c->layer[1].modulation == DQPSK) /* DQPSK on external segments */
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002226 ncoeff = coeff_4k_sb_3seg_0dqpsk_1dqpsk;
2227 else /* QPSK or QAM on external segments */
2228 ncoeff = coeff_4k_sb_3seg_0dqpsk;
2229 } else { /* QPSK or QAM on central segment */
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03002230 if (c->layer[1].modulation == DQPSK) /* DQPSK on external segments */
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002231 ncoeff = coeff_4k_sb_3seg_1dqpsk;
2232 else /* QPSK or QAM on external segments */
2233 ncoeff = coeff_4k_sb_3seg;
2234 }
2235 }
2236 break;
2237 case TRANSMISSION_MODE_AUTO:
2238 case TRANSMISSION_MODE_8K:
2239 default:
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03002240 if (c->isdbt_partial_reception == 0) { /* 1-seg */
2241 if (c->layer[0].modulation == DQPSK) /* DQPSK */
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002242 ncoeff = coeff_8k_sb_1seg_dqpsk;
2243 else /* QPSK or QAM */
2244 ncoeff = coeff_8k_sb_1seg;
2245 } else { /* 3-segments */
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03002246 if (c->layer[0].modulation == DQPSK) { /* DQPSK on central segment */
2247 if (c->layer[1].modulation == DQPSK) /* DQPSK on external segments */
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002248 ncoeff = coeff_8k_sb_3seg_0dqpsk_1dqpsk;
2249 else /* QPSK or QAM on external segments */
2250 ncoeff = coeff_8k_sb_3seg_0dqpsk;
2251 } else { /* QPSK or QAM on central segment */
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03002252 if (c->layer[1].modulation == DQPSK) /* DQPSK on external segments */
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002253 ncoeff = coeff_8k_sb_3seg_1dqpsk;
2254 else /* QPSK or QAM on external segments */
2255 ncoeff = coeff_8k_sb_3seg;
2256 }
2257 }
2258 break;
2259 }
2260
2261 for (i = 0; i < 8; i++)
2262 dib8000_write_word(state, 343 + i, ncoeff[i]);
2263 }
2264}
2265
2266static const u16 coff_thres_1seg[3] = {300, 150, 80};
2267static const u16 coff_thres_3seg[3] = {350, 300, 250};
2268static void dib8000_set_sb_channel(struct dib8000_state *state)
2269{
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03002270 struct dtv_frontend_properties *c = &state->fe[0]->dtv_property_cache;
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002271 const u16 *coff;
2272 u16 i;
2273
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03002274 if (c->transmission_mode == TRANSMISSION_MODE_2K || c->transmission_mode == TRANSMISSION_MODE_4K) {
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002275 dib8000_write_word(state, 219, dib8000_read_word(state, 219) | 0x1); /* adp_pass =1 */
2276 dib8000_write_word(state, 190, dib8000_read_word(state, 190) | (0x1 << 14)); /* pha3_force_pha_shift = 1 */
2277 } else {
2278 dib8000_write_word(state, 219, dib8000_read_word(state, 219) & 0xfffe); /* adp_pass =0 */
2279 dib8000_write_word(state, 190, dib8000_read_word(state, 190) & 0xbfff); /* pha3_force_pha_shift = 0 */
2280 }
2281
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03002282 if (c->isdbt_partial_reception == 1) /* 3-segments */
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002283 state->seg_mask = 0x00E0;
2284 else /* 1-segment */
2285 state->seg_mask = 0x0040;
2286
2287 dib8000_write_word(state, 268, (dib8000_read_word(state, 268) & 0xF9FF) | 0x0200);
2288
2289 /* ---- COFF ---- Carloff, the most robust --- */
2290 /* 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 -03002291 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 -03002292
2293 dib8000_write_word(state, 340, (16 << 6) | (8 << 0)); /* P_ctrl_pre_freq_win_len=16, P_ctrl_pre_freq_thres_lockin=8 */
2294 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 */
2295
2296 /* Sound Broadcasting mode 1 seg */
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03002297 if (c->isdbt_partial_reception == 0) {
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002298 /* 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) */
2299 if (state->mode == 3)
2300 dib8000_write_word(state, 180, 0x1fcf | ((state->mode - 1) << 14));
2301 else
2302 dib8000_write_word(state, 180, 0x0fcf | ((state->mode - 1) << 14));
2303
2304 /* 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 */
2305 dib8000_write_word(state, 338, (1 << 12) | (1 << 10) | (0 << 9) | (5 << 5) | 4);
2306 coff = &coff_thres_1seg[0];
2307 } else { /* Sound Broadcasting mode 3 seg */
2308 dib8000_write_word(state, 180, 0x1fcf | (1 << 14));
2309 /* 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 */
2310 dib8000_write_word(state, 338, (1 << 12) | (1 << 10) | (0 << 9) | (4 << 5) | 4);
2311 coff = &coff_thres_3seg[0];
2312 }
2313
2314 dib8000_write_word(state, 228, 1); /* P_2d_mode_byp=1 */
2315 dib8000_write_word(state, 205, dib8000_read_word(state, 205) & 0xfff0); /* P_cspu_win_cut = 0 */
2316
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03002317 if (c->isdbt_partial_reception == 0 && c->transmission_mode == TRANSMISSION_MODE_2K)
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002318 dib8000_write_word(state, 265, 15); /* P_equal_noise_sel = 15 */
2319
2320 /* Write COFF thres */
2321 for (i = 0 ; i < 3; i++) {
2322 dib8000_write_word(state, 181+i, coff[i]);
2323 dib8000_write_word(state, 184+i, coff[i]);
2324 }
2325
2326 /*
2327 * make the cpil_coff_lock more robust but slower p_coff_winlen
2328 * 6bits; p_coff_thres_lock 6bits (for coff lock if needed)
2329 */
2330
2331 dib8000_write_word(state, 266, ~state->seg_mask | state->seg_diff_mask); /* P_equal_noise_seg_inh */
2332
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03002333 if (c->isdbt_partial_reception == 0)
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002334 dib8000_write_word(state, 178, 64); /* P_fft_powrange = 64 */
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002335 else
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002336 dib8000_write_word(state, 178, 32); /* P_fft_powrange = 32 */
2337}
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002338
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002339static void dib8000_set_isdbt_common_channel(struct dib8000_state *state, u8 seq, u8 autosearching)
2340{
2341 u16 p_cfr_left_edge = 0, p_cfr_right_edge = 0;
2342 u16 tmcc_pow = 0, ana_gain = 0, tmp = 0, i = 0, nbseg_diff = 0 ;
2343 u16 max_constellation = DQPSK;
2344 int init_prbs;
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03002345 struct dtv_frontend_properties *c = &state->fe[0]->dtv_property_cache;
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002346
Mauro Carvalho Chehabdde8e112014-07-04 14:15:32 -03002347 if (autosearching)
2348 c->isdbt_partial_reception = 1;
2349
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002350 /* P_mode */
2351 dib8000_write_word(state, 10, (seq << 4));
2352
2353 /* init mode */
2354 state->mode = fft_to_mode(state);
2355
2356 /* set guard */
2357 tmp = dib8000_read_word(state, 1);
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03002358 dib8000_write_word(state, 1, (tmp&0xfffc) | (c->guard_interval & 0x3));
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002359
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03002360 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 -03002361
2362 /* signal optimization parameter */
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03002363 if (c->isdbt_partial_reception) {
2364 state->seg_diff_mask = (c->layer[0].modulation == DQPSK) << permu_seg[0];
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002365 for (i = 1; i < 3; i++)
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03002366 nbseg_diff += (c->layer[i].modulation == DQPSK) * c->layer[i].segment_count;
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002367 for (i = 0; i < nbseg_diff; i++)
2368 state->seg_diff_mask |= 1 << permu_seg[i+1];
2369 } else {
2370 for (i = 0; i < 3; i++)
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03002371 nbseg_diff += (c->layer[i].modulation == DQPSK) * c->layer[i].segment_count;
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002372 for (i = 0; i < nbseg_diff; i++)
2373 state->seg_diff_mask |= 1 << permu_seg[i];
2374 }
2375
2376 if (state->seg_diff_mask)
2377 dib8000_write_word(state, 268, (dib8000_read_word(state, 268) & 0xF9FF) | 0x0200);
2378 else
2379 dib8000_write_word(state, 268, (2 << 9) | 39); /*init value */
2380
2381 for (i = 0; i < 3; i++)
2382 max_constellation = dib8000_set_layer(state, i, max_constellation);
2383 if (autosearching == 0) {
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03002384 state->layer_b_nb_seg = c->layer[1].segment_count;
2385 state->layer_c_nb_seg = c->layer[2].segment_count;
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002386 }
2387
2388 /* WRITE: Mode & Diff mask */
2389 dib8000_write_word(state, 0, (state->mode << 13) | state->seg_diff_mask);
2390
2391 state->differential_constellation = (state->seg_diff_mask != 0);
2392
2393 /* channel estimation fine configuration */
2394 ana_gain = dib8000_adp_fine_tune(state, max_constellation);
2395
2396 /* update ana_gain depending on max constellation */
2397 dib8000_update_ana_gain(state, ana_gain);
2398
2399 /* ---- ANA_FE ---- */
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03002400 if (c->isdbt_partial_reception) /* 3-segments */
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002401 dib8000_load_ana_fe_coefs(state, ana_fe_coeff_3seg);
2402 else
2403 dib8000_load_ana_fe_coefs(state, ana_fe_coeff_1seg); /* 1-segment */
2404
2405 /* TSB or ISDBT ? apply it now */
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03002406 if (c->isdbt_sb_mode) {
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002407 dib8000_set_sb_channel(state);
Mauro Carvalho Chehab746f7ae2013-04-25 11:15:54 -03002408 if (c->isdbt_sb_subchannel < 14)
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03002409 init_prbs = dib8000_get_init_prbs(state, c->isdbt_sb_subchannel);
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002410 else
2411 init_prbs = 0;
2412 } else {
2413 dib8000_set_13seg_channel(state);
2414 init_prbs = 0xfff;
2415 }
2416
2417 /* SMALL */
2418 dib8000_small_fine_tune(state);
2419
2420 dib8000_set_subchannel_prbs(state, init_prbs);
2421
2422 /* ---- CHAN_BLK ---- */
2423 for (i = 0; i < 13; i++) {
2424 if ((((~state->seg_diff_mask) >> i) & 1) == 1) {
2425 p_cfr_left_edge += (1 << i) * ((i == 0) || ((((state->seg_mask & (~state->seg_diff_mask)) >> (i - 1)) & 1) == 0));
2426 p_cfr_right_edge += (1 << i) * ((i == 12) || ((((state->seg_mask & (~state->seg_diff_mask)) >> (i + 1)) & 1) == 0));
2427 }
2428 }
2429 dib8000_write_word(state, 222, p_cfr_left_edge); /* p_cfr_left_edge */
2430 dib8000_write_word(state, 223, p_cfr_right_edge); /* p_cfr_right_edge */
2431 /* "P_cspu_left_edge" & "P_cspu_right_edge" not used => do not care */
2432
2433 dib8000_write_word(state, 189, ~state->seg_mask | state->seg_diff_mask); /* P_lmod4_seg_inh */
2434 dib8000_write_word(state, 192, ~state->seg_mask | state->seg_diff_mask); /* P_pha3_seg_inh */
2435 dib8000_write_word(state, 225, ~state->seg_mask | state->seg_diff_mask); /* P_tac_seg_inh */
2436
2437 if (!autosearching)
2438 dib8000_write_word(state, 288, (~state->seg_mask | state->seg_diff_mask) & 0x1fff); /* P_tmcc_seg_eq_inh */
2439 else
2440 dib8000_write_word(state, 288, 0x1fff); /*disable equalisation of the tmcc when autosearch to be able to find the DQPSK channels. */
2441
2442 dib8000_write_word(state, 211, state->seg_mask & (~state->seg_diff_mask)); /* P_des_seg_enabled */
2443 dib8000_write_word(state, 287, ~state->seg_mask | 0x1000); /* P_tmcc_seg_inh */
2444
2445 dib8000_write_word(state, 178, 32); /* P_fft_powrange = 32 */
2446
2447 /* ---- TMCC ---- */
2448 for (i = 0; i < 3; i++)
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03002449 tmcc_pow += (((c->layer[i].modulation == DQPSK) * 4 + 1) * c->layer[i].segment_count) ;
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002450
2451 /* Quantif of "P_tmcc_dec_thres_?k" is (0, 5+mode, 9); */
2452 /* Threshold is set at 1/4 of max power. */
2453 tmcc_pow *= (1 << (9-2));
2454 dib8000_write_word(state, 290, tmcc_pow); /* P_tmcc_dec_thres_2k */
2455 dib8000_write_word(state, 291, tmcc_pow); /* P_tmcc_dec_thres_4k */
2456 dib8000_write_word(state, 292, tmcc_pow); /* P_tmcc_dec_thres_8k */
2457 /*dib8000_write_word(state, 287, (1 << 13) | 0x1000 ); */
2458
2459 /* ---- PHA3 ---- */
2460 if (state->isdbt_cfg_loaded == 0)
2461 dib8000_write_word(state, 250, 3285); /* p_2d_hspeed_thr0 */
2462
2463 state->isdbt_cfg_loaded = 0;
2464}
2465
Mauro Carvalho Chehab6f7ee062013-04-25 10:36:56 -03002466static u32 dib8000_wait_lock(struct dib8000_state *state, u32 internal,
2467 u32 wait0_ms, u32 wait1_ms, u32 wait2_ms)
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002468{
Mauro Carvalho Chehab13122f92013-04-25 15:22:20 -03002469 u32 value = 0; /* P_search_end0 wait time */
2470 u16 reg = 11; /* P_search_end0 start addr */
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002471
2472 for (reg = 11; reg < 16; reg += 2) {
2473 if (reg == 11) {
2474 if (state->revision == 0x8090)
Mauro Carvalho Chehab13122f92013-04-25 15:22:20 -03002475 value = internal * wait1_ms;
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002476 else
Mauro Carvalho Chehab13122f92013-04-25 15:22:20 -03002477 value = internal * wait0_ms;
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002478 } else if (reg == 13)
Mauro Carvalho Chehab13122f92013-04-25 15:22:20 -03002479 value = internal * wait1_ms;
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002480 else if (reg == 15)
Mauro Carvalho Chehab13122f92013-04-25 15:22:20 -03002481 value = internal * wait2_ms;
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002482 dib8000_write_word(state, reg, (u16)((value >> 16) & 0xffff));
2483 dib8000_write_word(state, (reg + 1), (u16)(value & 0xffff));
2484 }
2485 return value;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002486}
2487
2488static int dib8000_autosearch_start(struct dvb_frontend *fe)
2489{
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002490 struct dib8000_state *state = fe->demodulator_priv;
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03002491 struct dtv_frontend_properties *c = &state->fe[0]->dtv_property_cache;
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002492 u8 slist = 0;
2493 u32 value, internal = state->cfg.pll->internal;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002494
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002495 if (state->revision == 0x8090)
2496 internal = dib8000_read32(state, 23) / 1000;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002497
Olivier Grenied67350f2013-12-12 09:26:22 -03002498 if ((state->revision >= 0x8002) &&
2499 (state->autosearch_state == AS_SEARCHING_FFT)) {
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002500 dib8000_write_word(state, 37, 0x0065); /* P_ctrl_pha_off_max default values */
2501 dib8000_write_word(state, 116, 0x0000); /* P_ana_gain to 0 */
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002502
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002503 dib8000_write_word(state, 0, (dib8000_read_word(state, 0) & 0x1fff) | (0 << 13) | (1 << 15)); /* P_mode = 0, P_restart_search=1 */
2504 dib8000_write_word(state, 1, (dib8000_read_word(state, 1) & 0xfffc) | 0); /* P_guard = 0 */
2505 dib8000_write_word(state, 6, 0); /* P_lock0_mask = 0 */
2506 dib8000_write_word(state, 7, 0); /* P_lock1_mask = 0 */
2507 dib8000_write_word(state, 8, 0); /* P_lock2_mask = 0 */
2508 dib8000_write_word(state, 10, (dib8000_read_word(state, 10) & 0x200) | (16 << 4) | (0 << 0)); /* P_search_list=16, P_search_maxtrial=0 */
2509
2510 if (state->revision == 0x8090)
2511 value = dib8000_wait_lock(state, internal, 10, 10, 10); /* time in ms configure P_search_end0 P_search_end1 P_search_end2 */
2512 else
2513 value = dib8000_wait_lock(state, internal, 20, 20, 20); /* time in ms configure P_search_end0 P_search_end1 P_search_end2 */
2514
2515 dib8000_write_word(state, 17, 0);
2516 dib8000_write_word(state, 18, 200); /* P_search_rstst = 200 */
2517 dib8000_write_word(state, 19, 0);
2518 dib8000_write_word(state, 20, 400); /* P_search_rstend = 400 */
2519 dib8000_write_word(state, 21, (value >> 16) & 0xffff); /* P_search_checkst */
2520 dib8000_write_word(state, 22, value & 0xffff);
2521
2522 if (state->revision == 0x8090)
2523 dib8000_write_word(state, 32, (dib8000_read_word(state, 32) & 0xf0ff) | (0 << 8)); /* P_corm_alpha = 0 */
2524 else
2525 dib8000_write_word(state, 32, (dib8000_read_word(state, 32) & 0xf0ff) | (9 << 8)); /* P_corm_alpha = 3 */
2526 dib8000_write_word(state, 355, 2); /* P_search_param_max = 2 */
2527
2528 /* P_search_param_select = (1 | 1<<4 | 1 << 8) */
2529 dib8000_write_word(state, 356, 0);
2530 dib8000_write_word(state, 357, 0x111);
2531
2532 dib8000_write_word(state, 770, (dib8000_read_word(state, 770) & 0xdfff) | (1 << 13)); /* P_restart_ccg = 1 */
2533 dib8000_write_word(state, 770, (dib8000_read_word(state, 770) & 0xdfff) | (0 << 13)); /* P_restart_ccg = 0 */
2534 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 -03002535 } else if ((state->revision >= 0x8002) &&
2536 (state->autosearch_state == AS_SEARCHING_GUARD)) {
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03002537 c->transmission_mode = TRANSMISSION_MODE_8K;
2538 c->guard_interval = GUARD_INTERVAL_1_8;
2539 c->inversion = 0;
2540 c->layer[0].modulation = QAM_64;
2541 c->layer[0].fec = FEC_2_3;
2542 c->layer[0].interleaving = 0;
2543 c->layer[0].segment_count = 13;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002544
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002545 slist = 16;
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03002546 c->transmission_mode = state->found_nfft;
Patrick Boettcher78f3bc62009-08-17 12:53:51 -03002547
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002548 dib8000_set_isdbt_common_channel(state, slist, 1);
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002549
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002550 /* set lock_mask values */
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002551 dib8000_write_word(state, 6, 0x4);
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002552 if (state->revision == 0x8090)
2553 dib8000_write_word(state, 7, ((1 << 12) | (1 << 11) | (1 << 10)));/* tmcc_dec_lock, tmcc_sync_lock, tmcc_data_lock, tmcc_bch_uncor */
2554 else
2555 dib8000_write_word(state, 7, 0x8);
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002556 dib8000_write_word(state, 8, 0x1000);
2557
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002558 /* set lock_mask wait time values */
2559 if (state->revision == 0x8090)
2560 dib8000_wait_lock(state, internal, 50, 100, 1000); /* time in ms configure P_search_end0 P_search_end1 P_search_end2 */
2561 else
2562 dib8000_wait_lock(state, internal, 50, 200, 1000); /* time in ms configure P_search_end0 P_search_end1 P_search_end2 */
2563
2564 dib8000_write_word(state, 355, 3); /* P_search_param_max = 3 */
2565
2566 /* P_search_param_select = 0xf; look for the 4 different guard intervals */
2567 dib8000_write_word(state, 356, 0);
2568 dib8000_write_word(state, 357, 0xf);
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002569
2570 value = dib8000_read_word(state, 0);
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002571 dib8000_write_word(state, 0, (u16)((1 << 15) | value));
2572 dib8000_read_word(state, 1284); /* reset the INT. n_irq_pending */
2573 dib8000_write_word(state, 0, (u16)value);
2574 } else {
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03002575 c->inversion = 0;
2576 c->layer[0].modulation = QAM_64;
2577 c->layer[0].fec = FEC_2_3;
2578 c->layer[0].interleaving = 0;
2579 c->layer[0].segment_count = 13;
2580 if (!c->isdbt_sb_mode)
2581 c->layer[0].segment_count = 13;
Patrick Boettcher78f3bc62009-08-17 12:53:51 -03002582
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002583 /* choose the right list, in sb, always do everything */
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03002584 if (c->isdbt_sb_mode) {
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002585 slist = 7;
2586 dib8000_write_word(state, 0, (dib8000_read_word(state, 0) & 0x9fff) | (1 << 13));
2587 } else {
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03002588 if (c->guard_interval == GUARD_INTERVAL_AUTO) {
2589 if (c->transmission_mode == TRANSMISSION_MODE_AUTO) {
2590 c->transmission_mode = TRANSMISSION_MODE_8K;
2591 c->guard_interval = GUARD_INTERVAL_1_8;
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002592 slist = 7;
2593 dib8000_write_word(state, 0, (dib8000_read_word(state, 0) & 0x9fff) | (1 << 13)); /* P_mode = 1 to have autosearch start ok with mode2 */
2594 } else {
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03002595 c->guard_interval = GUARD_INTERVAL_1_8;
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002596 slist = 3;
2597 }
2598 } else {
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03002599 if (c->transmission_mode == TRANSMISSION_MODE_AUTO) {
2600 c->transmission_mode = TRANSMISSION_MODE_8K;
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002601 slist = 2;
2602 dib8000_write_word(state, 0, (dib8000_read_word(state, 0) & 0x9fff) | (1 << 13)); /* P_mode = 1 */
2603 } else
2604 slist = 0;
2605 }
2606 }
2607 dprintk("Using list for autosearch : %d", slist);
2608
2609 dib8000_set_isdbt_common_channel(state, slist, 1);
2610
2611 /* set lock_mask values */
2612 dib8000_write_word(state, 6, 0x4);
2613 if (state->revision == 0x8090)
2614 dib8000_write_word(state, 7, (1 << 12) | (1 << 11) | (1 << 10));
2615 else
2616 dib8000_write_word(state, 7, 0x8);
2617 dib8000_write_word(state, 8, 0x1000);
2618
2619 /* set lock_mask wait time values */
2620 if (state->revision == 0x8090)
2621 dib8000_wait_lock(state, internal, 50, 200, 1000); /* time in ms configure P_search_end0 P_search_end1 P_search_end2 */
2622 else
2623 dib8000_wait_lock(state, internal, 50, 100, 1000); /* time in ms configure P_search_end0 P_search_end1 P_search_end2 */
2624
2625 value = dib8000_read_word(state, 0);
2626 dib8000_write_word(state, 0, (u16)((1 << 15) | value));
2627 dib8000_read_word(state, 1284); /* reset the INT. n_irq_pending */
2628 dib8000_write_word(state, 0, (u16)value);
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002629 }
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002630 return 0;
2631}
2632
2633static int dib8000_autosearch_irq(struct dvb_frontend *fe)
2634{
2635 struct dib8000_state *state = fe->demodulator_priv;
2636 u16 irq_pending = dib8000_read_word(state, 1284);
2637
Olivier Grenied67350f2013-12-12 09:26:22 -03002638 if ((state->revision >= 0x8002) &&
2639 (state->autosearch_state == AS_SEARCHING_FFT)) {
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002640 if (irq_pending & 0x1) {
2641 dprintk("dib8000_autosearch_irq: max correlation result available");
2642 return 3;
2643 }
2644 } else {
2645 if (irq_pending & 0x1) { /* failed */
2646 dprintk("dib8000_autosearch_irq failed");
2647 return 1;
2648 }
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002649
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002650 if (irq_pending & 0x2) { /* succeeded */
2651 dprintk("dib8000_autosearch_irq succeeded");
2652 return 2;
2653 }
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002654 }
2655
2656 return 0; // still pending
2657}
2658
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002659static void dib8000_viterbi_state(struct dib8000_state *state, u8 onoff)
2660{
2661 u16 tmp;
2662
2663 tmp = dib8000_read_word(state, 771);
2664 if (onoff) /* start P_restart_chd : channel_decoder */
2665 dib8000_write_word(state, 771, tmp & 0xfffd);
2666 else /* stop P_restart_chd : channel_decoder */
2667 dib8000_write_word(state, 771, tmp | (1<<1));
2668}
2669
2670static void dib8000_set_dds(struct dib8000_state *state, s32 offset_khz)
2671{
2672 s16 unit_khz_dds_val;
2673 u32 abs_offset_khz = ABS(offset_khz);
2674 u32 dds = state->cfg.pll->ifreq & 0x1ffffff;
2675 u8 invert = !!(state->cfg.pll->ifreq & (1 << 25));
2676 u8 ratio;
2677
2678 if (state->revision == 0x8090) {
2679 ratio = 4;
2680 unit_khz_dds_val = (1<<26) / (dib8000_read32(state, 23) / 1000);
2681 if (offset_khz < 0)
2682 dds = (1 << 26) - (abs_offset_khz * unit_khz_dds_val);
2683 else
2684 dds = (abs_offset_khz * unit_khz_dds_val);
2685
2686 if (invert)
2687 dds = (1<<26) - dds;
2688 } else {
2689 ratio = 2;
2690 unit_khz_dds_val = (u16) (67108864 / state->cfg.pll->internal);
2691
2692 if (offset_khz < 0)
2693 unit_khz_dds_val *= -1;
2694
2695 /* IF tuner */
2696 if (invert)
2697 dds -= abs_offset_khz * unit_khz_dds_val;
2698 else
2699 dds += abs_offset_khz * unit_khz_dds_val;
2700 }
2701
2702 dprintk("setting a DDS frequency offset of %c%dkHz", invert ? '-' : ' ', dds / unit_khz_dds_val);
2703
2704 if (abs_offset_khz <= (state->cfg.pll->internal / ratio)) {
2705 /* Max dds offset is the half of the demod freq */
2706 dib8000_write_word(state, 26, invert);
2707 dib8000_write_word(state, 27, (u16)(dds >> 16) & 0x1ff);
2708 dib8000_write_word(state, 28, (u16)(dds & 0xffff));
2709 }
2710}
2711
2712static void dib8000_set_frequency_offset(struct dib8000_state *state)
2713{
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03002714 struct dtv_frontend_properties *c = &state->fe[0]->dtv_property_cache;
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002715 int i;
2716 u32 current_rf;
2717 int total_dds_offset_khz;
2718
2719 if (state->fe[0]->ops.tuner_ops.get_frequency)
2720 state->fe[0]->ops.tuner_ops.get_frequency(state->fe[0], &current_rf);
2721 else
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03002722 current_rf = c->frequency;
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002723 current_rf /= 1000;
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03002724 total_dds_offset_khz = (int)current_rf - (int)c->frequency / 1000;
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002725
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03002726 if (c->isdbt_sb_mode) {
2727 state->subchannel = c->isdbt_sb_subchannel;
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002728
2729 i = dib8000_read_word(state, 26) & 1; /* P_dds_invspec */
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03002730 dib8000_write_word(state, 26, c->inversion ^ i);
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002731
2732 if (state->cfg.pll->ifreq == 0) { /* low if tuner */
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03002733 if ((c->inversion ^ i) == 0)
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002734 dib8000_write_word(state, 26, dib8000_read_word(state, 26) | 1);
2735 } else {
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03002736 if ((c->inversion ^ i) == 0)
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002737 total_dds_offset_khz *= -1;
2738 }
2739 }
2740
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03002741 dprintk("%dkhz tuner offset (frequency = %dHz & current_rf = %dHz) total_dds_offset_hz = %d", c->frequency - current_rf, c->frequency, current_rf, total_dds_offset_khz);
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002742
2743 /* apply dds offset now */
2744 dib8000_set_dds(state, total_dds_offset_khz);
2745}
2746
2747static u16 LUT_isdbt_symbol_duration[4] = { 26, 101, 63 };
Mauro Carvalho Chehab6f7ee062013-04-25 10:36:56 -03002748
2749static u32 dib8000_get_symbol_duration(struct dib8000_state *state)
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002750{
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03002751 struct dtv_frontend_properties *c = &state->fe[0]->dtv_property_cache;
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002752 u16 i;
2753
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03002754 switch (c->transmission_mode) {
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002755 case TRANSMISSION_MODE_2K:
2756 i = 0;
2757 break;
2758 case TRANSMISSION_MODE_4K:
2759 i = 2;
2760 break;
2761 default:
2762 case TRANSMISSION_MODE_AUTO:
2763 case TRANSMISSION_MODE_8K:
2764 i = 1;
2765 break;
2766 }
2767
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03002768 return (LUT_isdbt_symbol_duration[i] / (c->bandwidth_hz / 1000)) + 1;
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002769}
2770
2771static void dib8000_set_isdbt_loop_params(struct dib8000_state *state, enum param_loop_step loop_step)
2772{
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03002773 struct dtv_frontend_properties *c = &state->fe[0]->dtv_property_cache;
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002774 u16 reg_32 = 0, reg_37 = 0;
2775
2776 switch (loop_step) {
2777 case LOOP_TUNE_1:
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03002778 if (c->isdbt_sb_mode) {
2779 if (c->isdbt_partial_reception == 0) {
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002780 reg_32 = ((11 - state->mode) << 12) | (6 << 8) | 0x40; /* P_timf_alpha = (11-P_mode), P_corm_alpha=6, P_corm_thres=0x40 */
2781 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) */
2782 } else { /* Sound Broadcasting mode 3 seg */
2783 reg_32 = ((10 - state->mode) << 12) | (6 << 8) | 0x60; /* P_timf_alpha = (10-P_mode), P_corm_alpha=6, P_corm_thres=0x60 */
2784 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) */
2785 }
2786 } else { /* 13-seg start conf offset loop parameters */
2787 reg_32 = ((9 - state->mode) << 12) | (6 << 8) | 0x80; /* P_timf_alpha = (9-P_mode, P_corm_alpha=6, P_corm_thres=0x80 */
2788 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 */
2789 }
2790 break;
2791 case LOOP_TUNE_2:
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03002792 if (c->isdbt_sb_mode) {
2793 if (c->isdbt_partial_reception == 0) { /* Sound Broadcasting mode 1 seg */
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002794 reg_32 = ((13-state->mode) << 12) | (6 << 8) | 0x40; /* P_timf_alpha = (13-P_mode) , P_corm_alpha=6, P_corm_thres=0x40*/
2795 reg_37 = (12-state->mode) | ((5 + state->mode) << 5);
2796 } else { /* Sound Broadcasting mode 3 seg */
2797 reg_32 = ((12-state->mode) << 12) | (6 << 8) | 0x60; /* P_timf_alpha = (12-P_mode) , P_corm_alpha=6, P_corm_thres=0x60 */
2798 reg_37 = (11-state->mode) | ((5 + state->mode) << 5);
2799 }
2800 } else { /* 13 seg */
2801 reg_32 = ((11-state->mode) << 12) | (6 << 8) | 0x80; /* P_timf_alpha = 8 , P_corm_alpha=6, P_corm_thres=0x80 */
2802 reg_37 = ((5+state->mode) << 5) | (10 - state->mode);
2803 }
2804 break;
2805 }
2806 dib8000_write_word(state, 32, reg_32);
2807 dib8000_write_word(state, 37, reg_37);
2808}
2809
2810static void dib8000_demod_restart(struct dib8000_state *state)
2811{
2812 dib8000_write_word(state, 770, 0x4000);
2813 dib8000_write_word(state, 770, 0x0000);
2814 return;
2815}
2816
2817static void dib8000_set_sync_wait(struct dib8000_state *state)
2818{
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03002819 struct dtv_frontend_properties *c = &state->fe[0]->dtv_property_cache;
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002820 u16 sync_wait = 64;
2821
2822 /* P_dvsy_sync_wait - reuse mode */
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03002823 switch (c->transmission_mode) {
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002824 case TRANSMISSION_MODE_8K:
2825 sync_wait = 256;
2826 break;
2827 case TRANSMISSION_MODE_4K:
2828 sync_wait = 128;
2829 break;
2830 default:
2831 case TRANSMISSION_MODE_2K:
2832 sync_wait = 64;
2833 break;
2834 }
2835
2836 if (state->cfg.diversity_delay == 0)
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03002837 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 -03002838 else
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03002839 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 -03002840
2841 dib8000_write_word(state, 273, (dib8000_read_word(state, 273) & 0x000f) | (sync_wait << 4));
2842}
2843
Mauro Carvalho Chehabd6c62b72014-07-04 14:15:37 -03002844static unsigned long dib8000_get_timeout(struct dib8000_state *state, u32 delay, enum timeout_mode mode)
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002845{
2846 if (mode == SYMBOL_DEPENDENT_ON)
Mauro Carvalho Chehabd6c62b72014-07-04 14:15:37 -03002847 delay *= state->symbol_duration;
2848
2849 return jiffies + usecs_to_jiffies(delay * 100);
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002850}
2851
2852static s32 dib8000_get_status(struct dvb_frontend *fe)
2853{
2854 struct dib8000_state *state = fe->demodulator_priv;
2855 return state->status;
2856}
2857
Mauro Carvalho Chehabd44913c2014-05-29 09:20:17 -03002858static enum frontend_tune_state dib8000_get_tune_state(struct dvb_frontend *fe)
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002859{
2860 struct dib8000_state *state = fe->demodulator_priv;
2861 return state->tune_state;
2862}
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002863
Mauro Carvalho Chehabd44913c2014-05-29 09:20:17 -03002864static int dib8000_set_tune_state(struct dvb_frontend *fe, enum frontend_tune_state tune_state)
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002865{
2866 struct dib8000_state *state = fe->demodulator_priv;
2867
2868 state->tune_state = tune_state;
2869 return 0;
2870}
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002871
2872static int dib8000_tune_restart_from_demod(struct dvb_frontend *fe)
2873{
2874 struct dib8000_state *state = fe->demodulator_priv;
2875
2876 state->status = FE_STATUS_TUNE_PENDING;
2877 state->tune_state = CT_DEMOD_START;
2878 return 0;
2879}
2880
2881static u16 dib8000_read_lock(struct dvb_frontend *fe)
2882{
2883 struct dib8000_state *state = fe->demodulator_priv;
2884
2885 if (state->revision == 0x8090)
2886 return dib8000_read_word(state, 570);
2887 return dib8000_read_word(state, 568);
2888}
2889
2890static int dib8090p_init_sdram(struct dib8000_state *state)
2891{
2892 u16 reg = 0;
2893 dprintk("init sdram");
2894
2895 reg = dib8000_read_word(state, 274) & 0xfff0;
2896 dib8000_write_word(state, 274, reg | 0x7); /* P_dintlv_delay_ram = 7 because of MobileSdram */
2897
2898 dib8000_write_word(state, 1803, (7 << 2));
2899
2900 reg = dib8000_read_word(state, 1280);
2901 dib8000_write_word(state, 1280, reg | (1 << 2)); /* force restart P_restart_sdram */
2902 dib8000_write_word(state, 1280, reg); /* release restart P_restart_sdram */
2903
2904 return 0;
2905}
2906
Mauro Carvalho Chehabad976182013-12-15 09:57:40 -03002907/**
2908 * is_manual_mode - Check if TMCC should be used for parameters settings
2909 * @c: struct dvb_frontend_properties
2910 *
2911 * By default, TMCC table should be used for parameter settings on most
2912 * usercases. However, sometimes it is desirable to lock the demod to
2913 * use the manual parameters.
2914 *
2915 * On manual mode, the current dib8000_tune state machine is very restrict:
2916 * It requires that both per-layer and per-transponder parameters to be
2917 * properly specified, otherwise the device won't lock.
2918 *
2919 * Check if all those conditions are properly satisfied before allowing
2920 * the device to use the manual frequency lock mode.
2921 */
2922static int is_manual_mode(struct dtv_frontend_properties *c)
2923{
2924 int i, n_segs = 0;
2925
2926 /* Use auto mode on DVB-T compat mode */
2927 if (c->delivery_system != SYS_ISDBT)
2928 return 0;
2929
2930 /*
2931 * Transmission mode is only detected on auto mode, currently
2932 */
2933 if (c->transmission_mode == TRANSMISSION_MODE_AUTO) {
2934 dprintk("transmission mode auto");
2935 return 0;
2936 }
2937
2938 /*
2939 * Guard interval is only detected on auto mode, currently
2940 */
2941 if (c->guard_interval == GUARD_INTERVAL_AUTO) {
2942 dprintk("guard interval auto");
2943 return 0;
2944 }
2945
2946 /*
2947 * If no layer is enabled, assume auto mode, as at least one
2948 * layer should be enabled
2949 */
2950 if (!c->isdbt_layer_enabled) {
2951 dprintk("no layer modulation specified");
2952 return 0;
2953 }
2954
2955 /*
2956 * Check if the per-layer parameters aren't auto and
2957 * disable a layer if segment count is 0 or invalid.
2958 */
2959 for (i = 0; i < 3; i++) {
2960 if (!(c->isdbt_layer_enabled & 1 << i))
2961 continue;
2962
2963 if ((c->layer[i].segment_count > 13) ||
2964 (c->layer[i].segment_count == 0)) {
2965 c->isdbt_layer_enabled &= ~(1 << i);
2966 continue;
2967 }
2968
2969 n_segs += c->layer[i].segment_count;
2970
2971 if ((c->layer[i].modulation == QAM_AUTO) ||
2972 (c->layer[i].fec == FEC_AUTO)) {
2973 dprintk("layer %c has either modulation or FEC auto",
2974 'A' + i);
2975 return 0;
2976 }
2977 }
2978
2979 /*
2980 * Userspace specified a wrong number of segments.
2981 * fallback to auto mode.
2982 */
2983 if (n_segs == 0 || n_segs > 13) {
2984 dprintk("number of segments is invalid");
2985 return 0;
2986 }
2987
2988 /* Everything looks ok for manual mode */
2989 return 1;
2990}
2991
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002992static int dib8000_tune(struct dvb_frontend *fe)
2993{
2994 struct dib8000_state *state = fe->demodulator_priv;
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03002995 struct dtv_frontend_properties *c = &state->fe[0]->dtv_property_cache;
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002996 enum frontend_tune_state *tune_state = &state->tune_state;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002997
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002998 u16 locks, deeper_interleaver = 0, i;
2999 int ret = 1; /* 1 symbol duration (in 100us unit) delay most of the time */
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003000
Mauro Carvalho Chehabd6c62b72014-07-04 14:15:37 -03003001 unsigned long *timeout = &state->timeout;
3002 unsigned long now = jiffies;
Patrick Boettcher173a64c2013-04-22 12:45:52 -03003003#ifdef DIB8000_AGC_FREEZE
3004 u16 agc1, agc2;
3005#endif
Dan Carpentere04f4b22012-07-20 07:11:57 -03003006
Patrick Boettcher173a64c2013-04-22 12:45:52 -03003007 u32 corm[4] = {0, 0, 0, 0};
3008 u8 find_index, max_value;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003009
Patrick Boettcher173a64c2013-04-22 12:45:52 -03003010#if 0
3011 if (*tune_state < CT_DEMOD_STOP)
Mauro Carvalho Chehabd6c62b72014-07-04 14:15:37 -03003012 dprintk("IN: context status = %d, TUNE_STATE %d autosearch step = %u jiffies = %lu",
3013 state->channel_parameters_set, *tune_state, state->autosearch_state, now);
Patrick Boettcher173a64c2013-04-22 12:45:52 -03003014#endif
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003015
Patrick Boettcher173a64c2013-04-22 12:45:52 -03003016 switch (*tune_state) {
3017 case CT_DEMOD_START: /* 30 */
Mauro Carvalho Chehab7fa676c2014-07-04 14:15:29 -03003018 dib8000_reset_stats(fe);
Mauro Carvalho Chehab6ef06e72013-12-16 19:10:59 -03003019
Mauro Carvalho Chehab7fa676c2014-07-04 14:15:29 -03003020 if (state->revision == 0x8090)
3021 dib8090p_init_sdram(state);
3022 state->status = FE_STATUS_TUNE_PENDING;
3023 state->channel_parameters_set = is_manual_mode(c);
Mauro Carvalho Chehabad976182013-12-15 09:57:40 -03003024
Mauro Carvalho Chehab7fa676c2014-07-04 14:15:29 -03003025 dprintk("Tuning channel on %s search mode",
3026 state->channel_parameters_set ? "manual" : "auto");
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003027
Mauro Carvalho Chehab7fa676c2014-07-04 14:15:29 -03003028 dib8000_viterbi_state(state, 0); /* force chan dec in restart */
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003029
Mauro Carvalho Chehab7fa676c2014-07-04 14:15:29 -03003030 /* Layer monitor */
3031 dib8000_write_word(state, 285, dib8000_read_word(state, 285) & 0x60);
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003032
Mauro Carvalho Chehab7fa676c2014-07-04 14:15:29 -03003033 dib8000_set_frequency_offset(state);
3034 dib8000_set_bandwidth(fe, c->bandwidth_hz / 1000);
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003035
Mauro Carvalho Chehab7fa676c2014-07-04 14:15:29 -03003036 if (state->channel_parameters_set == 0) { /* The channel struct is unknown, search it ! */
Patrick Boettcher173a64c2013-04-22 12:45:52 -03003037#ifdef DIB8000_AGC_FREEZE
Mauro Carvalho Chehab7fa676c2014-07-04 14:15:29 -03003038 if (state->revision != 0x8090) {
3039 state->agc1_max = dib8000_read_word(state, 108);
3040 state->agc1_min = dib8000_read_word(state, 109);
3041 state->agc2_max = dib8000_read_word(state, 110);
3042 state->agc2_min = dib8000_read_word(state, 111);
3043 agc1 = dib8000_read_word(state, 388);
3044 agc2 = dib8000_read_word(state, 389);
3045 dib8000_write_word(state, 108, agc1);
3046 dib8000_write_word(state, 109, agc1);
3047 dib8000_write_word(state, 110, agc2);
3048 dib8000_write_word(state, 111, agc2);
Patrick Boettcher173a64c2013-04-22 12:45:52 -03003049 }
Mauro Carvalho Chehab7fa676c2014-07-04 14:15:29 -03003050#endif
3051 state->autosearch_state = AS_SEARCHING_FFT;
3052 state->found_nfft = TRANSMISSION_MODE_AUTO;
3053 state->found_guard = GUARD_INTERVAL_AUTO;
3054 *tune_state = CT_DEMOD_SEARCH_NEXT;
3055 } else { /* we already know the channel struct so TUNE only ! */
3056 state->autosearch_state = AS_DONE;
3057 *tune_state = CT_DEMOD_STEP_3;
3058 }
3059 state->symbol_duration = dib8000_get_symbol_duration(state);
3060 break;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003061
Patrick Boettcher173a64c2013-04-22 12:45:52 -03003062 case CT_DEMOD_SEARCH_NEXT: /* 51 */
Mauro Carvalho Chehab7fa676c2014-07-04 14:15:29 -03003063 dib8000_autosearch_start(fe);
3064 if (state->revision == 0x8090)
3065 ret = 50;
3066 else
3067 ret = 15;
3068 *tune_state = CT_DEMOD_STEP_1;
3069 break;
3070
3071 case CT_DEMOD_STEP_1: /* 31 */
3072 switch (dib8000_autosearch_irq(fe)) {
3073 case 1: /* fail */
3074 state->status = FE_STATUS_TUNE_FAILED;
3075 state->autosearch_state = AS_DONE;
3076 *tune_state = CT_DEMOD_STOP; /* else we are done here */
3077 break;
3078 case 2: /* Succes */
3079 state->status = FE_STATUS_FFT_SUCCESS; /* signal to the upper layer, that there was a channel found and the parameters can be read */
3080 *tune_state = CT_DEMOD_STEP_3;
3081 if (state->autosearch_state == AS_SEARCHING_GUARD)
3082 *tune_state = CT_DEMOD_STEP_2;
3083 else
3084 state->autosearch_state = AS_DONE;
3085 break;
3086 case 3: /* Autosearch FFT max correlation endded */
3087 *tune_state = CT_DEMOD_STEP_2;
3088 break;
3089 }
3090 break;
3091
3092 case CT_DEMOD_STEP_2:
3093 switch (state->autosearch_state) {
3094 case AS_SEARCHING_FFT:
3095 /* searching for the correct FFT */
3096 if (state->revision == 0x8090) {
3097 corm[2] = (dib8000_read_word(state, 596) << 16) | (dib8000_read_word(state, 597));
3098 corm[1] = (dib8000_read_word(state, 598) << 16) | (dib8000_read_word(state, 599));
3099 corm[0] = (dib8000_read_word(state, 600) << 16) | (dib8000_read_word(state, 601));
3100 } else {
3101 corm[2] = (dib8000_read_word(state, 594) << 16) | (dib8000_read_word(state, 595));
3102 corm[1] = (dib8000_read_word(state, 596) << 16) | (dib8000_read_word(state, 597));
3103 corm[0] = (dib8000_read_word(state, 598) << 16) | (dib8000_read_word(state, 599));
3104 }
3105 /* dprintk("corm fft: %u %u %u", corm[0], corm[1], corm[2]); */
3106
3107 max_value = 0;
3108 for (find_index = 1 ; find_index < 3 ; find_index++) {
3109 if (corm[max_value] < corm[find_index])
3110 max_value = find_index ;
3111 }
3112
3113 switch (max_value) {
3114 case 0:
3115 state->found_nfft = TRANSMISSION_MODE_2K;
3116 break;
3117 case 1:
3118 state->found_nfft = TRANSMISSION_MODE_4K;
3119 break;
3120 case 2:
3121 default:
3122 state->found_nfft = TRANSMISSION_MODE_8K;
3123 break;
3124 }
3125 /* dprintk("Autosearch FFT has found Mode %d", max_value + 1); */
3126
3127 *tune_state = CT_DEMOD_SEARCH_NEXT;
3128 state->autosearch_state = AS_SEARCHING_GUARD;
Patrick Boettcher173a64c2013-04-22 12:45:52 -03003129 if (state->revision == 0x8090)
3130 ret = 50;
3131 else
Mauro Carvalho Chehab7fa676c2014-07-04 14:15:29 -03003132 ret = 10;
Patrick Boettcher173a64c2013-04-22 12:45:52 -03003133 break;
Mauro Carvalho Chehab7fa676c2014-07-04 14:15:29 -03003134 case AS_SEARCHING_GUARD:
3135 /* searching for the correct guard interval */
3136 if (state->revision == 0x8090)
3137 state->found_guard = dib8000_read_word(state, 572) & 0x3;
3138 else
3139 state->found_guard = dib8000_read_word(state, 570) & 0x3;
3140 /* dprintk("guard interval found=%i", state->found_guard); */
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003141
Mauro Carvalho Chehab7fa676c2014-07-04 14:15:29 -03003142 *tune_state = CT_DEMOD_STEP_3;
Patrick Boettcher173a64c2013-04-22 12:45:52 -03003143 break;
Mauro Carvalho Chehab7fa676c2014-07-04 14:15:29 -03003144 default:
3145 /* the demod should never be in this state */
3146 state->status = FE_STATUS_TUNE_FAILED;
3147 state->autosearch_state = AS_DONE;
3148 *tune_state = CT_DEMOD_STOP; /* else we are done here */
Patrick Boettcher173a64c2013-04-22 12:45:52 -03003149 break;
Mauro Carvalho Chehab7fa676c2014-07-04 14:15:29 -03003150 }
3151 break;
Patrick Boettcher173a64c2013-04-22 12:45:52 -03003152
3153 case CT_DEMOD_STEP_3: /* 33 */
Mauro Carvalho Chehab7fa676c2014-07-04 14:15:29 -03003154 dib8000_set_isdbt_loop_params(state, LOOP_TUNE_1);
3155 dib8000_set_isdbt_common_channel(state, 0, 0);/* setting the known channel parameters here */
3156 *tune_state = CT_DEMOD_STEP_4;
3157 break;
Patrick Boettcher173a64c2013-04-22 12:45:52 -03003158
3159 case CT_DEMOD_STEP_4: /* (34) */
Mauro Carvalho Chehab7fa676c2014-07-04 14:15:29 -03003160 dib8000_demod_restart(state);
Patrick Boettcher173a64c2013-04-22 12:45:52 -03003161
Mauro Carvalho Chehab7fa676c2014-07-04 14:15:29 -03003162 dib8000_set_sync_wait(state);
3163 dib8000_set_diversity_in(state->fe[0], state->diversity_onoff);
Patrick Boettcher173a64c2013-04-22 12:45:52 -03003164
Mauro Carvalho Chehab7fa676c2014-07-04 14:15:29 -03003165 locks = (dib8000_read_word(state, 180) >> 6) & 0x3f; /* P_coff_winlen ? */
3166 /* coff should lock over P_coff_winlen ofdm symbols : give 3 times this length to lock */
3167 *timeout = dib8000_get_timeout(state, 2 * locks, SYMBOL_DEPENDENT_ON);
3168 *tune_state = CT_DEMOD_STEP_5;
3169 break;
Patrick Boettcher173a64c2013-04-22 12:45:52 -03003170
3171 case CT_DEMOD_STEP_5: /* (35) */
Mauro Carvalho Chehab7fa676c2014-07-04 14:15:29 -03003172 locks = dib8000_read_lock(fe);
3173 if (locks & (0x3 << 11)) { /* coff-lock and off_cpil_lock achieved */
3174 dib8000_update_timf(state); /* we achieved a coff_cpil_lock - it's time to update the timf */
3175 if (!state->differential_constellation) {
3176 /* 2 times lmod4_win_len + 10 symbols (pipe delay after coff + nb to compute a 1st correlation) */
3177 *timeout = dib8000_get_timeout(state, (20 * ((dib8000_read_word(state, 188)>>5)&0x1f)), SYMBOL_DEPENDENT_ON);
3178 *tune_state = CT_DEMOD_STEP_7;
3179 } else {
3180 *tune_state = CT_DEMOD_STEP_8;
Patrick Boettcher173a64c2013-04-22 12:45:52 -03003181 }
Mauro Carvalho Chehabd6c62b72014-07-04 14:15:37 -03003182 } else if (time_after(now, *timeout)) {
Mauro Carvalho Chehab7fa676c2014-07-04 14:15:29 -03003183 *tune_state = CT_DEMOD_STEP_6; /* goto check for diversity input connection */
3184 }
3185 break;
Patrick Boettcher173a64c2013-04-22 12:45:52 -03003186
3187 case CT_DEMOD_STEP_6: /* (36) if there is an input (diversity) */
Mauro Carvalho Chehab7fa676c2014-07-04 14:15:29 -03003188 if ((state->fe[1] != NULL) && (state->output_mode != OUTMODE_DIVERSITY)) {
3189 /* 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 */
3190 if (dib8000_get_status(state->fe[1]) <= FE_STATUS_STD_SUCCESS) /* Something is locked on the input fe */
3191 *tune_state = CT_DEMOD_STEP_8; /* go for mpeg */
3192 else if (dib8000_get_status(state->fe[1]) >= FE_STATUS_TUNE_TIME_TOO_SHORT) { /* fe in input failled also, break the current one */
3193 *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 -03003194 dib8000_viterbi_state(state, 1); /* start viterbi chandec */
3195 dib8000_set_isdbt_loop_params(state, LOOP_TUNE_2);
Patrick Boettcher173a64c2013-04-22 12:45:52 -03003196 state->status = FE_STATUS_TUNE_FAILED;
3197 }
Mauro Carvalho Chehab7fa676c2014-07-04 14:15:29 -03003198 } else {
Patrick Boettcher173a64c2013-04-22 12:45:52 -03003199 dib8000_viterbi_state(state, 1); /* start viterbi chandec */
3200 dib8000_set_isdbt_loop_params(state, LOOP_TUNE_2);
Mauro Carvalho Chehab7fa676c2014-07-04 14:15:29 -03003201 *tune_state = CT_DEMOD_STOP; /* else we are done here ; step 8 will close the loops and exit */
3202 state->status = FE_STATUS_TUNE_FAILED;
3203 }
3204 break;
Patrick Boettcher173a64c2013-04-22 12:45:52 -03003205
Mauro Carvalho Chehab7fa676c2014-07-04 14:15:29 -03003206 case CT_DEMOD_STEP_7: /* 37 */
3207 locks = dib8000_read_lock(fe);
3208 if (locks & (1<<10)) { /* lmod4_lock */
3209 ret = 14; /* wait for 14 symbols */
3210 *tune_state = CT_DEMOD_STEP_8;
Mauro Carvalho Chehabd6c62b72014-07-04 14:15:37 -03003211 } else if (time_after(now, *timeout))
Mauro Carvalho Chehab7fa676c2014-07-04 14:15:29 -03003212 *tune_state = CT_DEMOD_STEP_6; /* goto check for diversity input connection */
3213 break;
3214
3215 case CT_DEMOD_STEP_8: /* 38 */
3216 dib8000_viterbi_state(state, 1); /* start viterbi chandec */
3217 dib8000_set_isdbt_loop_params(state, LOOP_TUNE_2);
3218
3219 /* mpeg will never lock on this condition because init_prbs is not set : search for it !*/
3220 if (c->isdbt_sb_mode
3221 && c->isdbt_sb_subchannel < 14
3222 && !state->differential_constellation) {
3223 state->subchannel = 0;
3224 *tune_state = CT_DEMOD_STEP_11;
3225 } else {
3226 *tune_state = CT_DEMOD_STEP_9;
3227 state->status = FE_STATUS_LOCKED;
3228 }
3229 break;
Patrick Boettcher173a64c2013-04-22 12:45:52 -03003230
3231 case CT_DEMOD_STEP_9: /* 39 */
Mauro Carvalho Chehab7fa676c2014-07-04 14:15:29 -03003232 if ((state->revision == 0x8090) || ((dib8000_read_word(state, 1291) >> 9) & 0x1)) { /* fe capable of deinterleaving : esram */
3233 /* defines timeout for mpeg lock depending on interleaver length of longest layer */
3234 for (i = 0; i < 3; i++) {
3235 if (c->layer[i].interleaving >= deeper_interleaver) {
3236 dprintk("layer%i: time interleaver = %d ", i, c->layer[i].interleaving);
3237 if (c->layer[i].segment_count > 0) { /* valid layer */
3238 deeper_interleaver = c->layer[0].interleaving;
3239 state->longest_intlv_layer = i;
Patrick Boettcher173a64c2013-04-22 12:45:52 -03003240 }
3241 }
Mauro Carvalho Chehab7fa676c2014-07-04 14:15:29 -03003242 }
Patrick Boettcher173a64c2013-04-22 12:45:52 -03003243
Mauro Carvalho Chehab7fa676c2014-07-04 14:15:29 -03003244 if (deeper_interleaver == 0)
3245 locks = 2; /* locks is the tmp local variable name */
3246 else if (deeper_interleaver == 3)
3247 locks = 8;
3248 else
3249 locks = 2 * deeper_interleaver;
Patrick Boettcher173a64c2013-04-22 12:45:52 -03003250
Mauro Carvalho Chehab7fa676c2014-07-04 14:15:29 -03003251 if (state->diversity_onoff != 0) /* because of diversity sync */
3252 locks *= 2;
Patrick Boettcher173a64c2013-04-22 12:45:52 -03003253
Mauro Carvalho Chehabd6c62b72014-07-04 14:15:37 -03003254 *timeout = now + msecs_to_jiffies(200 * locks); /* give the mpeg lock 800ms if sram is present */
3255 dprintk("Deeper interleaver mode = %d on layer %d : timeout mult factor = %d => will use timeout = %ld",
3256 deeper_interleaver, state->longest_intlv_layer, locks, *timeout);
Patrick Boettcher173a64c2013-04-22 12:45:52 -03003257
Mauro Carvalho Chehab7fa676c2014-07-04 14:15:29 -03003258 *tune_state = CT_DEMOD_STEP_10;
3259 } else
3260 *tune_state = CT_DEMOD_STOP;
3261 break;
Patrick Boettcher173a64c2013-04-22 12:45:52 -03003262
3263 case CT_DEMOD_STEP_10: /* 40 */
Mauro Carvalho Chehab7fa676c2014-07-04 14:15:29 -03003264 locks = dib8000_read_lock(fe);
3265 if (locks&(1<<(7-state->longest_intlv_layer))) { /* mpeg lock : check the longest one */
Mauro Carvalho Chehab3c0d3942014-07-04 14:15:40 -03003266 dprintk("ISDB-T layer locks: Layer A %s, Layer B %s, Layer C %s",
3267 c->layer[0].segment_count ? (locks >> 7) & 0x1 ? "locked" : "NOT LOCKED" : "not enabled",
3268 c->layer[1].segment_count ? (locks >> 6) & 0x1 ? "locked" : "NOT LOCKED" : "not enabled",
3269 c->layer[2].segment_count ? (locks >> 5) & 0x1 ? "locked" : "NOT LOCKED" : "not enabled");
Mauro Carvalho Chehab7fa676c2014-07-04 14:15:29 -03003270 if (c->isdbt_sb_mode
3271 && c->isdbt_sb_subchannel < 14
3272 && !state->differential_constellation)
3273 /* signal to the upper layer, that there was a channel found and the parameters can be read */
3274 state->status = FE_STATUS_DEMOD_SUCCESS;
3275 else
3276 state->status = FE_STATUS_DATA_LOCKED;
3277 *tune_state = CT_DEMOD_STOP;
Mauro Carvalho Chehabd6c62b72014-07-04 14:15:37 -03003278 } else if (time_after(now, *timeout)) {
Mauro Carvalho Chehab7fa676c2014-07-04 14:15:29 -03003279 if (c->isdbt_sb_mode
3280 && c->isdbt_sb_subchannel < 14
3281 && !state->differential_constellation) { /* continue to try init prbs autosearch */
3282 state->subchannel += 3;
3283 *tune_state = CT_DEMOD_STEP_11;
3284 } 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 -03003285 if (locks & (0x7 << 5)) {
3286 dprintk("Not all ISDB-T layers locked in %d ms: Layer A %s, Layer B %s, Layer C %s",
3287 jiffies_to_msecs(now - *timeout),
3288 c->layer[0].segment_count ? (locks >> 7) & 0x1 ? "locked" : "NOT LOCKED" : "not enabled",
3289 c->layer[1].segment_count ? (locks >> 6) & 0x1 ? "locked" : "NOT LOCKED" : "not enabled",
3290 c->layer[2].segment_count ? (locks >> 5) & 0x1 ? "locked" : "NOT LOCKED" : "not enabled");
3291
Patrick Boettcher173a64c2013-04-22 12:45:52 -03003292 state->status = FE_STATUS_DATA_LOCKED;
Mauro Carvalho Chehab7fa676c2014-07-04 14:15:29 -03003293 } else
3294 state->status = FE_STATUS_TUNE_FAILED;
Patrick Boettcher173a64c2013-04-22 12:45:52 -03003295 *tune_state = CT_DEMOD_STOP;
Patrick Boettcher173a64c2013-04-22 12:45:52 -03003296 }
Mauro Carvalho Chehab7fa676c2014-07-04 14:15:29 -03003297 }
3298 break;
Patrick Boettcher173a64c2013-04-22 12:45:52 -03003299
3300 case CT_DEMOD_STEP_11: /* 41 : init prbs autosearch */
Mauro Carvalho Chehab7fa676c2014-07-04 14:15:29 -03003301 if (state->subchannel <= 41) {
3302 dib8000_set_subchannel_prbs(state, dib8000_get_init_prbs(state, state->subchannel));
3303 *tune_state = CT_DEMOD_STEP_9;
3304 } else {
3305 *tune_state = CT_DEMOD_STOP;
3306 state->status = FE_STATUS_TUNE_FAILED;
3307 }
3308 break;
Patrick Boettcher173a64c2013-04-22 12:45:52 -03003309
3310 default:
Mauro Carvalho Chehab7fa676c2014-07-04 14:15:29 -03003311 break;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003312 }
3313
Patrick Boettcher173a64c2013-04-22 12:45:52 -03003314 /* tuning is finished - cleanup the demod */
3315 switch (*tune_state) {
3316 case CT_DEMOD_STOP: /* (42) */
3317#ifdef DIB8000_AGC_FREEZE
Mauro Carvalho Chehab7fa676c2014-07-04 14:15:29 -03003318 if ((state->revision != 0x8090) && (state->agc1_max != 0)) {
3319 dib8000_write_word(state, 108, state->agc1_max);
3320 dib8000_write_word(state, 109, state->agc1_min);
3321 dib8000_write_word(state, 110, state->agc2_max);
3322 dib8000_write_word(state, 111, state->agc2_min);
3323 state->agc1_max = 0;
3324 state->agc1_min = 0;
3325 state->agc2_max = 0;
3326 state->agc2_min = 0;
3327 }
Patrick Boettcher173a64c2013-04-22 12:45:52 -03003328#endif
Mauro Carvalho Chehabd6c62b72014-07-04 14:15:37 -03003329 ret = 0;
Mauro Carvalho Chehab7fa676c2014-07-04 14:15:29 -03003330 break;
Patrick Boettcher173a64c2013-04-22 12:45:52 -03003331 default:
Mauro Carvalho Chehab7fa676c2014-07-04 14:15:29 -03003332 break;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003333 }
3334
Patrick Boettcher173a64c2013-04-22 12:45:52 -03003335 if ((ret > 0) && (*tune_state > CT_DEMOD_STEP_3))
3336 return ret * state->symbol_duration;
3337 if ((ret > 0) && (ret < state->symbol_duration))
3338 return state->symbol_duration; /* at least one symbol */
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003339 return ret;
3340}
3341
3342static int dib8000_wakeup(struct dvb_frontend *fe)
3343{
3344 struct dib8000_state *state = fe->demodulator_priv;
Olivier Grenie4c70e072011-01-03 15:33:37 -03003345 u8 index_frontend;
3346 int ret;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003347
Olivier Grenie0c32dbd2011-08-10 05:17:18 -03003348 dib8000_set_power_mode(state, DIB8000_POWER_ALL);
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003349 dib8000_set_adc_state(state, DIBX000_ADC_ON);
3350 if (dib8000_set_adc_state(state, DIBX000_SLOW_ADC_ON) != 0)
3351 dprintk("could not start Slow ADC");
3352
Patrick Boettcher173a64c2013-04-22 12:45:52 -03003353 if (state->revision == 0x8090)
Olivier Grenie0c32dbd2011-08-10 05:17:18 -03003354 dib8000_sad_calib(state);
3355
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03003356 for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
Olivier Grenie4c70e072011-01-03 15:33:37 -03003357 ret = state->fe[index_frontend]->ops.init(state->fe[index_frontend]);
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03003358 if (ret < 0)
Olivier Grenie4c70e072011-01-03 15:33:37 -03003359 return ret;
3360 }
3361
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003362 return 0;
3363}
3364
3365static int dib8000_sleep(struct dvb_frontend *fe)
3366{
Olivier Grenie4c70e072011-01-03 15:33:37 -03003367 struct dib8000_state *state = fe->demodulator_priv;
3368 u8 index_frontend;
3369 int ret;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003370
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03003371 for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
Olivier Grenie4c70e072011-01-03 15:33:37 -03003372 ret = state->fe[index_frontend]->ops.sleep(state->fe[index_frontend]);
3373 if (ret < 0)
3374 return ret;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003375 }
Olivier Grenie4c70e072011-01-03 15:33:37 -03003376
Olivier Grenie0c32dbd2011-08-10 05:17:18 -03003377 if (state->revision != 0x8090)
3378 dib8000_set_output_mode(fe, OUTMODE_HIGH_Z);
3379 dib8000_set_power_mode(state, DIB8000_POWER_INTERFACE_ONLY);
Olivier Grenie4c70e072011-01-03 15:33:37 -03003380 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 -03003381}
3382
Mauro Carvalho Chehab0df289a2015-06-07 14:53:52 -03003383static int dib8000_read_status(struct dvb_frontend *fe, enum fe_status *stat);
Mauro Carvalho Chehab70315b32013-12-15 07:41:20 -02003384
Mauro Carvalho Chehab7e3e68b2016-02-04 12:58:30 -02003385static int dib8000_get_frontend(struct dvb_frontend *fe,
3386 struct dtv_frontend_properties *c)
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003387{
3388 struct dib8000_state *state = fe->demodulator_priv;
3389 u16 i, val = 0;
Mauro Carvalho Chehab0df289a2015-06-07 14:53:52 -03003390 enum fe_status stat = 0;
Olivier Grenie4c70e072011-01-03 15:33:37 -03003391 u8 index_frontend, sub_index_frontend;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003392
Mauro Carvalho Chehab7e3e68b2016-02-04 12:58:30 -02003393 c->bandwidth_hz = 6000000;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003394
Mauro Carvalho Chehab70315b32013-12-15 07:41:20 -02003395 /*
3396 * If called to early, get_frontend makes dib8000_tune to either
3397 * not lock or not sync. This causes dvbv5-scan/dvbv5-zap to fail.
3398 * So, let's just return if frontend 0 has not locked.
3399 */
3400 dib8000_read_status(fe, &stat);
3401 if (!(stat & FE_HAS_SYNC))
3402 return 0;
3403
Mauro Carvalho Chehabecc31d52014-07-04 14:15:39 -03003404 dprintk("dib8000_get_frontend: TMCC lock");
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03003405 for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
Olivier Grenie4c70e072011-01-03 15:33:37 -03003406 state->fe[index_frontend]->ops.read_status(state->fe[index_frontend], &stat);
3407 if (stat&FE_HAS_SYNC) {
3408 dprintk("TMCC lock on the slave%i", index_frontend);
3409 /* synchronize the cache with the other frontends */
Mauro Carvalho Chehab7e3e68b2016-02-04 12:58:30 -02003410 state->fe[index_frontend]->ops.get_frontend(state->fe[index_frontend], c);
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03003411 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 -03003412 if (sub_index_frontend != index_frontend) {
3413 state->fe[sub_index_frontend]->dtv_property_cache.isdbt_sb_mode = state->fe[index_frontend]->dtv_property_cache.isdbt_sb_mode;
3414 state->fe[sub_index_frontend]->dtv_property_cache.inversion = state->fe[index_frontend]->dtv_property_cache.inversion;
3415 state->fe[sub_index_frontend]->dtv_property_cache.transmission_mode = state->fe[index_frontend]->dtv_property_cache.transmission_mode;
3416 state->fe[sub_index_frontend]->dtv_property_cache.guard_interval = state->fe[index_frontend]->dtv_property_cache.guard_interval;
3417 state->fe[sub_index_frontend]->dtv_property_cache.isdbt_partial_reception = state->fe[index_frontend]->dtv_property_cache.isdbt_partial_reception;
3418 for (i = 0; i < 3; i++) {
3419 state->fe[sub_index_frontend]->dtv_property_cache.layer[i].segment_count = state->fe[index_frontend]->dtv_property_cache.layer[i].segment_count;
3420 state->fe[sub_index_frontend]->dtv_property_cache.layer[i].interleaving = state->fe[index_frontend]->dtv_property_cache.layer[i].interleaving;
3421 state->fe[sub_index_frontend]->dtv_property_cache.layer[i].fec = state->fe[index_frontend]->dtv_property_cache.layer[i].fec;
3422 state->fe[sub_index_frontend]->dtv_property_cache.layer[i].modulation = state->fe[index_frontend]->dtv_property_cache.layer[i].modulation;
3423 }
3424 }
3425 }
3426 return 0;
3427 }
3428 }
3429
Mauro Carvalho Chehab7e3e68b2016-02-04 12:58:30 -02003430 c->isdbt_sb_mode = dib8000_read_word(state, 508) & 0x1;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003431
Olivier Grenie0c32dbd2011-08-10 05:17:18 -03003432 if (state->revision == 0x8090)
3433 val = dib8000_read_word(state, 572);
3434 else
3435 val = dib8000_read_word(state, 570);
Mauro Carvalho Chehab7e3e68b2016-02-04 12:58:30 -02003436 c->inversion = (val & 0x40) >> 6;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003437 switch ((val & 0x30) >> 4) {
3438 case 1:
Mauro Carvalho Chehab7e3e68b2016-02-04 12:58:30 -02003439 c->transmission_mode = TRANSMISSION_MODE_2K;
Mauro Carvalho Chehabecc31d52014-07-04 14:15:39 -03003440 dprintk("dib8000_get_frontend: transmission mode 2K");
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003441 break;
Mauro Carvalho Chehab7fec1c82014-07-04 14:15:30 -03003442 case 2:
Mauro Carvalho Chehab7e3e68b2016-02-04 12:58:30 -02003443 c->transmission_mode = TRANSMISSION_MODE_4K;
Mauro Carvalho Chehabecc31d52014-07-04 14:15:39 -03003444 dprintk("dib8000_get_frontend: transmission mode 4K");
Mauro Carvalho Chehab7fec1c82014-07-04 14:15:30 -03003445 break;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003446 case 3:
3447 default:
Mauro Carvalho Chehab7e3e68b2016-02-04 12:58:30 -02003448 c->transmission_mode = TRANSMISSION_MODE_8K;
Mauro Carvalho Chehabecc31d52014-07-04 14:15:39 -03003449 dprintk("dib8000_get_frontend: transmission mode 8K");
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003450 break;
3451 }
3452
3453 switch (val & 0x3) {
3454 case 0:
Mauro Carvalho Chehab7e3e68b2016-02-04 12:58:30 -02003455 c->guard_interval = GUARD_INTERVAL_1_32;
Mauro Carvalho Chehabecc31d52014-07-04 14:15:39 -03003456 dprintk("dib8000_get_frontend: Guard Interval = 1/32 ");
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003457 break;
3458 case 1:
Mauro Carvalho Chehab7e3e68b2016-02-04 12:58:30 -02003459 c->guard_interval = GUARD_INTERVAL_1_16;
Mauro Carvalho Chehabecc31d52014-07-04 14:15:39 -03003460 dprintk("dib8000_get_frontend: Guard Interval = 1/16 ");
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003461 break;
3462 case 2:
Mauro Carvalho Chehabecc31d52014-07-04 14:15:39 -03003463 dprintk("dib8000_get_frontend: Guard Interval = 1/8 ");
Mauro Carvalho Chehab7e3e68b2016-02-04 12:58:30 -02003464 c->guard_interval = GUARD_INTERVAL_1_8;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003465 break;
3466 case 3:
Mauro Carvalho Chehabecc31d52014-07-04 14:15:39 -03003467 dprintk("dib8000_get_frontend: Guard Interval = 1/4 ");
Mauro Carvalho Chehab7e3e68b2016-02-04 12:58:30 -02003468 c->guard_interval = GUARD_INTERVAL_1_4;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003469 break;
3470 }
3471
3472 val = dib8000_read_word(state, 505);
Mauro Carvalho Chehab7e3e68b2016-02-04 12:58:30 -02003473 c->isdbt_partial_reception = val & 1;
3474 dprintk("dib8000_get_frontend: partial_reception = %d ", c->isdbt_partial_reception);
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003475
3476 for (i = 0; i < 3; i++) {
Mauro Carvalho Chehabecc31d52014-07-04 14:15:39 -03003477 int show;
3478
3479 val = dib8000_read_word(state, 493 + i) & 0x0f;
Mauro Carvalho Chehab7e3e68b2016-02-04 12:58:30 -02003480 c->layer[i].segment_count = val;
Mauro Carvalho Chehabecc31d52014-07-04 14:15:39 -03003481
3482 if (val == 0 || val > 13)
3483 show = 0;
3484 else
3485 show = 1;
3486
3487 if (show)
3488 dprintk("dib8000_get_frontend: Layer %d segments = %d ",
Mauro Carvalho Chehab7e3e68b2016-02-04 12:58:30 -02003489 i, c->layer[i].segment_count);
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003490
Mauro Carvalho Chehab51fea112013-12-16 04:16:59 -03003491 val = dib8000_read_word(state, 499 + i) & 0x3;
3492 /* Interleaving can be 0, 1, 2 or 4 */
3493 if (val == 3)
3494 val = 4;
Mauro Carvalho Chehab7e3e68b2016-02-04 12:58:30 -02003495 c->layer[i].interleaving = val;
Mauro Carvalho Chehabecc31d52014-07-04 14:15:39 -03003496 if (show)
3497 dprintk("dib8000_get_frontend: Layer %d time_intlv = %d ",
Mauro Carvalho Chehab7e3e68b2016-02-04 12:58:30 -02003498 i, c->layer[i].interleaving);
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003499
3500 val = dib8000_read_word(state, 481 + i);
3501 switch (val & 0x7) {
3502 case 1:
Mauro Carvalho Chehab7e3e68b2016-02-04 12:58:30 -02003503 c->layer[i].fec = FEC_1_2;
Mauro Carvalho Chehabecc31d52014-07-04 14:15:39 -03003504 if (show)
3505 dprintk("dib8000_get_frontend: Layer %d Code Rate = 1/2 ", i);
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003506 break;
3507 case 2:
Mauro Carvalho Chehab7e3e68b2016-02-04 12:58:30 -02003508 c->layer[i].fec = FEC_2_3;
Mauro Carvalho Chehabecc31d52014-07-04 14:15:39 -03003509 if (show)
3510 dprintk("dib8000_get_frontend: Layer %d Code Rate = 2/3 ", i);
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003511 break;
3512 case 3:
Mauro Carvalho Chehab7e3e68b2016-02-04 12:58:30 -02003513 c->layer[i].fec = FEC_3_4;
Mauro Carvalho Chehabecc31d52014-07-04 14:15:39 -03003514 if (show)
3515 dprintk("dib8000_get_frontend: Layer %d Code Rate = 3/4 ", i);
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003516 break;
3517 case 5:
Mauro Carvalho Chehab7e3e68b2016-02-04 12:58:30 -02003518 c->layer[i].fec = FEC_5_6;
Mauro Carvalho Chehabecc31d52014-07-04 14:15:39 -03003519 if (show)
3520 dprintk("dib8000_get_frontend: Layer %d Code Rate = 5/6 ", i);
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003521 break;
3522 default:
Mauro Carvalho Chehab7e3e68b2016-02-04 12:58:30 -02003523 c->layer[i].fec = FEC_7_8;
Mauro Carvalho Chehabecc31d52014-07-04 14:15:39 -03003524 if (show)
3525 dprintk("dib8000_get_frontend: Layer %d Code Rate = 7/8 ", i);
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003526 break;
3527 }
3528
3529 val = dib8000_read_word(state, 487 + i);
3530 switch (val & 0x3) {
3531 case 0:
Mauro Carvalho Chehab7e3e68b2016-02-04 12:58:30 -02003532 c->layer[i].modulation = DQPSK;
Mauro Carvalho Chehabecc31d52014-07-04 14:15:39 -03003533 if (show)
3534 dprintk("dib8000_get_frontend: Layer %d DQPSK ", i);
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003535 break;
3536 case 1:
Mauro Carvalho Chehab7e3e68b2016-02-04 12:58:30 -02003537 c->layer[i].modulation = QPSK;
Mauro Carvalho Chehabecc31d52014-07-04 14:15:39 -03003538 if (show)
3539 dprintk("dib8000_get_frontend: Layer %d QPSK ", i);
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003540 break;
3541 case 2:
Mauro Carvalho Chehab7e3e68b2016-02-04 12:58:30 -02003542 c->layer[i].modulation = QAM_16;
Mauro Carvalho Chehabecc31d52014-07-04 14:15:39 -03003543 if (show)
3544 dprintk("dib8000_get_frontend: Layer %d QAM16 ", i);
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003545 break;
3546 case 3:
3547 default:
Mauro Carvalho Chehab7e3e68b2016-02-04 12:58:30 -02003548 c->layer[i].modulation = QAM_64;
Mauro Carvalho Chehabecc31d52014-07-04 14:15:39 -03003549 if (show)
3550 dprintk("dib8000_get_frontend: Layer %d QAM64 ", i);
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003551 break;
3552 }
3553 }
Olivier Grenie4c70e072011-01-03 15:33:37 -03003554
3555 /* synchronize the cache with the other frontends */
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03003556 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 -02003557 state->fe[index_frontend]->dtv_property_cache.isdbt_sb_mode = c->isdbt_sb_mode;
3558 state->fe[index_frontend]->dtv_property_cache.inversion = c->inversion;
3559 state->fe[index_frontend]->dtv_property_cache.transmission_mode = c->transmission_mode;
3560 state->fe[index_frontend]->dtv_property_cache.guard_interval = c->guard_interval;
3561 state->fe[index_frontend]->dtv_property_cache.isdbt_partial_reception = c->isdbt_partial_reception;
Olivier Grenie4c70e072011-01-03 15:33:37 -03003562 for (i = 0; i < 3; i++) {
Mauro Carvalho Chehab7e3e68b2016-02-04 12:58:30 -02003563 state->fe[index_frontend]->dtv_property_cache.layer[i].segment_count = c->layer[i].segment_count;
3564 state->fe[index_frontend]->dtv_property_cache.layer[i].interleaving = c->layer[i].interleaving;
3565 state->fe[index_frontend]->dtv_property_cache.layer[i].fec = c->layer[i].fec;
3566 state->fe[index_frontend]->dtv_property_cache.layer[i].modulation = c->layer[i].modulation;
Olivier Grenie4c70e072011-01-03 15:33:37 -03003567 }
3568 }
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003569 return 0;
3570}
3571
Mauro Carvalho Chehab490ecd62011-12-22 20:38:27 -03003572static int dib8000_set_frontend(struct dvb_frontend *fe)
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003573{
3574 struct dib8000_state *state = fe->demodulator_priv;
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03003575 struct dtv_frontend_properties *c = &state->fe[0]->dtv_property_cache;
Mauro Carvalho Chehabd6c62b72014-07-04 14:15:37 -03003576 int l, i, active, time, time_slave = 0;
Patrick Boettcher173a64c2013-04-22 12:45:52 -03003577 u8 exit_condition, index_frontend;
Mauro Carvalho Chehabd6c62b72014-07-04 14:15:37 -03003578 unsigned long delay, callback_time;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003579
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03003580 if (c->frequency == 0) {
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003581 dprintk("dib8000: must at least specify frequency ");
3582 return 0;
3583 }
3584
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03003585 if (c->bandwidth_hz == 0) {
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003586 dprintk("dib8000: no bandwidth specified, set to default ");
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03003587 c->bandwidth_hz = 6000000;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003588 }
3589
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03003590 for (index_frontend = 0; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
Olivier Grenie4c70e072011-01-03 15:33:37 -03003591 /* synchronization of the cache */
3592 state->fe[index_frontend]->dtv_property_cache.delivery_system = SYS_ISDBT;
3593 memcpy(&state->fe[index_frontend]->dtv_property_cache, &fe->dtv_property_cache, sizeof(struct dtv_frontend_properties));
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003594
Patrick Boettcher173a64c2013-04-22 12:45:52 -03003595 /* set output mode and diversity input */
3596 if (state->revision != 0x8090) {
3597 dib8000_set_diversity_in(state->fe[index_frontend], 1);
3598 if (index_frontend != 0)
3599 dib8000_set_output_mode(state->fe[index_frontend],
3600 OUTMODE_DIVERSITY);
3601 else
3602 dib8000_set_output_mode(state->fe[0], OUTMODE_HIGH_Z);
3603 } else {
3604 dib8096p_set_diversity_in(state->fe[index_frontend], 1);
3605 if (index_frontend != 0)
3606 dib8096p_set_output_mode(state->fe[index_frontend],
3607 OUTMODE_DIVERSITY);
3608 else
3609 dib8096p_set_output_mode(state->fe[0], OUTMODE_HIGH_Z);
3610 }
3611
3612 /* tune the tuner */
Olivier Grenie4c70e072011-01-03 15:33:37 -03003613 if (state->fe[index_frontend]->ops.tuner_ops.set_params)
Mauro Carvalho Chehab14d24d12011-12-24 12:24:33 -03003614 state->fe[index_frontend]->ops.tuner_ops.set_params(state->fe[index_frontend]);
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003615
Olivier Grenie4c70e072011-01-03 15:33:37 -03003616 dib8000_set_tune_state(state->fe[index_frontend], CT_AGC_START);
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003617 }
3618
Patrick Boettcher173a64c2013-04-22 12:45:52 -03003619 /* turn off the diversity of the last chip */
3620 if (state->revision != 0x8090)
3621 dib8000_set_diversity_in(state->fe[index_frontend - 1], 0);
3622 else
3623 dib8096p_set_diversity_in(state->fe[index_frontend - 1], 0);
3624
Olivier Grenie4c70e072011-01-03 15:33:37 -03003625 /* start up the AGC */
3626 do {
3627 time = dib8000_agc_startup(state->fe[0]);
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03003628 for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
Olivier Grenie4c70e072011-01-03 15:33:37 -03003629 time_slave = dib8000_agc_startup(state->fe[index_frontend]);
Mauro Carvalho Chehabd6c62b72014-07-04 14:15:37 -03003630 if (time == 0)
Olivier Grenie4c70e072011-01-03 15:33:37 -03003631 time = time_slave;
Mauro Carvalho Chehabd6c62b72014-07-04 14:15:37 -03003632 else if ((time_slave != 0) && (time_slave > time))
Olivier Grenie4c70e072011-01-03 15:33:37 -03003633 time = time_slave;
3634 }
Mauro Carvalho Chehabd6c62b72014-07-04 14:15:37 -03003635 if (time == 0)
Olivier Grenie4c70e072011-01-03 15:33:37 -03003636 break;
Mauro Carvalho Chehab4607bb72014-07-04 14:15:35 -03003637
3638 /*
3639 * Despite dib8000_agc_startup returns time at a 0.1 ms range,
3640 * the actual sleep time depends on CONFIG_HZ. The worse case
3641 * is when CONFIG_HZ=100. In such case, the minimum granularity
3642 * is 10ms. On some real field tests, the tuner sometimes don't
3643 * lock when this timer is lower than 10ms. So, enforce a 10ms
3644 * granularity.
3645 */
3646 time = 10 * (time + 99)/100;
3647 usleep_range(time * 1000, (time + 1) * 1000);
Olivier Grenie4c70e072011-01-03 15:33:37 -03003648 exit_condition = 1;
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03003649 for (index_frontend = 0; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
Olivier Grenie4c70e072011-01-03 15:33:37 -03003650 if (dib8000_get_tune_state(state->fe[index_frontend]) != CT_AGC_STOP) {
3651 exit_condition = 0;
3652 break;
3653 }
3654 }
3655 } while (exit_condition == 0);
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003656
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03003657 for (index_frontend = 0; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++)
Olivier Grenie4c70e072011-01-03 15:33:37 -03003658 dib8000_set_tune_state(state->fe[index_frontend], CT_DEMOD_START);
3659
Patrick Boettcher173a64c2013-04-22 12:45:52 -03003660 active = 1;
3661 do {
Mauro Carvalho Chehabd6c62b72014-07-04 14:15:37 -03003662 callback_time = 0;
Mauro Carvalho Chehab2c2c4412011-01-16 13:02:52 -02003663 for (index_frontend = 0; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
Patrick Boettcher173a64c2013-04-22 12:45:52 -03003664 delay = dib8000_tune(state->fe[index_frontend]);
Mauro Carvalho Chehabd6c62b72014-07-04 14:15:37 -03003665 if (delay != 0) {
3666 delay = jiffies + usecs_to_jiffies(100 * delay);
3667 if (!callback_time || delay < callback_time)
3668 callback_time = delay;
3669 }
Olivier Grenie4c70e072011-01-03 15:33:37 -03003670
Patrick Boettcher173a64c2013-04-22 12:45:52 -03003671 /* we are in autosearch */
3672 if (state->channel_parameters_set == 0) { /* searching */
3673 if ((dib8000_get_status(state->fe[index_frontend]) == FE_STATUS_DEMOD_SUCCESS) || (dib8000_get_status(state->fe[index_frontend]) == FE_STATUS_FFT_SUCCESS)) {
3674 dprintk("autosearch succeeded on fe%i", index_frontend);
Mauro Carvalho Chehab7e3e68b2016-02-04 12:58:30 -02003675 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 -03003676 state->channel_parameters_set = 1;
3677
3678 for (l = 0; (l < MAX_NUMBER_OF_FRONTENDS) && (state->fe[l] != NULL); l++) {
3679 if (l != index_frontend) { /* and for all frontend except the successful one */
Mauro Carvalho Chehabecc31d52014-07-04 14:15:39 -03003680 dprintk("Restarting frontend %d\n", l);
Patrick Boettcher173a64c2013-04-22 12:45:52 -03003681 dib8000_tune_restart_from_demod(state->fe[l]);
3682
3683 state->fe[l]->dtv_property_cache.isdbt_sb_mode = state->fe[index_frontend]->dtv_property_cache.isdbt_sb_mode;
3684 state->fe[l]->dtv_property_cache.inversion = state->fe[index_frontend]->dtv_property_cache.inversion;
3685 state->fe[l]->dtv_property_cache.transmission_mode = state->fe[index_frontend]->dtv_property_cache.transmission_mode;
3686 state->fe[l]->dtv_property_cache.guard_interval = state->fe[index_frontend]->dtv_property_cache.guard_interval;
3687 state->fe[l]->dtv_property_cache.isdbt_partial_reception = state->fe[index_frontend]->dtv_property_cache.isdbt_partial_reception;
3688 for (i = 0; i < 3; i++) {
3689 state->fe[l]->dtv_property_cache.layer[i].segment_count = state->fe[index_frontend]->dtv_property_cache.layer[i].segment_count;
3690 state->fe[l]->dtv_property_cache.layer[i].interleaving = state->fe[index_frontend]->dtv_property_cache.layer[i].interleaving;
3691 state->fe[l]->dtv_property_cache.layer[i].fec = state->fe[index_frontend]->dtv_property_cache.layer[i].fec;
3692 state->fe[l]->dtv_property_cache.layer[i].modulation = state->fe[index_frontend]->dtv_property_cache.layer[i].modulation;
3693 }
3694
3695 }
Mauro Carvalho Chehab2c2c4412011-01-16 13:02:52 -02003696 }
3697 }
3698 }
Patrick Boettcher173a64c2013-04-22 12:45:52 -03003699 }
3700 /* tuning is done when the master frontend is done (failed or success) */
3701 if (dib8000_get_status(state->fe[0]) == FE_STATUS_TUNE_FAILED ||
3702 dib8000_get_status(state->fe[0]) == FE_STATUS_LOCKED ||
3703 dib8000_get_status(state->fe[0]) == FE_STATUS_DATA_LOCKED) {
3704 active = 0;
3705 /* we need to wait for all frontends to be finished */
3706 for (index_frontend = 0; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
3707 if (dib8000_get_tune_state(state->fe[index_frontend]) != CT_DEMOD_STOP)
3708 active = 1;
3709 }
3710 if (active == 0)
3711 dprintk("tuning done with status %d", dib8000_get_status(state->fe[0]));
Mauro Carvalho Chehab2c2c4412011-01-16 13:02:52 -02003712 }
Olivier Grenie4c70e072011-01-03 15:33:37 -03003713
Mauro Carvalho Chehabd6c62b72014-07-04 14:15:37 -03003714 if ((active == 1) && (callback_time == 0)) {
Patrick Boettcher173a64c2013-04-22 12:45:52 -03003715 dprintk("strange callback time something went wrong");
3716 active = 0;
3717 }
Olivier Grenie4c70e072011-01-03 15:33:37 -03003718
Mauro Carvalho Chehabd6c62b72014-07-04 14:15:37 -03003719 while ((active == 1) && (time_before(jiffies, callback_time)))
Patrick Boettcher173a64c2013-04-22 12:45:52 -03003720 msleep(100);
3721 } while (active);
Olivier Grenie4c70e072011-01-03 15:33:37 -03003722
Patrick Boettcher173a64c2013-04-22 12:45:52 -03003723 /* set output mode */
3724 if (state->revision != 0x8090)
Olivier Grenie0c32dbd2011-08-10 05:17:18 -03003725 dib8000_set_output_mode(state->fe[0], state->cfg.output_mode);
Patrick Boettcher173a64c2013-04-22 12:45:52 -03003726 else {
Olivier Grenie0c32dbd2011-08-10 05:17:18 -03003727 dib8096p_set_output_mode(state->fe[0], state->cfg.output_mode);
3728 if (state->cfg.enMpegOutput == 0) {
3729 dib8096p_setDibTxMux(state, MPEG_ON_DIBTX);
3730 dib8096p_setHostBusMux(state, DIBTX_ON_HOSTBUS);
3731 }
Olivier Grenie0c32dbd2011-08-10 05:17:18 -03003732 }
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003733
Geert Uytterhoeven4d8d5d92013-06-02 13:52:17 -03003734 return 0;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003735}
3736
Mauro Carvalho Chehab0df289a2015-06-07 14:53:52 -03003737static int dib8000_get_stats(struct dvb_frontend *fe, enum fe_status stat);
Mauro Carvalho Chehab6ef06e72013-12-16 19:10:59 -03003738
Mauro Carvalho Chehab0df289a2015-06-07 14:53:52 -03003739static int dib8000_read_status(struct dvb_frontend *fe, enum fe_status *stat)
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003740{
3741 struct dib8000_state *state = fe->demodulator_priv;
Olivier Grenie0c32dbd2011-08-10 05:17:18 -03003742 u16 lock_slave = 0, lock;
Olivier Grenie4c70e072011-01-03 15:33:37 -03003743 u8 index_frontend;
3744
Patrick Boettcher173a64c2013-04-22 12:45:52 -03003745 lock = dib8000_read_lock(fe);
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03003746 for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++)
Olivier Grenie4c70e072011-01-03 15:33:37 -03003747 lock_slave |= dib8000_read_lock(state->fe[index_frontend]);
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003748
3749 *stat = 0;
3750
Olivier Grenie4c70e072011-01-03 15:33:37 -03003751 if (((lock >> 13) & 1) || ((lock_slave >> 13) & 1))
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003752 *stat |= FE_HAS_SIGNAL;
3753
Olivier Grenie4c70e072011-01-03 15:33:37 -03003754 if (((lock >> 8) & 1) || ((lock_slave >> 8) & 1)) /* Equal */
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003755 *stat |= FE_HAS_CARRIER;
3756
Olivier Grenie4c70e072011-01-03 15:33:37 -03003757 if ((((lock >> 1) & 0xf) == 0xf) || (((lock_slave >> 1) & 0xf) == 0xf)) /* TMCC_SYNC */
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003758 *stat |= FE_HAS_SYNC;
3759
Olivier Grenie4c70e072011-01-03 15:33:37 -03003760 if ((((lock >> 12) & 1) || ((lock_slave >> 12) & 1)) && ((lock >> 5) & 7)) /* FEC MPEG */
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003761 *stat |= FE_HAS_LOCK;
3762
Olivier Grenie4c70e072011-01-03 15:33:37 -03003763 if (((lock >> 12) & 1) || ((lock_slave >> 12) & 1)) {
Olivier Grenie89dfc552009-11-30 06:38:49 -03003764 lock = dib8000_read_word(state, 554); /* Viterbi Layer A */
3765 if (lock & 0x01)
3766 *stat |= FE_HAS_VITERBI;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003767
Olivier Grenie89dfc552009-11-30 06:38:49 -03003768 lock = dib8000_read_word(state, 555); /* Viterbi Layer B */
3769 if (lock & 0x01)
3770 *stat |= FE_HAS_VITERBI;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003771
Olivier Grenie89dfc552009-11-30 06:38:49 -03003772 lock = dib8000_read_word(state, 556); /* Viterbi Layer C */
3773 if (lock & 0x01)
3774 *stat |= FE_HAS_VITERBI;
3775 }
Mauro Carvalho Chehab6ef06e72013-12-16 19:10:59 -03003776 dib8000_get_stats(fe, *stat);
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003777
3778 return 0;
3779}
3780
3781static int dib8000_read_ber(struct dvb_frontend *fe, u32 * ber)
3782{
3783 struct dib8000_state *state = fe->demodulator_priv;
Olivier Grenie0c32dbd2011-08-10 05:17:18 -03003784
3785 /* 13 segments */
3786 if (state->revision == 0x8090)
3787 *ber = (dib8000_read_word(state, 562) << 16) |
3788 dib8000_read_word(state, 563);
3789 else
3790 *ber = (dib8000_read_word(state, 560) << 16) |
3791 dib8000_read_word(state, 561);
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003792 return 0;
3793}
3794
3795static int dib8000_read_unc_blocks(struct dvb_frontend *fe, u32 * unc)
3796{
3797 struct dib8000_state *state = fe->demodulator_priv;
Olivier Grenie0c32dbd2011-08-10 05:17:18 -03003798
3799 /* packet error on 13 seg */
3800 if (state->revision == 0x8090)
3801 *unc = dib8000_read_word(state, 567);
3802 else
3803 *unc = dib8000_read_word(state, 565);
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003804 return 0;
3805}
3806
3807static int dib8000_read_signal_strength(struct dvb_frontend *fe, u16 * strength)
3808{
3809 struct dib8000_state *state = fe->demodulator_priv;
Olivier Grenie4c70e072011-01-03 15:33:37 -03003810 u8 index_frontend;
3811 u16 val;
3812
3813 *strength = 0;
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03003814 for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
Olivier Grenie4c70e072011-01-03 15:33:37 -03003815 state->fe[index_frontend]->ops.read_signal_strength(state->fe[index_frontend], &val);
3816 if (val > 65535 - *strength)
3817 *strength = 65535;
3818 else
3819 *strength += val;
3820 }
3821
3822 val = 65535 - dib8000_read_word(state, 390);
3823 if (val > 65535 - *strength)
3824 *strength = 65535;
3825 else
3826 *strength += val;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003827 return 0;
3828}
3829
Olivier Grenie4c70e072011-01-03 15:33:37 -03003830static u32 dib8000_get_snr(struct dvb_frontend *fe)
3831{
3832 struct dib8000_state *state = fe->demodulator_priv;
3833 u32 n, s, exp;
3834 u16 val;
3835
Olivier Grenie0c32dbd2011-08-10 05:17:18 -03003836 if (state->revision != 0x8090)
3837 val = dib8000_read_word(state, 542);
3838 else
3839 val = dib8000_read_word(state, 544);
Olivier Grenie4c70e072011-01-03 15:33:37 -03003840 n = (val >> 6) & 0xff;
3841 exp = (val & 0x3f);
3842 if ((exp & 0x20) != 0)
3843 exp -= 0x40;
3844 n <<= exp+16;
3845
Olivier Grenie0c32dbd2011-08-10 05:17:18 -03003846 if (state->revision != 0x8090)
3847 val = dib8000_read_word(state, 543);
3848 else
3849 val = dib8000_read_word(state, 545);
Olivier Grenie4c70e072011-01-03 15:33:37 -03003850 s = (val >> 6) & 0xff;
3851 exp = (val & 0x3f);
3852 if ((exp & 0x20) != 0)
3853 exp -= 0x40;
3854 s <<= exp+16;
3855
3856 if (n > 0) {
3857 u32 t = (s/n) << 16;
3858 return t + ((s << 16) - n*t) / n;
3859 }
3860 return 0xffffffff;
3861}
3862
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003863static int dib8000_read_snr(struct dvb_frontend *fe, u16 * snr)
3864{
3865 struct dib8000_state *state = fe->demodulator_priv;
Olivier Grenie4c70e072011-01-03 15:33:37 -03003866 u8 index_frontend;
3867 u32 snr_master;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003868
Olivier Grenie4c70e072011-01-03 15:33:37 -03003869 snr_master = dib8000_get_snr(fe);
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03003870 for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++)
Olivier Grenie4c70e072011-01-03 15:33:37 -03003871 snr_master += dib8000_get_snr(state->fe[index_frontend]);
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003872
Olivier Grenie1f6bfcc2011-07-04 12:33:54 -03003873 if ((snr_master >> 16) != 0) {
Olivier Grenie4c70e072011-01-03 15:33:37 -03003874 snr_master = 10*intlog10(snr_master>>16);
3875 *snr = snr_master / ((1 << 24) / 10);
3876 }
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003877 else
Olivier Grenie4c70e072011-01-03 15:33:37 -03003878 *snr = 0;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003879
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003880 return 0;
3881}
3882
Mauro Carvalho Chehab6ef06e72013-12-16 19:10:59 -03003883struct per_layer_regs {
3884 u16 lock, ber, per;
3885};
3886
3887static const struct per_layer_regs per_layer_regs[] = {
3888 { 554, 560, 562 },
3889 { 555, 576, 578 },
3890 { 556, 581, 583 },
3891};
3892
Mauro Carvalho Chehab42ff76b2013-12-16 21:45:19 -03003893struct linear_segments {
3894 unsigned x;
3895 signed y;
3896};
3897
3898/*
3899 * Table to estimate signal strength in dBm.
3900 * This table was empirically determinated by measuring the signal
3901 * strength generated by a DTA-2111 RF generator directly connected into
3902 * a dib8076 device (a PixelView PV-D231U stick), using a good quality
3903 * 3 meters RC6 cable and good RC6 connectors.
3904 * The real value can actually be different on other devices, depending
3905 * on several factors, like if LNA is enabled or not, if diversity is
3906 * enabled, type of connectors, etc.
3907 * Yet, it is better to use this measure in dB than a random non-linear
3908 * percentage value, especially for antenna adjustments.
3909 * On my tests, the precision of the measure using this table is about
3910 * 0.5 dB, with sounds reasonable enough.
3911 */
3912static struct linear_segments strength_to_db_table[] = {
3913 { 55953, 108500 }, /* -22.5 dBm */
3914 { 55394, 108000 },
3915 { 53834, 107000 },
3916 { 52863, 106000 },
3917 { 52239, 105000 },
3918 { 52012, 104000 },
3919 { 51803, 103000 },
3920 { 51566, 102000 },
3921 { 51356, 101000 },
3922 { 51112, 100000 },
3923 { 50869, 99000 },
3924 { 50600, 98000 },
3925 { 50363, 97000 },
3926 { 50117, 96000 }, /* -35 dBm */
3927 { 49889, 95000 },
3928 { 49680, 94000 },
3929 { 49493, 93000 },
3930 { 49302, 92000 },
3931 { 48929, 91000 },
3932 { 48416, 90000 },
3933 { 48035, 89000 },
3934 { 47593, 88000 },
3935 { 47282, 87000 },
3936 { 46953, 86000 },
3937 { 46698, 85000 },
3938 { 45617, 84000 },
3939 { 44773, 83000 },
3940 { 43845, 82000 },
3941 { 43020, 81000 },
3942 { 42010, 80000 }, /* -51 dBm */
3943 { 0, 0 },
3944};
3945
3946static u32 interpolate_value(u32 value, struct linear_segments *segments,
3947 unsigned len)
3948{
3949 u64 tmp64;
3950 u32 dx;
3951 s32 dy;
3952 int i, ret;
3953
3954 if (value >= segments[0].x)
3955 return segments[0].y;
3956 if (value < segments[len-1].x)
3957 return segments[len-1].y;
3958
3959 for (i = 1; i < len - 1; i++) {
3960 /* If value is identical, no need to interpolate */
3961 if (value == segments[i].x)
3962 return segments[i].y;
3963 if (value > segments[i].x)
3964 break;
3965 }
3966
3967 /* Linear interpolation between the two (x,y) points */
3968 dy = segments[i - 1].y - segments[i].y;
3969 dx = segments[i - 1].x - segments[i].x;
3970
3971 tmp64 = value - segments[i].x;
3972 tmp64 *= dy;
3973 do_div(tmp64, dx);
3974 ret = segments[i].y + tmp64;
3975
3976 return ret;
3977}
3978
Mauro Carvalho Chehab704f01b2013-12-17 10:08:20 -03003979static u32 dib8000_get_time_us(struct dvb_frontend *fe, int layer)
3980{
3981 struct dib8000_state *state = fe->demodulator_priv;
3982 struct dtv_frontend_properties *c = &state->fe[0]->dtv_property_cache;
3983 int ini_layer, end_layer, i;
Mauro Carvalho Chehab4bf48152013-12-20 08:11:31 -02003984 u64 time_us, tmp64;
Mauro Carvalho Chehab704f01b2013-12-17 10:08:20 -03003985 u32 tmp, denom;
Mauro Carvalho Chehabe4a3bc12014-01-13 15:14:33 -02003986 int guard, rate_num, rate_denum = 1, bits_per_symbol, nsegs;
3987 int interleaving = 0, fft_div;
Mauro Carvalho Chehab704f01b2013-12-17 10:08:20 -03003988
3989 if (layer >= 0) {
3990 ini_layer = layer;
3991 end_layer = layer + 1;
3992 } else {
3993 ini_layer = 0;
3994 end_layer = 3;
3995 }
3996
3997 switch (c->guard_interval) {
3998 case GUARD_INTERVAL_1_4:
3999 guard = 4;
4000 break;
4001 case GUARD_INTERVAL_1_8:
4002 guard = 8;
4003 break;
4004 case GUARD_INTERVAL_1_16:
4005 guard = 16;
4006 break;
4007 default:
4008 case GUARD_INTERVAL_1_32:
4009 guard = 32;
4010 break;
4011 }
4012
4013 switch (c->transmission_mode) {
4014 case TRANSMISSION_MODE_2K:
4015 fft_div = 4;
4016 break;
4017 case TRANSMISSION_MODE_4K:
4018 fft_div = 2;
4019 break;
4020 default:
4021 case TRANSMISSION_MODE_8K:
4022 fft_div = 1;
4023 break;
4024 }
4025
4026 denom = 0;
4027 for (i = ini_layer; i < end_layer; i++) {
4028 nsegs = c->layer[i].segment_count;
4029 if (nsegs == 0 || nsegs > 13)
4030 continue;
4031
4032 switch (c->layer[i].modulation) {
4033 case DQPSK:
4034 case QPSK:
4035 bits_per_symbol = 2;
4036 break;
4037 case QAM_16:
4038 bits_per_symbol = 4;
4039 break;
4040 default:
4041 case QAM_64:
4042 bits_per_symbol = 6;
4043 break;
4044 }
4045
4046 switch (c->layer[i].fec) {
4047 case FEC_1_2:
4048 rate_num = 1;
4049 rate_denum = 2;
4050 break;
4051 case FEC_2_3:
4052 rate_num = 2;
4053 rate_denum = 3;
4054 break;
4055 case FEC_3_4:
4056 rate_num = 3;
4057 rate_denum = 4;
4058 break;
4059 case FEC_5_6:
4060 rate_num = 5;
4061 rate_denum = 6;
4062 break;
4063 default:
4064 case FEC_7_8:
4065 rate_num = 7;
4066 rate_denum = 8;
4067 break;
4068 }
4069
4070 interleaving = c->layer[i].interleaving;
4071
4072 denom += bits_per_symbol * rate_num * fft_div * nsegs * 384;
4073 }
4074
4075 /* If all goes wrong, wait for 1s for the next stats */
4076 if (!denom)
4077 return 0;
4078
4079 /* Estimate the period for the total bit rate */
4080 time_us = rate_denum * (1008 * 1562500L);
Mauro Carvalho Chehab4bf48152013-12-20 08:11:31 -02004081 tmp64 = time_us;
4082 do_div(tmp64, guard);
4083 time_us = time_us + tmp64;
Mauro Carvalho Chehab704f01b2013-12-17 10:08:20 -03004084 time_us += denom / 2;
4085 do_div(time_us, denom);
4086
4087 tmp = 1008 * 96 * interleaving;
4088 time_us += tmp + tmp / guard;
4089
4090 return time_us;
4091}
4092
Mauro Carvalho Chehab0df289a2015-06-07 14:53:52 -03004093static int dib8000_get_stats(struct dvb_frontend *fe, enum fe_status stat)
Mauro Carvalho Chehab6ef06e72013-12-16 19:10:59 -03004094{
4095 struct dib8000_state *state = fe->demodulator_priv;
4096 struct dtv_frontend_properties *c = &state->fe[0]->dtv_property_cache;
Mauro Carvalho Chehab704f01b2013-12-17 10:08:20 -03004097 int i;
Mauro Carvalho Chehab0400c532013-12-17 11:34:22 -03004098 int show_per_stats = 0;
4099 u32 time_us = 0, snr, val;
4100 u64 blocks;
Mauro Carvalho Chehab42ff76b2013-12-16 21:45:19 -03004101 s32 db;
Mauro Carvalho Chehab6ef06e72013-12-16 19:10:59 -03004102 u16 strength;
4103
4104 /* Get Signal strength */
4105 dib8000_read_signal_strength(fe, &strength);
Mauro Carvalho Chehab42ff76b2013-12-16 21:45:19 -03004106 val = strength;
4107 db = interpolate_value(val,
4108 strength_to_db_table,
4109 ARRAY_SIZE(strength_to_db_table)) - 131000;
4110 c->strength.stat[0].svalue = db;
Mauro Carvalho Chehab6ef06e72013-12-16 19:10:59 -03004111
Mauro Carvalho Chehab704f01b2013-12-17 10:08:20 -03004112 /* UCB/BER/CNR measures require lock */
Mauro Carvalho Chehab6ef06e72013-12-16 19:10:59 -03004113 if (!(stat & FE_HAS_LOCK)) {
Mauro Carvalho Chehab704f01b2013-12-17 10:08:20 -03004114 c->cnr.len = 1;
Mauro Carvalho Chehab0400c532013-12-17 11:34:22 -03004115 c->block_count.len = 1;
Mauro Carvalho Chehab6ef06e72013-12-16 19:10:59 -03004116 c->block_error.len = 1;
4117 c->post_bit_error.len = 1;
4118 c->post_bit_count.len = 1;
Mauro Carvalho Chehab704f01b2013-12-17 10:08:20 -03004119 c->cnr.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
Mauro Carvalho Chehab6ef06e72013-12-16 19:10:59 -03004120 c->post_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
4121 c->post_bit_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
4122 c->block_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
Mauro Carvalho Chehab0400c532013-12-17 11:34:22 -03004123 c->block_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
Mauro Carvalho Chehab6ef06e72013-12-16 19:10:59 -03004124 return 0;
4125 }
4126
Mauro Carvalho Chehab704f01b2013-12-17 10:08:20 -03004127 /* Check if time for stats was elapsed */
Mauro Carvalho Chehab0400c532013-12-17 11:34:22 -03004128 if (time_after(jiffies, state->per_jiffies_stats)) {
4129 state->per_jiffies_stats = jiffies + msecs_to_jiffies(1000);
Mauro Carvalho Chehab6ef06e72013-12-16 19:10:59 -03004130
Mauro Carvalho Chehab704f01b2013-12-17 10:08:20 -03004131 /* Get SNR */
4132 snr = dib8000_get_snr(fe);
4133 for (i = 1; i < MAX_NUMBER_OF_FRONTENDS; i++) {
4134 if (state->fe[i])
4135 snr += dib8000_get_snr(state->fe[i]);
4136 }
4137 snr = snr >> 16;
Mauro Carvalho Chehab6ef06e72013-12-16 19:10:59 -03004138
Mauro Carvalho Chehab704f01b2013-12-17 10:08:20 -03004139 if (snr) {
4140 snr = 10 * intlog10(snr);
4141 snr = (1000L * snr) >> 24;
4142 } else {
4143 snr = 0;
4144 }
4145 c->cnr.stat[0].svalue = snr;
4146 c->cnr.stat[0].scale = FE_SCALE_DECIBEL;
Mauro Carvalho Chehab6ef06e72013-12-16 19:10:59 -03004147
Mauro Carvalho Chehab0400c532013-12-17 11:34:22 -03004148 /* Get UCB measures */
4149 dib8000_read_unc_blocks(fe, &val);
4150 if (val < state->init_ucb)
Mauro Carvalho Chehab5dc85262014-01-13 15:05:44 -02004151 state->init_ucb += 0x100000000LL;
Mauro Carvalho Chehab0400c532013-12-17 11:34:22 -03004152
4153 c->block_error.stat[0].scale = FE_SCALE_COUNTER;
4154 c->block_error.stat[0].uvalue = val + state->init_ucb;
4155
4156 /* Estimate the number of packets based on bitrate */
4157 if (!time_us)
4158 time_us = dib8000_get_time_us(fe, -1);
4159
4160 if (time_us) {
Mauro Carvalho Chehab5dc85262014-01-13 15:05:44 -02004161 blocks = 1250000ULL * 1000000ULL;
Mauro Carvalho Chehab0400c532013-12-17 11:34:22 -03004162 do_div(blocks, time_us * 8 * 204);
4163 c->block_count.stat[0].scale = FE_SCALE_COUNTER;
4164 c->block_count.stat[0].uvalue += blocks;
4165 }
4166
4167 show_per_stats = 1;
4168 }
4169
4170 /* Get post-BER measures */
4171 if (time_after(jiffies, state->ber_jiffies_stats)) {
4172 time_us = dib8000_get_time_us(fe, -1);
4173 state->ber_jiffies_stats = jiffies + msecs_to_jiffies((time_us + 500) / 1000);
4174
4175 dprintk("Next all layers stats available in %u us.", time_us);
Mauro Carvalho Chehab704f01b2013-12-17 10:08:20 -03004176
4177 dib8000_read_ber(fe, &val);
4178 c->post_bit_error.stat[0].scale = FE_SCALE_COUNTER;
4179 c->post_bit_error.stat[0].uvalue += val;
4180
4181 c->post_bit_count.stat[0].scale = FE_SCALE_COUNTER;
4182 c->post_bit_count.stat[0].uvalue += 100000000;
Mauro Carvalho Chehab704f01b2013-12-17 10:08:20 -03004183 }
Mauro Carvalho Chehab6ef06e72013-12-16 19:10:59 -03004184
4185 if (state->revision < 0x8002)
4186 return 0;
4187
4188 c->block_error.len = 4;
4189 c->post_bit_error.len = 4;
4190 c->post_bit_count.len = 4;
4191
4192 for (i = 0; i < 3; i++) {
Mauro Carvalho Chehab0400c532013-12-17 11:34:22 -03004193 unsigned nsegs = c->layer[i].segment_count;
4194
4195 if (nsegs == 0 || nsegs > 13)
Mauro Carvalho Chehab704f01b2013-12-17 10:08:20 -03004196 continue;
Mauro Carvalho Chehab6ef06e72013-12-16 19:10:59 -03004197
Mauro Carvalho Chehab0400c532013-12-17 11:34:22 -03004198 time_us = 0;
Mauro Carvalho Chehab6ef06e72013-12-16 19:10:59 -03004199
Mauro Carvalho Chehab0400c532013-12-17 11:34:22 -03004200 if (time_after(jiffies, state->ber_jiffies_stats_layer[i])) {
4201 time_us = dib8000_get_time_us(fe, i);
Mauro Carvalho Chehab6ef06e72013-12-16 19:10:59 -03004202
Mauro Carvalho Chehab0400c532013-12-17 11:34:22 -03004203 state->ber_jiffies_stats_layer[i] = jiffies + msecs_to_jiffies((time_us + 500) / 1000);
4204 dprintk("Next layer %c stats will be available in %u us\n",
4205 'A' + i, time_us);
Mauro Carvalho Chehab704f01b2013-12-17 10:08:20 -03004206
Mauro Carvalho Chehab0400c532013-12-17 11:34:22 -03004207 val = dib8000_read_word(state, per_layer_regs[i].ber);
4208 c->post_bit_error.stat[1 + i].scale = FE_SCALE_COUNTER;
4209 c->post_bit_error.stat[1 + i].uvalue += val;
Mauro Carvalho Chehab704f01b2013-12-17 10:08:20 -03004210
Mauro Carvalho Chehab0400c532013-12-17 11:34:22 -03004211 c->post_bit_count.stat[1 + i].scale = FE_SCALE_COUNTER;
4212 c->post_bit_count.stat[1 + i].uvalue += 100000000;
4213 }
4214
4215 if (show_per_stats) {
4216 val = dib8000_read_word(state, per_layer_regs[i].per);
4217
4218 c->block_error.stat[1 + i].scale = FE_SCALE_COUNTER;
4219 c->block_error.stat[1 + i].uvalue += val;
4220
4221 if (!time_us)
4222 time_us = dib8000_get_time_us(fe, i);
4223 if (time_us) {
Mauro Carvalho Chehab5dc85262014-01-13 15:05:44 -02004224 blocks = 1250000ULL * 1000000ULL;
Mauro Carvalho Chehab0400c532013-12-17 11:34:22 -03004225 do_div(blocks, time_us * 8 * 204);
4226 c->block_count.stat[0].scale = FE_SCALE_COUNTER;
4227 c->block_count.stat[0].uvalue += blocks;
4228 }
4229 }
Mauro Carvalho Chehab6ef06e72013-12-16 19:10:59 -03004230 }
4231 return 0;
4232}
4233
Mauro Carvalho Chehabd44913c2014-05-29 09:20:17 -03004234static int dib8000_set_slave_frontend(struct dvb_frontend *fe, struct dvb_frontend *fe_slave)
Olivier Grenie4c70e072011-01-03 15:33:37 -03004235{
4236 struct dib8000_state *state = fe->demodulator_priv;
4237 u8 index_frontend = 1;
4238
4239 while ((index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL))
4240 index_frontend++;
4241 if (index_frontend < MAX_NUMBER_OF_FRONTENDS) {
4242 dprintk("set slave fe %p to index %i", fe_slave, index_frontend);
4243 state->fe[index_frontend] = fe_slave;
4244 return 0;
4245 }
4246
4247 dprintk("too many slave frontend");
4248 return -ENOMEM;
4249}
Olivier Grenie4c70e072011-01-03 15:33:37 -03004250
Mauro Carvalho Chehabd44913c2014-05-29 09:20:17 -03004251static int dib8000_remove_slave_frontend(struct dvb_frontend *fe)
Olivier Grenie4c70e072011-01-03 15:33:37 -03004252{
4253 struct dib8000_state *state = fe->demodulator_priv;
4254 u8 index_frontend = 1;
4255
4256 while ((index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL))
4257 index_frontend++;
4258 if (index_frontend != 1) {
4259 dprintk("remove slave fe %p (index %i)", state->fe[index_frontend-1], index_frontend-1);
4260 state->fe[index_frontend] = NULL;
4261 return 0;
4262 }
4263
4264 dprintk("no frontend to be removed");
4265 return -ENODEV;
4266}
Olivier Grenie4c70e072011-01-03 15:33:37 -03004267
Mauro Carvalho Chehabd44913c2014-05-29 09:20:17 -03004268static struct dvb_frontend *dib8000_get_slave_frontend(struct dvb_frontend *fe, int slave_index)
Olivier Grenie4c70e072011-01-03 15:33:37 -03004269{
4270 struct dib8000_state *state = fe->demodulator_priv;
4271
4272 if (slave_index >= MAX_NUMBER_OF_FRONTENDS)
4273 return NULL;
4274 return state->fe[slave_index];
4275}
Olivier Grenie4c70e072011-01-03 15:33:37 -03004276
Mauro Carvalho Chehabd44913c2014-05-29 09:20:17 -03004277static int dib8000_i2c_enumeration(struct i2c_adapter *host, int no_of_demods,
Olivier Grenie0c32dbd2011-08-10 05:17:18 -03004278 u8 default_addr, u8 first_addr, u8 is_dib8096p)
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03004279{
Olivier Grenie5a0deee2011-05-03 12:27:33 -03004280 int k = 0, ret = 0;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03004281 u8 new_addr = 0;
4282 struct i2c_device client = {.adap = host };
4283
Olivier Grenie5a0deee2011-05-03 12:27:33 -03004284 client.i2c_write_buffer = kzalloc(4 * sizeof(u8), GFP_KERNEL);
4285 if (!client.i2c_write_buffer) {
4286 dprintk("%s: not enough memory", __func__);
4287 return -ENOMEM;
4288 }
4289 client.i2c_read_buffer = kzalloc(4 * sizeof(u8), GFP_KERNEL);
4290 if (!client.i2c_read_buffer) {
4291 dprintk("%s: not enough memory", __func__);
4292 ret = -ENOMEM;
Patrick Boettcher79fcce32011-08-03 12:08:21 -03004293 goto error_memory_read;
Olivier Grenie5a0deee2011-05-03 12:27:33 -03004294 }
Patrick Boettcher79fcce32011-08-03 12:08:21 -03004295 client.i2c_buffer_lock = kzalloc(sizeof(struct mutex), GFP_KERNEL);
4296 if (!client.i2c_buffer_lock) {
4297 dprintk("%s: not enough memory", __func__);
4298 ret = -ENOMEM;
4299 goto error_memory_lock;
4300 }
4301 mutex_init(client.i2c_buffer_lock);
Olivier Grenie5a0deee2011-05-03 12:27:33 -03004302
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03004303 for (k = no_of_demods - 1; k >= 0; k--) {
4304 /* designated i2c address */
4305 new_addr = first_addr + (k << 1);
4306
4307 client.addr = new_addr;
Olivier Grenie0c32dbd2011-08-10 05:17:18 -03004308 if (!is_dib8096p)
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03004309 dib8000_i2c_write16(&client, 1287, 0x0003); /* sram lead in, rdy */
Olivier Grenie0c32dbd2011-08-10 05:17:18 -03004310 if (dib8000_identify(&client) == 0) {
4311 /* sram lead in, rdy */
4312 if (!is_dib8096p)
4313 dib8000_i2c_write16(&client, 1287, 0x0003);
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03004314 client.addr = default_addr;
4315 if (dib8000_identify(&client) == 0) {
4316 dprintk("#%d: not identified", k);
Olivier Grenie5a0deee2011-05-03 12:27:33 -03004317 ret = -EINVAL;
4318 goto error;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03004319 }
4320 }
4321
4322 /* start diversity to pull_down div_str - just for i2c-enumeration */
4323 dib8000_i2c_write16(&client, 1286, (1 << 10) | (4 << 6));
4324
4325 /* set new i2c address and force divstart */
4326 dib8000_i2c_write16(&client, 1285, (new_addr << 2) | 0x2);
4327 client.addr = new_addr;
4328 dib8000_identify(&client);
4329
4330 dprintk("IC %d initialized (to i2c_address 0x%x)", k, new_addr);
4331 }
4332
4333 for (k = 0; k < no_of_demods; k++) {
4334 new_addr = first_addr | (k << 1);
4335 client.addr = new_addr;
4336
4337 // unforce divstr
4338 dib8000_i2c_write16(&client, 1285, new_addr << 2);
4339
4340 /* deactivate div - it was just for i2c-enumeration */
4341 dib8000_i2c_write16(&client, 1286, 0);
4342 }
4343
Olivier Grenie5a0deee2011-05-03 12:27:33 -03004344error:
Patrick Boettcher79fcce32011-08-03 12:08:21 -03004345 kfree(client.i2c_buffer_lock);
4346error_memory_lock:
Olivier Grenie5a0deee2011-05-03 12:27:33 -03004347 kfree(client.i2c_read_buffer);
Patrick Boettcher79fcce32011-08-03 12:08:21 -03004348error_memory_read:
Olivier Grenie5a0deee2011-05-03 12:27:33 -03004349 kfree(client.i2c_write_buffer);
4350
4351 return ret;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03004352}
4353
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03004354static int dib8000_fe_get_tune_settings(struct dvb_frontend *fe, struct dvb_frontend_tune_settings *tune)
4355{
4356 tune->min_delay_ms = 1000;
4357 tune->step_size = 0;
4358 tune->max_drift = 0;
4359 return 0;
4360}
4361
4362static void dib8000_release(struct dvb_frontend *fe)
4363{
4364 struct dib8000_state *st = fe->demodulator_priv;
Olivier Grenie4c70e072011-01-03 15:33:37 -03004365 u8 index_frontend;
4366
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03004367 for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (st->fe[index_frontend] != NULL); index_frontend++)
Olivier Grenie4c70e072011-01-03 15:33:37 -03004368 dvb_frontend_detach(st->fe[index_frontend]);
4369
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03004370 dibx000_exit_i2c_master(&st->i2c_master);
Olivier Grenie0c32dbd2011-08-10 05:17:18 -03004371 i2c_del_adapter(&st->dib8096p_tuner_adap);
Olivier Grenie4c70e072011-01-03 15:33:37 -03004372 kfree(st->fe[0]);
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03004373 kfree(st);
4374}
4375
Mauro Carvalho Chehabd44913c2014-05-29 09:20:17 -03004376static 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 -03004377{
4378 struct dib8000_state *st = fe->demodulator_priv;
4379 return dibx000_get_i2c_adapter(&st->i2c_master, intf, gating);
4380}
4381
Mauro Carvalho Chehabd44913c2014-05-29 09:20:17 -03004382static int dib8000_pid_filter_ctrl(struct dvb_frontend *fe, u8 onoff)
Olivier Grenief8731f42009-09-18 04:08:43 -03004383{
4384 struct dib8000_state *st = fe->demodulator_priv;
Olivier Grenie4c70e072011-01-03 15:33:37 -03004385 u16 val = dib8000_read_word(st, 299) & 0xffef;
4386 val |= (onoff & 0x1) << 4;
Olivier Grenief8731f42009-09-18 04:08:43 -03004387
Olivier Grenie4c70e072011-01-03 15:33:37 -03004388 dprintk("pid filter enabled %d", onoff);
4389 return dib8000_write_word(st, 299, val);
Olivier Grenief8731f42009-09-18 04:08:43 -03004390}
Olivier Grenief8731f42009-09-18 04:08:43 -03004391
Mauro Carvalho Chehabd44913c2014-05-29 09:20:17 -03004392static int dib8000_pid_filter(struct dvb_frontend *fe, u8 id, u16 pid, u8 onoff)
Olivier Grenief8731f42009-09-18 04:08:43 -03004393{
4394 struct dib8000_state *st = fe->demodulator_priv;
Olivier Grenie4c70e072011-01-03 15:33:37 -03004395 dprintk("Index %x, PID %d, OnOff %d", id, pid, onoff);
4396 return dib8000_write_word(st, 305 + id, onoff ? (1 << 13) | pid : 0);
Olivier Grenief8731f42009-09-18 04:08:43 -03004397}
Olivier Grenief8731f42009-09-18 04:08:43 -03004398
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03004399static const struct dvb_frontend_ops dib8000_ops = {
Mauro Carvalho Chehab490ecd62011-12-22 20:38:27 -03004400 .delsys = { SYS_ISDBT },
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03004401 .info = {
4402 .name = "DiBcom 8000 ISDB-T",
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03004403 .frequency_min = 44250000,
4404 .frequency_max = 867250000,
4405 .frequency_stepsize = 62500,
4406 .caps = FE_CAN_INVERSION_AUTO |
4407 FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
4408 FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
4409 FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO |
4410 FE_CAN_TRANSMISSION_MODE_AUTO | FE_CAN_GUARD_INTERVAL_AUTO | FE_CAN_RECOVER | FE_CAN_HIERARCHY_AUTO,
4411 },
4412
4413 .release = dib8000_release,
4414
4415 .init = dib8000_wakeup,
4416 .sleep = dib8000_sleep,
4417
Mauro Carvalho Chehab490ecd62011-12-22 20:38:27 -03004418 .set_frontend = dib8000_set_frontend,
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03004419 .get_tune_settings = dib8000_fe_get_tune_settings,
Mauro Carvalho Chehab490ecd62011-12-22 20:38:27 -03004420 .get_frontend = dib8000_get_frontend,
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03004421
4422 .read_status = dib8000_read_status,
4423 .read_ber = dib8000_read_ber,
4424 .read_signal_strength = dib8000_read_signal_strength,
4425 .read_snr = dib8000_read_snr,
4426 .read_ucblocks = dib8000_read_unc_blocks,
4427};
4428
Mauro Carvalho Chehabd44913c2014-05-29 09:20:17 -03004429static struct dvb_frontend *dib8000_init(struct i2c_adapter *i2c_adap, u8 i2c_addr, struct dib8000_config *cfg)
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03004430{
4431 struct dvb_frontend *fe;
4432 struct dib8000_state *state;
4433
Mauro Carvalho Chehabb9bc7d52014-05-29 09:20:16 -03004434 dprintk("dib8000_init");
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03004435
4436 state = kzalloc(sizeof(struct dib8000_state), GFP_KERNEL);
4437 if (state == NULL)
4438 return NULL;
Olivier Grenie4c70e072011-01-03 15:33:37 -03004439 fe = kzalloc(sizeof(struct dvb_frontend), GFP_KERNEL);
4440 if (fe == NULL)
Dan Carpentered54c0e2011-01-19 11:27:58 -03004441 goto error;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03004442
4443 memcpy(&state->cfg, cfg, sizeof(struct dib8000_config));
4444 state->i2c.adap = i2c_adap;
4445 state->i2c.addr = i2c_addr;
Olivier Grenie5a0deee2011-05-03 12:27:33 -03004446 state->i2c.i2c_write_buffer = state->i2c_write_buffer;
4447 state->i2c.i2c_read_buffer = state->i2c_read_buffer;
Patrick Boettcher79fcce32011-08-03 12:08:21 -03004448 mutex_init(&state->i2c_buffer_lock);
4449 state->i2c.i2c_buffer_lock = &state->i2c_buffer_lock;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03004450 state->gpio_val = cfg->gpio_val;
4451 state->gpio_dir = cfg->gpio_dir;
4452
4453 /* Ensure the output mode remains at the previous default if it's
4454 * not specifically set by the caller.
4455 */
4456 if ((state->cfg.output_mode != OUTMODE_MPEG2_SERIAL) && (state->cfg.output_mode != OUTMODE_MPEG2_PAR_GATED_CLK))
4457 state->cfg.output_mode = OUTMODE_MPEG2_FIFO;
4458
Olivier Grenie4c70e072011-01-03 15:33:37 -03004459 state->fe[0] = fe;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03004460 fe->demodulator_priv = state;
Olivier Grenie4c70e072011-01-03 15:33:37 -03004461 memcpy(&state->fe[0]->ops, &dib8000_ops, sizeof(struct dvb_frontend_ops));
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03004462
4463 state->timf_default = cfg->pll->timf;
4464
4465 if (dib8000_identify(&state->i2c) == 0)
4466 goto error;
4467
4468 dibx000_init_i2c_master(&state->i2c_master, DIB8000, state->i2c.adap, state->i2c.addr);
4469
Olivier Grenie0c32dbd2011-08-10 05:17:18 -03004470 /* init 8096p tuner adapter */
4471 strncpy(state->dib8096p_tuner_adap.name, "DiB8096P tuner interface",
4472 sizeof(state->dib8096p_tuner_adap.name));
4473 state->dib8096p_tuner_adap.algo = &dib8096p_tuner_xfer_algo;
4474 state->dib8096p_tuner_adap.algo_data = NULL;
4475 state->dib8096p_tuner_adap.dev.parent = state->i2c.adap->dev.parent;
4476 i2c_set_adapdata(&state->dib8096p_tuner_adap, state);
4477 i2c_add_adapter(&state->dib8096p_tuner_adap);
4478
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03004479 dib8000_reset(fe);
4480
4481 dib8000_write_word(state, 285, (dib8000_read_word(state, 285) & ~0x60) | (3 << 5)); /* ber_rs_len = 3 */
Patrick Boettcher173a64c2013-04-22 12:45:52 -03004482 state->current_demod_bw = 6000;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03004483
4484 return fe;
4485
Patrick Boettcher173a64c2013-04-22 12:45:52 -03004486error:
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03004487 kfree(state);
4488 return NULL;
4489}
4490
Mauro Carvalho Chehabd44913c2014-05-29 09:20:17 -03004491void *dib8000_attach(struct dib8000_ops *ops)
4492{
4493 if (!ops)
4494 return NULL;
4495
4496 ops->pwm_agc_reset = dib8000_pwm_agc_reset;
4497 ops->get_dc_power = dib8090p_get_dc_power;
4498 ops->set_gpio = dib8000_set_gpio;
4499 ops->get_slave_frontend = dib8000_get_slave_frontend;
4500 ops->set_tune_state = dib8000_set_tune_state;
4501 ops->pid_filter_ctrl = dib8000_pid_filter_ctrl;
4502 ops->remove_slave_frontend = dib8000_remove_slave_frontend;
4503 ops->get_adc_power = dib8000_get_adc_power;
4504 ops->update_pll = dib8000_update_pll;
4505 ops->tuner_sleep = dib8096p_tuner_sleep;
4506 ops->get_tune_state = dib8000_get_tune_state;
4507 ops->get_i2c_tuner = dib8096p_get_i2c_tuner;
4508 ops->set_slave_frontend = dib8000_set_slave_frontend;
4509 ops->pid_filter = dib8000_pid_filter;
4510 ops->ctrl_timf = dib8000_ctrl_timf;
4511 ops->init = dib8000_init;
4512 ops->get_i2c_master = dib8000_get_i2c_master;
4513 ops->i2c_enumeration = dib8000_i2c_enumeration;
4514 ops->set_wbd_ref = dib8000_set_wbd_ref;
4515
4516 return ops;
4517}
4518EXPORT_SYMBOL(dib8000_attach);
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03004519
Patrick Boettcher99e44da2016-01-24 12:56:58 -02004520MODULE_AUTHOR("Olivier Grenie <Olivier.Grenie@parrot.com, Patrick Boettcher <patrick.boettcher@posteo.de>");
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03004521MODULE_DESCRIPTION("Driver for the DiBcom 8000 ISDB-T demodulator");
4522MODULE_LICENSE("GPL");