blob: 270a58e3e837c2a6b5b1b609d7ee39f1b8669e44 [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;
118 u32 timeout;
119 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
591 reg_907 |= (1 << 14) | (1 << 13) | (1 << 12);
592 reg_908 |= (1 << 5) | (1 << 4) | (1 << 3) | (1 << 2);
593 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);
Olivier Grenie0c32dbd2011-08-10 05:17:18 -03001053 if (state->revision == 0x8090)
1054 dib8000_write_word(state, 1280, 0x0045);
1055 else
1056 dib8000_write_word(state, 1280, 0x004d);
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001057 dib8000_write_word(state, 1281, 0x000c);
1058
1059 dib8000_write_word(state, 770, 0x0000);
1060 dib8000_write_word(state, 771, 0x0000);
1061 dib8000_write_word(state, 772, 0x0000);
1062 dib8000_write_word(state, 898, 0x0004); // sad
1063 dib8000_write_word(state, 1280, 0x0000);
1064 dib8000_write_word(state, 1281, 0x0000);
1065
1066 /* drives */
Olivier Grenie0c32dbd2011-08-10 05:17:18 -03001067 if (state->revision != 0x8090) {
1068 if (state->cfg.drives)
1069 dib8000_write_word(state, 906, state->cfg.drives);
1070 else {
1071 dprintk("using standard PAD-drive-settings, please adjust settings in config-struct to be optimal.");
1072 /* min drive SDRAM - not optimal - adjust */
1073 dib8000_write_word(state, 906, 0x2d98);
1074 }
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001075 }
1076
1077 dib8000_reset_pll(state);
Olivier Grenie0c32dbd2011-08-10 05:17:18 -03001078 if (state->revision != 0x8090)
1079 dib8000_write_word(state, 898, 0x0004);
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001080
1081 if (dib8000_reset_gpio(state) != 0)
1082 dprintk("GPIO reset was not successful.");
1083
Olivier Grenie0c32dbd2011-08-10 05:17:18 -03001084 if ((state->revision != 0x8090) &&
1085 (dib8000_set_output_mode(fe, OUTMODE_HIGH_Z) != 0))
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001086 dprintk("OUTPUT_MODE could not be resetted.");
1087
1088 state->current_agc = NULL;
1089
1090 // P_iqc_alpha_pha, P_iqc_alpha_amp, P_iqc_dcc_alpha, ...
1091 /* P_iqc_ca2 = 0; P_iqc_impnc_on = 0; P_iqc_mode = 0; */
1092 if (state->cfg.pll->ifreq == 0)
1093 dib8000_write_word(state, 40, 0x0755); /* P_iqc_corr_inh = 0 enable IQcorr block */
1094 else
1095 dib8000_write_word(state, 40, 0x1f55); /* P_iqc_corr_inh = 1 disable IQcorr block */
1096
1097 {
1098 u16 l = 0, r;
1099 const u16 *n;
1100 n = dib8000_defaults;
1101 l = *n++;
1102 while (l) {
1103 r = *n++;
1104 do {
1105 dib8000_write_word(state, r, *n++);
1106 r++;
1107 } while (--l);
1108 l = *n++;
1109 }
1110 }
Patrick Boettcher173a64c2013-04-22 12:45:52 -03001111
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001112 state->isdbt_cfg_loaded = 0;
1113
1114 //div_cfg override for special configs
Patrick Boettcher173a64c2013-04-22 12:45:52 -03001115 if ((state->revision != 8090) && (state->cfg.div_cfg != 0))
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001116 dib8000_write_word(state, 903, state->cfg.div_cfg);
1117
1118 /* unforce divstr regardless whether i2c enumeration was done or not */
1119 dib8000_write_word(state, 1285, dib8000_read_word(state, 1285) & ~(1 << 1));
1120
Olivier Grenie4c70e072011-01-03 15:33:37 -03001121 dib8000_set_bandwidth(fe, 6000);
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001122
1123 dib8000_set_adc_state(state, DIBX000_SLOW_ADC_ON);
Patrick Boettcher173a64c2013-04-22 12:45:52 -03001124 dib8000_sad_calib(state);
1125 if (state->revision != 0x8090)
Olivier Grenie0c32dbd2011-08-10 05:17:18 -03001126 dib8000_set_adc_state(state, DIBX000_SLOW_ADC_OFF);
Patrick Boettcher173a64c2013-04-22 12:45:52 -03001127
1128 /* ber_rs_len = 3 */
1129 dib8000_write_word(state, 285, (dib8000_read_word(state, 285) & ~0x60) | (3 << 5));
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001130
Olivier Grenie0c32dbd2011-08-10 05:17:18 -03001131 dib8000_set_power_mode(state, DIB8000_POWER_INTERFACE_ONLY);
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001132
Mauro Carvalho Chehab6ef06e72013-12-16 19:10:59 -03001133 dib8000_reset_stats(fe);
1134
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001135 return 0;
1136}
1137
1138static void dib8000_restart_agc(struct dib8000_state *state)
1139{
1140 // P_restart_iqc & P_restart_agc
1141 dib8000_write_word(state, 770, 0x0a00);
1142 dib8000_write_word(state, 770, 0x0000);
1143}
1144
1145static int dib8000_update_lna(struct dib8000_state *state)
1146{
1147 u16 dyn_gain;
1148
1149 if (state->cfg.update_lna) {
1150 // read dyn_gain here (because it is demod-dependent and not tuner)
1151 dyn_gain = dib8000_read_word(state, 390);
1152
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001153 if (state->cfg.update_lna(state->fe[0], dyn_gain)) {
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001154 dib8000_restart_agc(state);
1155 return 1;
1156 }
1157 }
1158 return 0;
1159}
1160
1161static int dib8000_set_agc_config(struct dib8000_state *state, u8 band)
1162{
1163 struct dibx000_agc_config *agc = NULL;
1164 int i;
Olivier Grenie0c32dbd2011-08-10 05:17:18 -03001165 u16 reg;
1166
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001167 if (state->current_band == band && state->current_agc != NULL)
1168 return 0;
1169 state->current_band = band;
1170
1171 for (i = 0; i < state->cfg.agc_config_count; i++)
1172 if (state->cfg.agc[i].band_caps & band) {
1173 agc = &state->cfg.agc[i];
1174 break;
1175 }
1176
1177 if (agc == NULL) {
1178 dprintk("no valid AGC configuration found for band 0x%02x", band);
1179 return -EINVAL;
1180 }
1181
1182 state->current_agc = agc;
1183
1184 /* AGC */
1185 dib8000_write_word(state, 76, agc->setup);
1186 dib8000_write_word(state, 77, agc->inv_gain);
1187 dib8000_write_word(state, 78, agc->time_stabiliz);
1188 dib8000_write_word(state, 101, (agc->alpha_level << 12) | agc->thlock);
1189
1190 // Demod AGC loop configuration
1191 dib8000_write_word(state, 102, (agc->alpha_mant << 5) | agc->alpha_exp);
1192 dib8000_write_word(state, 103, (agc->beta_mant << 6) | agc->beta_exp);
1193
1194 dprintk("WBD: ref: %d, sel: %d, active: %d, alpha: %d",
1195 state->wbd_ref != 0 ? state->wbd_ref : agc->wbd_ref, agc->wbd_sel, !agc->perform_agc_softsplit, agc->wbd_sel);
1196
1197 /* AGC continued */
1198 if (state->wbd_ref != 0)
1199 dib8000_write_word(state, 106, state->wbd_ref);
1200 else // use default
1201 dib8000_write_word(state, 106, agc->wbd_ref);
Olivier Grenie0c32dbd2011-08-10 05:17:18 -03001202
1203 if (state->revision == 0x8090) {
1204 reg = dib8000_read_word(state, 922) & (0x3 << 2);
1205 dib8000_write_word(state, 922, reg | (agc->wbd_sel << 2));
1206 }
1207
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001208 dib8000_write_word(state, 107, (agc->wbd_alpha << 9) | (agc->perform_agc_softsplit << 8));
1209 dib8000_write_word(state, 108, agc->agc1_max);
1210 dib8000_write_word(state, 109, agc->agc1_min);
1211 dib8000_write_word(state, 110, agc->agc2_max);
1212 dib8000_write_word(state, 111, agc->agc2_min);
1213 dib8000_write_word(state, 112, (agc->agc1_pt1 << 8) | agc->agc1_pt2);
1214 dib8000_write_word(state, 113, (agc->agc1_slope1 << 8) | agc->agc1_slope2);
1215 dib8000_write_word(state, 114, (agc->agc2_pt1 << 8) | agc->agc2_pt2);
1216 dib8000_write_word(state, 115, (agc->agc2_slope1 << 8) | agc->agc2_slope2);
1217
1218 dib8000_write_word(state, 75, agc->agc1_pt3);
Olivier Grenie0c32dbd2011-08-10 05:17:18 -03001219 if (state->revision != 0x8090)
1220 dib8000_write_word(state, 923,
1221 (dib8000_read_word(state, 923) & 0xffe3) |
1222 (agc->wbd_inv << 4) | (agc->wbd_sel << 2));
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001223
1224 return 0;
1225}
1226
Mauro Carvalho Chehabd44913c2014-05-29 09:20:17 -03001227static void dib8000_pwm_agc_reset(struct dvb_frontend *fe)
Olivier Grenie03245a52009-12-04 13:27:57 -03001228{
1229 struct dib8000_state *state = fe->demodulator_priv;
1230 dib8000_set_adc_state(state, DIBX000_ADC_ON);
1231 dib8000_set_agc_config(state, (unsigned char)(BAND_OF_FREQUENCY(fe->dtv_property_cache.frequency / 1000)));
1232}
Olivier Grenie03245a52009-12-04 13:27:57 -03001233
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001234static int dib8000_agc_soft_split(struct dib8000_state *state)
1235{
1236 u16 agc, split_offset;
1237
1238 if (!state->current_agc || !state->current_agc->perform_agc_softsplit || state->current_agc->split.max == 0)
1239 return FE_CALLBACK_TIME_NEVER;
1240
1241 // n_agc_global
1242 agc = dib8000_read_word(state, 390);
1243
1244 if (agc > state->current_agc->split.min_thres)
1245 split_offset = state->current_agc->split.min;
1246 else if (agc < state->current_agc->split.max_thres)
1247 split_offset = state->current_agc->split.max;
1248 else
1249 split_offset = state->current_agc->split.max *
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001250 (agc - state->current_agc->split.min_thres) /
1251 (state->current_agc->split.max_thres - state->current_agc->split.min_thres);
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001252
1253 dprintk("AGC split_offset: %d", split_offset);
1254
1255 // P_agc_force_split and P_agc_split_offset
1256 dib8000_write_word(state, 107, (dib8000_read_word(state, 107) & 0xff00) | split_offset);
1257 return 5000;
1258}
1259
1260static int dib8000_agc_startup(struct dvb_frontend *fe)
1261{
1262 struct dib8000_state *state = fe->demodulator_priv;
1263 enum frontend_tune_state *tune_state = &state->tune_state;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001264 int ret = 0;
Olivier Grenie0c32dbd2011-08-10 05:17:18 -03001265 u16 reg, upd_demod_gain_period = 0x8000;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001266
1267 switch (*tune_state) {
1268 case CT_AGC_START:
1269 // set power-up level: interf+analog+AGC
1270
Olivier Grenie0c32dbd2011-08-10 05:17:18 -03001271 if (state->revision != 0x8090)
1272 dib8000_set_adc_state(state, DIBX000_ADC_ON);
1273 else {
1274 dib8000_set_power_mode(state, DIB8000_POWER_ALL);
1275
1276 reg = dib8000_read_word(state, 1947)&0xff00;
1277 dib8000_write_word(state, 1946,
1278 upd_demod_gain_period & 0xFFFF);
1279 /* bit 14 = enDemodGain */
1280 dib8000_write_word(state, 1947, reg | (1<<14) |
1281 ((upd_demod_gain_period >> 16) & 0xFF));
1282
1283 /* enable adc i & q */
1284 reg = dib8000_read_word(state, 1920);
1285 dib8000_write_word(state, 1920, (reg | 0x3) &
1286 (~(1 << 7)));
1287 }
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001288
1289 if (dib8000_set_agc_config(state, (unsigned char)(BAND_OF_FREQUENCY(fe->dtv_property_cache.frequency / 1000))) != 0) {
1290 *tune_state = CT_AGC_STOP;
1291 state->status = FE_STATUS_TUNE_FAILED;
1292 break;
1293 }
1294
1295 ret = 70;
1296 *tune_state = CT_AGC_STEP_0;
1297 break;
1298
1299 case CT_AGC_STEP_0:
1300 //AGC initialization
1301 if (state->cfg.agc_control)
Olivier Grenie4c70e072011-01-03 15:33:37 -03001302 state->cfg.agc_control(fe, 1);
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001303
1304 dib8000_restart_agc(state);
1305
1306 // wait AGC rough lock time
1307 ret = 50;
1308 *tune_state = CT_AGC_STEP_1;
1309 break;
1310
1311 case CT_AGC_STEP_1:
1312 // wait AGC accurate lock time
1313 ret = 70;
1314
1315 if (dib8000_update_lna(state))
1316 // wait only AGC rough lock time
1317 ret = 50;
1318 else
1319 *tune_state = CT_AGC_STEP_2;
1320 break;
1321
1322 case CT_AGC_STEP_2:
1323 dib8000_agc_soft_split(state);
1324
1325 if (state->cfg.agc_control)
Olivier Grenie4c70e072011-01-03 15:33:37 -03001326 state->cfg.agc_control(fe, 0);
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001327
1328 *tune_state = CT_AGC_STOP;
1329 break;
1330 default:
1331 ret = dib8000_agc_soft_split(state);
1332 break;
1333 }
1334 return ret;
1335
1336}
1337
Olivier Grenie0c32dbd2011-08-10 05:17:18 -03001338static void dib8096p_host_bus_drive(struct dib8000_state *state, u8 drive)
1339{
1340 u16 reg;
1341
1342 drive &= 0x7;
1343
1344 /* drive host bus 2, 3, 4 */
1345 reg = dib8000_read_word(state, 1798) &
1346 ~(0x7 | (0x7 << 6) | (0x7 << 12));
1347 reg |= (drive<<12) | (drive<<6) | drive;
1348 dib8000_write_word(state, 1798, reg);
1349
1350 /* drive host bus 5,6 */
1351 reg = dib8000_read_word(state, 1799) & ~((0x7 << 2) | (0x7 << 8));
1352 reg |= (drive<<8) | (drive<<2);
1353 dib8000_write_word(state, 1799, reg);
1354
1355 /* drive host bus 7, 8, 9 */
1356 reg = dib8000_read_word(state, 1800) &
1357 ~(0x7 | (0x7 << 6) | (0x7 << 12));
1358 reg |= (drive<<12) | (drive<<6) | drive;
1359 dib8000_write_word(state, 1800, reg);
1360
1361 /* drive host bus 10, 11 */
1362 reg = dib8000_read_word(state, 1801) & ~((0x7 << 2) | (0x7 << 8));
1363 reg |= (drive<<8) | (drive<<2);
1364 dib8000_write_word(state, 1801, reg);
1365
1366 /* drive host bus 12, 13, 14 */
1367 reg = dib8000_read_word(state, 1802) &
1368 ~(0x7 | (0x7 << 6) | (0x7 << 12));
1369 reg |= (drive<<12) | (drive<<6) | drive;
1370 dib8000_write_word(state, 1802, reg);
1371}
1372
1373static u32 dib8096p_calcSyncFreq(u32 P_Kin, u32 P_Kout,
1374 u32 insertExtSynchro, u32 syncSize)
1375{
1376 u32 quantif = 3;
1377 u32 nom = (insertExtSynchro * P_Kin+syncSize);
1378 u32 denom = P_Kout;
1379 u32 syncFreq = ((nom << quantif) / denom);
1380
1381 if ((syncFreq & ((1 << quantif) - 1)) != 0)
1382 syncFreq = (syncFreq >> quantif) + 1;
1383 else
1384 syncFreq = (syncFreq >> quantif);
1385
1386 if (syncFreq != 0)
1387 syncFreq = syncFreq - 1;
1388
1389 return syncFreq;
1390}
1391
1392static void dib8096p_cfg_DibTx(struct dib8000_state *state, u32 P_Kin,
1393 u32 P_Kout, u32 insertExtSynchro, u32 synchroMode,
1394 u32 syncWord, u32 syncSize)
1395{
1396 dprintk("Configure DibStream Tx");
1397
1398 dib8000_write_word(state, 1615, 1);
1399 dib8000_write_word(state, 1603, P_Kin);
1400 dib8000_write_word(state, 1605, P_Kout);
1401 dib8000_write_word(state, 1606, insertExtSynchro);
1402 dib8000_write_word(state, 1608, synchroMode);
1403 dib8000_write_word(state, 1609, (syncWord >> 16) & 0xffff);
1404 dib8000_write_word(state, 1610, syncWord & 0xffff);
1405 dib8000_write_word(state, 1612, syncSize);
1406 dib8000_write_word(state, 1615, 0);
1407}
1408
1409static void dib8096p_cfg_DibRx(struct dib8000_state *state, u32 P_Kin,
1410 u32 P_Kout, u32 synchroMode, u32 insertExtSynchro,
1411 u32 syncWord, u32 syncSize, u32 dataOutRate)
1412{
1413 u32 syncFreq;
1414
1415 dprintk("Configure DibStream Rx synchroMode = %d", synchroMode);
1416
1417 if ((P_Kin != 0) && (P_Kout != 0)) {
1418 syncFreq = dib8096p_calcSyncFreq(P_Kin, P_Kout,
1419 insertExtSynchro, syncSize);
1420 dib8000_write_word(state, 1542, syncFreq);
1421 }
1422
1423 dib8000_write_word(state, 1554, 1);
1424 dib8000_write_word(state, 1536, P_Kin);
1425 dib8000_write_word(state, 1537, P_Kout);
1426 dib8000_write_word(state, 1539, synchroMode);
1427 dib8000_write_word(state, 1540, (syncWord >> 16) & 0xffff);
1428 dib8000_write_word(state, 1541, syncWord & 0xffff);
1429 dib8000_write_word(state, 1543, syncSize);
1430 dib8000_write_word(state, 1544, dataOutRate);
1431 dib8000_write_word(state, 1554, 0);
1432}
1433
1434static void dib8096p_enMpegMux(struct dib8000_state *state, int onoff)
1435{
1436 u16 reg_1287;
1437
1438 reg_1287 = dib8000_read_word(state, 1287);
1439
1440 switch (onoff) {
1441 case 1:
1442 reg_1287 &= ~(1 << 8);
1443 break;
1444 case 0:
1445 reg_1287 |= (1 << 8);
1446 break;
1447 }
1448
1449 dib8000_write_word(state, 1287, reg_1287);
1450}
1451
1452static void dib8096p_configMpegMux(struct dib8000_state *state,
1453 u16 pulseWidth, u16 enSerialMode, u16 enSerialClkDiv2)
1454{
1455 u16 reg_1287;
1456
1457 dprintk("Enable Mpeg mux");
1458
1459 dib8096p_enMpegMux(state, 0);
1460
1461 /* If the input mode is MPEG do not divide the serial clock */
1462 if ((enSerialMode == 1) && (state->input_mode_mpeg == 1))
1463 enSerialClkDiv2 = 0;
1464
1465 reg_1287 = ((pulseWidth & 0x1f) << 3) |
1466 ((enSerialMode & 0x1) << 2) | (enSerialClkDiv2 & 0x1);
1467 dib8000_write_word(state, 1287, reg_1287);
1468
1469 dib8096p_enMpegMux(state, 1);
1470}
1471
1472static void dib8096p_setDibTxMux(struct dib8000_state *state, int mode)
1473{
1474 u16 reg_1288 = dib8000_read_word(state, 1288) & ~(0x7 << 7);
1475
1476 switch (mode) {
1477 case MPEG_ON_DIBTX:
1478 dprintk("SET MPEG ON DIBSTREAM TX");
1479 dib8096p_cfg_DibTx(state, 8, 5, 0, 0, 0, 0);
1480 reg_1288 |= (1 << 9); break;
1481 case DIV_ON_DIBTX:
1482 dprintk("SET DIV_OUT ON DIBSTREAM TX");
1483 dib8096p_cfg_DibTx(state, 5, 5, 0, 0, 0, 0);
1484 reg_1288 |= (1 << 8); break;
1485 case ADC_ON_DIBTX:
1486 dprintk("SET ADC_OUT ON DIBSTREAM TX");
1487 dib8096p_cfg_DibTx(state, 20, 5, 10, 0, 0, 0);
1488 reg_1288 |= (1 << 7); break;
1489 default:
1490 break;
1491 }
1492 dib8000_write_word(state, 1288, reg_1288);
1493}
1494
1495static void dib8096p_setHostBusMux(struct dib8000_state *state, int mode)
1496{
1497 u16 reg_1288 = dib8000_read_word(state, 1288) & ~(0x7 << 4);
1498
1499 switch (mode) {
1500 case DEMOUT_ON_HOSTBUS:
1501 dprintk("SET DEM OUT OLD INTERF ON HOST BUS");
1502 dib8096p_enMpegMux(state, 0);
1503 reg_1288 |= (1 << 6);
1504 break;
1505 case DIBTX_ON_HOSTBUS:
1506 dprintk("SET DIBSTREAM TX ON HOST BUS");
1507 dib8096p_enMpegMux(state, 0);
1508 reg_1288 |= (1 << 5);
1509 break;
1510 case MPEG_ON_HOSTBUS:
1511 dprintk("SET MPEG MUX ON HOST BUS");
1512 reg_1288 |= (1 << 4);
1513 break;
1514 default:
1515 break;
1516 }
1517 dib8000_write_word(state, 1288, reg_1288);
1518}
1519
1520static int dib8096p_set_diversity_in(struct dvb_frontend *fe, int onoff)
1521{
1522 struct dib8000_state *state = fe->demodulator_priv;
1523 u16 reg_1287;
1524
1525 switch (onoff) {
1526 case 0: /* only use the internal way - not the diversity input */
1527 dprintk("%s mode OFF : by default Enable Mpeg INPUT",
1528 __func__);
1529 /* outputRate = 8 */
1530 dib8096p_cfg_DibRx(state, 8, 5, 0, 0, 0, 8, 0);
1531
1532 /* Do not divide the serial clock of MPEG MUX in
1533 SERIAL MODE in case input mode MPEG is used */
1534 reg_1287 = dib8000_read_word(state, 1287);
1535 /* enSerialClkDiv2 == 1 ? */
1536 if ((reg_1287 & 0x1) == 1) {
1537 /* force enSerialClkDiv2 = 0 */
1538 reg_1287 &= ~0x1;
1539 dib8000_write_word(state, 1287, reg_1287);
1540 }
1541 state->input_mode_mpeg = 1;
1542 break;
1543 case 1: /* both ways */
1544 case 2: /* only the diversity input */
1545 dprintk("%s ON : Enable diversity INPUT", __func__);
1546 dib8096p_cfg_DibRx(state, 5, 5, 0, 0, 0, 0, 0);
1547 state->input_mode_mpeg = 0;
1548 break;
1549 }
1550
1551 dib8000_set_diversity_in(state->fe[0], onoff);
1552 return 0;
1553}
1554
1555static int dib8096p_set_output_mode(struct dvb_frontend *fe, int mode)
1556{
1557 struct dib8000_state *state = fe->demodulator_priv;
1558 u16 outreg, smo_mode, fifo_threshold;
1559 u8 prefer_mpeg_mux_use = 1;
1560 int ret = 0;
1561
Patrick Boettcher173a64c2013-04-22 12:45:52 -03001562 state->output_mode = mode;
Olivier Grenie0c32dbd2011-08-10 05:17:18 -03001563 dib8096p_host_bus_drive(state, 1);
1564
1565 fifo_threshold = 1792;
1566 smo_mode = (dib8000_read_word(state, 299) & 0x0050) | (1 << 1);
1567 outreg = dib8000_read_word(state, 1286) &
1568 ~((1 << 10) | (0x7 << 6) | (1 << 1));
1569
1570 switch (mode) {
1571 case OUTMODE_HIGH_Z:
1572 outreg = 0;
1573 break;
1574
1575 case OUTMODE_MPEG2_SERIAL:
1576 if (prefer_mpeg_mux_use) {
1577 dprintk("dib8096P setting output mode TS_SERIAL using Mpeg Mux");
1578 dib8096p_configMpegMux(state, 3, 1, 1);
1579 dib8096p_setHostBusMux(state, MPEG_ON_HOSTBUS);
1580 } else {/* Use Smooth block */
1581 dprintk("dib8096P setting output mode TS_SERIAL using Smooth bloc");
1582 dib8096p_setHostBusMux(state,
1583 DEMOUT_ON_HOSTBUS);
1584 outreg |= (2 << 6) | (0 << 1);
1585 }
1586 break;
1587
1588 case OUTMODE_MPEG2_PAR_GATED_CLK:
1589 if (prefer_mpeg_mux_use) {
1590 dprintk("dib8096P setting output mode TS_PARALLEL_GATED using Mpeg Mux");
1591 dib8096p_configMpegMux(state, 2, 0, 0);
1592 dib8096p_setHostBusMux(state, MPEG_ON_HOSTBUS);
1593 } else { /* Use Smooth block */
1594 dprintk("dib8096P setting output mode TS_PARALLEL_GATED using Smooth block");
1595 dib8096p_setHostBusMux(state,
1596 DEMOUT_ON_HOSTBUS);
1597 outreg |= (0 << 6);
1598 }
1599 break;
1600
1601 case OUTMODE_MPEG2_PAR_CONT_CLK: /* Using Smooth block only */
1602 dprintk("dib8096P setting output mode TS_PARALLEL_CONT using Smooth block");
1603 dib8096p_setHostBusMux(state, DEMOUT_ON_HOSTBUS);
1604 outreg |= (1 << 6);
1605 break;
1606
1607 case OUTMODE_MPEG2_FIFO:
1608 /* Using Smooth block because not supported
1609 by new Mpeg Mux bloc */
1610 dprintk("dib8096P setting output mode TS_FIFO using Smooth block");
1611 dib8096p_setHostBusMux(state, DEMOUT_ON_HOSTBUS);
1612 outreg |= (5 << 6);
1613 smo_mode |= (3 << 1);
1614 fifo_threshold = 512;
1615 break;
1616
1617 case OUTMODE_DIVERSITY:
1618 dprintk("dib8096P setting output mode MODE_DIVERSITY");
1619 dib8096p_setDibTxMux(state, DIV_ON_DIBTX);
1620 dib8096p_setHostBusMux(state, DIBTX_ON_HOSTBUS);
1621 break;
1622
1623 case OUTMODE_ANALOG_ADC:
1624 dprintk("dib8096P setting output mode MODE_ANALOG_ADC");
1625 dib8096p_setDibTxMux(state, ADC_ON_DIBTX);
1626 dib8096p_setHostBusMux(state, DIBTX_ON_HOSTBUS);
1627 break;
1628 }
1629
1630 if (mode != OUTMODE_HIGH_Z)
1631 outreg |= (1<<10);
1632
1633 dprintk("output_mpeg2_in_188_bytes = %d",
1634 state->cfg.output_mpeg2_in_188_bytes);
1635 if (state->cfg.output_mpeg2_in_188_bytes)
1636 smo_mode |= (1 << 5);
1637
1638 ret |= dib8000_write_word(state, 299, smo_mode);
1639 /* synchronous fread */
1640 ret |= dib8000_write_word(state, 299 + 1, fifo_threshold);
1641 ret |= dib8000_write_word(state, 1286, outreg);
1642
1643 return ret;
1644}
1645
1646static int map_addr_to_serpar_number(struct i2c_msg *msg)
1647{
1648 if (msg->buf[0] <= 15)
1649 msg->buf[0] -= 1;
1650 else if (msg->buf[0] == 17)
1651 msg->buf[0] = 15;
1652 else if (msg->buf[0] == 16)
1653 msg->buf[0] = 17;
1654 else if (msg->buf[0] == 19)
1655 msg->buf[0] = 16;
1656 else if (msg->buf[0] >= 21 && msg->buf[0] <= 25)
1657 msg->buf[0] -= 3;
1658 else if (msg->buf[0] == 28)
1659 msg->buf[0] = 23;
1660 else if (msg->buf[0] == 99)
1661 msg->buf[0] = 99;
1662 else
1663 return -EINVAL;
1664 return 0;
1665}
1666
1667static int dib8096p_tuner_write_serpar(struct i2c_adapter *i2c_adap,
1668 struct i2c_msg msg[], int num)
1669{
1670 struct dib8000_state *state = i2c_get_adapdata(i2c_adap);
1671 u8 n_overflow = 1;
1672 u16 i = 1000;
1673 u16 serpar_num = msg[0].buf[0];
1674
1675 while (n_overflow == 1 && i) {
1676 n_overflow = (dib8000_read_word(state, 1984) >> 1) & 0x1;
1677 i--;
1678 if (i == 0)
1679 dprintk("Tuner ITF: write busy (overflow)");
1680 }
1681 dib8000_write_word(state, 1985, (1 << 6) | (serpar_num & 0x3f));
1682 dib8000_write_word(state, 1986, (msg[0].buf[1] << 8) | msg[0].buf[2]);
1683
1684 return num;
1685}
1686
1687static int dib8096p_tuner_read_serpar(struct i2c_adapter *i2c_adap,
1688 struct i2c_msg msg[], int num)
1689{
1690 struct dib8000_state *state = i2c_get_adapdata(i2c_adap);
1691 u8 n_overflow = 1, n_empty = 1;
1692 u16 i = 1000;
1693 u16 serpar_num = msg[0].buf[0];
1694 u16 read_word;
1695
1696 while (n_overflow == 1 && i) {
1697 n_overflow = (dib8000_read_word(state, 1984) >> 1) & 0x1;
1698 i--;
1699 if (i == 0)
1700 dprintk("TunerITF: read busy (overflow)");
1701 }
1702 dib8000_write_word(state, 1985, (0<<6) | (serpar_num&0x3f));
1703
1704 i = 1000;
1705 while (n_empty == 1 && i) {
1706 n_empty = dib8000_read_word(state, 1984)&0x1;
1707 i--;
1708 if (i == 0)
1709 dprintk("TunerITF: read busy (empty)");
1710 }
1711
1712 read_word = dib8000_read_word(state, 1987);
1713 msg[1].buf[0] = (read_word >> 8) & 0xff;
1714 msg[1].buf[1] = (read_word) & 0xff;
1715
1716 return num;
1717}
1718
1719static int dib8096p_tuner_rw_serpar(struct i2c_adapter *i2c_adap,
1720 struct i2c_msg msg[], int num)
1721{
1722 if (map_addr_to_serpar_number(&msg[0]) == 0) {
1723 if (num == 1) /* write */
1724 return dib8096p_tuner_write_serpar(i2c_adap, msg, 1);
1725 else /* read */
1726 return dib8096p_tuner_read_serpar(i2c_adap, msg, 2);
1727 }
1728 return num;
1729}
1730
1731static int dib8096p_rw_on_apb(struct i2c_adapter *i2c_adap,
1732 struct i2c_msg msg[], int num, u16 apb_address)
1733{
1734 struct dib8000_state *state = i2c_get_adapdata(i2c_adap);
1735 u16 word;
1736
1737 if (num == 1) { /* write */
1738 dib8000_write_word(state, apb_address,
1739 ((msg[0].buf[1] << 8) | (msg[0].buf[2])));
1740 } else {
1741 word = dib8000_read_word(state, apb_address);
1742 msg[1].buf[0] = (word >> 8) & 0xff;
1743 msg[1].buf[1] = (word) & 0xff;
1744 }
1745 return num;
1746}
1747
1748static int dib8096p_tuner_xfer(struct i2c_adapter *i2c_adap,
1749 struct i2c_msg msg[], int num)
1750{
1751 struct dib8000_state *state = i2c_get_adapdata(i2c_adap);
1752 u16 apb_address = 0, word;
1753 int i = 0;
1754
1755 switch (msg[0].buf[0]) {
1756 case 0x12:
1757 apb_address = 1920;
1758 break;
1759 case 0x14:
1760 apb_address = 1921;
1761 break;
1762 case 0x24:
1763 apb_address = 1922;
1764 break;
1765 case 0x1a:
1766 apb_address = 1923;
1767 break;
1768 case 0x22:
1769 apb_address = 1924;
1770 break;
1771 case 0x33:
1772 apb_address = 1926;
1773 break;
1774 case 0x34:
1775 apb_address = 1927;
1776 break;
1777 case 0x35:
1778 apb_address = 1928;
1779 break;
1780 case 0x36:
1781 apb_address = 1929;
1782 break;
1783 case 0x37:
1784 apb_address = 1930;
1785 break;
1786 case 0x38:
1787 apb_address = 1931;
1788 break;
1789 case 0x39:
1790 apb_address = 1932;
1791 break;
1792 case 0x2a:
1793 apb_address = 1935;
1794 break;
1795 case 0x2b:
1796 apb_address = 1936;
1797 break;
1798 case 0x2c:
1799 apb_address = 1937;
1800 break;
1801 case 0x2d:
1802 apb_address = 1938;
1803 break;
1804 case 0x2e:
1805 apb_address = 1939;
1806 break;
1807 case 0x2f:
1808 apb_address = 1940;
1809 break;
1810 case 0x30:
1811 apb_address = 1941;
1812 break;
1813 case 0x31:
1814 apb_address = 1942;
1815 break;
1816 case 0x32:
1817 apb_address = 1943;
1818 break;
1819 case 0x3e:
1820 apb_address = 1944;
1821 break;
1822 case 0x3f:
1823 apb_address = 1945;
1824 break;
1825 case 0x40:
1826 apb_address = 1948;
1827 break;
1828 case 0x25:
1829 apb_address = 936;
1830 break;
1831 case 0x26:
1832 apb_address = 937;
1833 break;
1834 case 0x27:
1835 apb_address = 938;
1836 break;
1837 case 0x28:
1838 apb_address = 939;
1839 break;
1840 case 0x1d:
1841 /* get sad sel request */
1842 i = ((dib8000_read_word(state, 921) >> 12)&0x3);
1843 word = dib8000_read_word(state, 924+i);
1844 msg[1].buf[0] = (word >> 8) & 0xff;
1845 msg[1].buf[1] = (word) & 0xff;
1846 return num;
1847 case 0x1f:
1848 if (num == 1) { /* write */
1849 word = (u16) ((msg[0].buf[1] << 8) |
1850 msg[0].buf[2]);
1851 /* in the VGAMODE Sel are located on bit 0/1 */
1852 word &= 0x3;
1853 word = (dib8000_read_word(state, 921) &
1854 ~(3<<12)) | (word<<12);
1855 /* Set the proper input */
1856 dib8000_write_word(state, 921, word);
1857 return num;
1858 }
1859 }
1860
1861 if (apb_address != 0) /* R/W acces via APB */
1862 return dib8096p_rw_on_apb(i2c_adap, msg, num, apb_address);
1863 else /* R/W access via SERPAR */
1864 return dib8096p_tuner_rw_serpar(i2c_adap, msg, num);
1865
1866 return 0;
1867}
1868
1869static u32 dib8096p_i2c_func(struct i2c_adapter *adapter)
1870{
1871 return I2C_FUNC_I2C;
1872}
1873
1874static struct i2c_algorithm dib8096p_tuner_xfer_algo = {
1875 .master_xfer = dib8096p_tuner_xfer,
1876 .functionality = dib8096p_i2c_func,
1877};
1878
Mauro Carvalho Chehabd44913c2014-05-29 09:20:17 -03001879static struct i2c_adapter *dib8096p_get_i2c_tuner(struct dvb_frontend *fe)
Olivier Grenie0c32dbd2011-08-10 05:17:18 -03001880{
1881 struct dib8000_state *st = fe->demodulator_priv;
1882 return &st->dib8096p_tuner_adap;
1883}
Olivier Grenie0c32dbd2011-08-10 05:17:18 -03001884
Mauro Carvalho Chehabd44913c2014-05-29 09:20:17 -03001885static int dib8096p_tuner_sleep(struct dvb_frontend *fe, int onoff)
Olivier Grenie0c32dbd2011-08-10 05:17:18 -03001886{
1887 struct dib8000_state *state = fe->demodulator_priv;
1888 u16 en_cur_state;
1889
1890 dprintk("sleep dib8096p: %d", onoff);
1891
1892 en_cur_state = dib8000_read_word(state, 1922);
1893
1894 /* LNAs and MIX are ON and therefore it is a valid configuration */
1895 if (en_cur_state > 0xff)
1896 state->tuner_enable = en_cur_state ;
1897
1898 if (onoff)
1899 en_cur_state &= 0x00ff;
1900 else {
1901 if (state->tuner_enable != 0)
1902 en_cur_state = state->tuner_enable;
1903 }
1904
1905 dib8000_write_word(state, 1922, en_cur_state);
1906
1907 return 0;
1908}
Olivier Grenie0c32dbd2011-08-10 05:17:18 -03001909
Olivier Grenie4c70e072011-01-03 15:33:37 -03001910static const s32 lut_1000ln_mant[] =
Olivier Grenie03245a52009-12-04 13:27:57 -03001911{
Olivier Grenie9c783032009-12-07 07:49:40 -03001912 908, 7003, 7090, 7170, 7244, 7313, 7377, 7438, 7495, 7549, 7600
Olivier Grenie03245a52009-12-04 13:27:57 -03001913};
1914
Mauro Carvalho Chehabd44913c2014-05-29 09:20:17 -03001915static s32 dib8000_get_adc_power(struct dvb_frontend *fe, u8 mode)
Olivier Grenie03245a52009-12-04 13:27:57 -03001916{
Olivier Grenie4c70e072011-01-03 15:33:37 -03001917 struct dib8000_state *state = fe->demodulator_priv;
1918 u32 ix = 0, tmp_val = 0, exp = 0, mant = 0;
1919 s32 val;
Olivier Grenie03245a52009-12-04 13:27:57 -03001920
Olivier Grenie4c70e072011-01-03 15:33:37 -03001921 val = dib8000_read32(state, 384);
Olivier Grenie4c70e072011-01-03 15:33:37 -03001922 if (mode) {
1923 tmp_val = val;
1924 while (tmp_val >>= 1)
1925 exp++;
1926 mant = (val * 1000 / (1<<exp));
1927 ix = (u8)((mant-1000)/100); /* index of the LUT */
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001928 val = (lut_1000ln_mant[ix] + 693*(exp-20) - 6908);
Olivier Grenie4c70e072011-01-03 15:33:37 -03001929 val = (val*256)/1000;
1930 }
1931 return val;
Olivier Grenie03245a52009-12-04 13:27:57 -03001932}
Olivier Grenie03245a52009-12-04 13:27:57 -03001933
Mauro Carvalho Chehabd44913c2014-05-29 09:20:17 -03001934static int dib8090p_get_dc_power(struct dvb_frontend *fe, u8 IQ)
Olivier Grenie0c32dbd2011-08-10 05:17:18 -03001935{
1936 struct dib8000_state *state = fe->demodulator_priv;
1937 int val = 0;
1938
1939 switch (IQ) {
1940 case 1:
1941 val = dib8000_read_word(state, 403);
1942 break;
1943 case 0:
1944 val = dib8000_read_word(state, 404);
1945 break;
1946 }
1947 if (val & 0x200)
1948 val -= 1024;
1949
1950 return val;
1951}
Olivier Grenie0c32dbd2011-08-10 05:17:18 -03001952
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001953static void dib8000_update_timf(struct dib8000_state *state)
1954{
1955 u32 timf = state->timf = dib8000_read32(state, 435);
1956
1957 dib8000_write_word(state, 29, (u16) (timf >> 16));
1958 dib8000_write_word(state, 30, (u16) (timf & 0xffff));
1959 dprintk("Updated timing frequency: %d (default: %d)", state->timf, state->timf_default);
1960}
1961
Mauro Carvalho Chehabd44913c2014-05-29 09:20:17 -03001962static u32 dib8000_ctrl_timf(struct dvb_frontend *fe, uint8_t op, uint32_t timf)
Olivier Grenie0c32dbd2011-08-10 05:17:18 -03001963{
1964 struct dib8000_state *state = fe->demodulator_priv;
1965
1966 switch (op) {
1967 case DEMOD_TIMF_SET:
1968 state->timf = timf;
1969 break;
1970 case DEMOD_TIMF_UPDATE:
1971 dib8000_update_timf(state);
1972 break;
1973 case DEMOD_TIMF_GET:
1974 break;
1975 }
1976 dib8000_set_bandwidth(state->fe[0], 6000);
1977
1978 return state->timf;
1979}
Olivier Grenie0c32dbd2011-08-10 05:17:18 -03001980
Olivier Grenie5a0deee2011-05-03 12:27:33 -03001981static const u16 adc_target_16dB[11] = {
1982 (1 << 13) - 825 - 117,
1983 (1 << 13) - 837 - 117,
1984 (1 << 13) - 811 - 117,
1985 (1 << 13) - 766 - 117,
1986 (1 << 13) - 737 - 117,
1987 (1 << 13) - 693 - 117,
1988 (1 << 13) - 648 - 117,
1989 (1 << 13) - 619 - 117,
1990 (1 << 13) - 575 - 117,
1991 (1 << 13) - 531 - 117,
1992 (1 << 13) - 501 - 117
1993};
1994static const u8 permu_seg[] = { 6, 5, 7, 4, 8, 3, 9, 2, 10, 1, 11, 0, 12 };
1995
Patrick Boettcher173a64c2013-04-22 12:45:52 -03001996static u16 dib8000_set_layer(struct dib8000_state *state, u8 layer_index, u16 max_constellation)
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001997{
Patrick Boettcher173a64c2013-04-22 12:45:52 -03001998 u8 cr, constellation, time_intlv;
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03001999 struct dtv_frontend_properties *c = &state->fe[0]->dtv_property_cache;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002000
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03002001 switch (c->layer[layer_index].modulation) {
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002002 case DQPSK:
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002003 constellation = 0;
2004 break;
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002005 case QPSK:
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002006 constellation = 1;
2007 break;
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002008 case QAM_16:
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002009 constellation = 2;
2010 break;
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002011 case QAM_64:
2012 default:
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002013 constellation = 3;
2014 break;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002015 }
2016
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03002017 switch (c->layer[layer_index].fec) {
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002018 case FEC_1_2:
2019 cr = 1;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002020 break;
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002021 case FEC_2_3:
2022 cr = 2;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002023 break;
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002024 case FEC_3_4:
2025 cr = 3;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002026 break;
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002027 case FEC_5_6:
2028 cr = 5;
2029 break;
2030 case FEC_7_8:
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002031 default:
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002032 cr = 7;
2033 break;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002034 }
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002035
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03002036 if ((c->layer[layer_index].interleaving > 0) && ((c->layer[layer_index].interleaving <= 3) || (c->layer[layer_index].interleaving == 4 && c->isdbt_sb_mode == 1)))
2037 time_intlv = c->layer[layer_index].interleaving;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002038 else
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002039 time_intlv = 0;
2040
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03002041 dib8000_write_word(state, 2 + layer_index, (constellation << 10) | ((c->layer[layer_index].segment_count & 0xf) << 6) | (cr << 3) | time_intlv);
2042 if (c->layer[layer_index].segment_count > 0) {
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002043 switch (max_constellation) {
2044 case DQPSK:
2045 case QPSK:
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03002046 if (c->layer[layer_index].modulation == QAM_16 || c->layer[layer_index].modulation == QAM_64)
2047 max_constellation = c->layer[layer_index].modulation;
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002048 break;
2049 case QAM_16:
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03002050 if (c->layer[layer_index].modulation == QAM_64)
2051 max_constellation = c->layer[layer_index].modulation;
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002052 break;
2053 }
2054 }
2055
2056 return max_constellation;
2057}
2058
2059static 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 */
2060static 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 */
2061static 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 */
2062static u16 dib8000_adp_fine_tune(struct dib8000_state *state, u16 max_constellation)
2063{
2064 u16 i, ana_gain = 0;
2065 const u16 *adp;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002066
2067 /* channel estimation fine configuration */
2068 switch (max_constellation) {
2069 case QAM_64:
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002070 ana_gain = 0x7;
2071 adp = &adp_Q64[0];
2072 break;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002073 case QAM_16:
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002074 ana_gain = 0x7;
2075 adp = &adp_Q16[0];
2076 break;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002077 default:
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002078 ana_gain = 0;
2079 adp = &adp_Qdefault[0];
2080 break;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002081 }
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002082
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002083 for (i = 0; i < 4; i++)
2084 dib8000_write_word(state, 215 + i, adp[i]);
2085
2086 return ana_gain;
2087}
2088
2089static void dib8000_update_ana_gain(struct dib8000_state *state, u16 ana_gain)
2090{
2091 u16 i;
2092
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002093 dib8000_write_word(state, 116, ana_gain);
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002094
2095 /* update ADC target depending on ana_gain */
2096 if (ana_gain) { /* set -16dB ADC target for ana_gain=-1 */
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002097 for (i = 0; i < 10; i++)
2098 dib8000_write_word(state, 80 + i, adc_target_16dB[i]);
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002099 } else { /* set -22dB ADC target for ana_gain=0 */
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002100 for (i = 0; i < 10; i++)
2101 dib8000_write_word(state, 80 + i, adc_target_16dB[i] - 355);
2102 }
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002103}
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002104
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002105static void dib8000_load_ana_fe_coefs(struct dib8000_state *state, const s16 *ana_fe)
2106{
2107 u16 mode = 0;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002108
2109 if (state->isdbt_cfg_loaded == 0)
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002110 for (mode = 0; mode < 24; mode++)
2111 dib8000_write_word(state, 117 + mode, ana_fe[mode]);
2112}
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002113
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002114static const u16 lut_prbs_2k[14] = {
2115 0, 0x423, 0x009, 0x5C7, 0x7A6, 0x3D8, 0x527, 0x7FF, 0x79B, 0x3D6, 0x3A2, 0x53B, 0x2F4, 0x213
2116};
2117static const u16 lut_prbs_4k[14] = {
2118 0, 0x208, 0x0C3, 0x7B9, 0x423, 0x5C7, 0x3D8, 0x7FF, 0x3D6, 0x53B, 0x213, 0x029, 0x0D0, 0x48E
2119};
2120static const u16 lut_prbs_8k[14] = {
2121 0, 0x740, 0x069, 0x7DD, 0x208, 0x7B9, 0x5C7, 0x7FF, 0x53B, 0x029, 0x48E, 0x4C4, 0x367, 0x684
2122};
2123
2124static u16 dib8000_get_init_prbs(struct dib8000_state *state, u16 subchannel)
2125{
2126 int sub_channel_prbs_group = 0;
2127
2128 sub_channel_prbs_group = (subchannel / 3) + 1;
2129 dprintk("sub_channel_prbs_group = %d , subchannel =%d prbs = 0x%04x", sub_channel_prbs_group, subchannel, lut_prbs_8k[sub_channel_prbs_group]);
2130
2131 switch (state->fe[0]->dtv_property_cache.transmission_mode) {
2132 case TRANSMISSION_MODE_2K:
2133 return lut_prbs_2k[sub_channel_prbs_group];
2134 case TRANSMISSION_MODE_4K:
2135 return lut_prbs_4k[sub_channel_prbs_group];
2136 default:
2137 case TRANSMISSION_MODE_8K:
2138 return lut_prbs_8k[sub_channel_prbs_group];
2139 }
2140}
2141
2142static void dib8000_set_13seg_channel(struct dib8000_state *state)
2143{
2144 u16 i;
2145 u16 coff_pow = 0x2800;
2146
2147 state->seg_mask = 0x1fff; /* All 13 segments enabled */
2148
2149 /* ---- COFF ---- Carloff, the most robust --- */
2150 if (state->isdbt_cfg_loaded == 0) { /* if not Sound Broadcasting mode : put default values for 13 segments */
2151 dib8000_write_word(state, 180, (16 << 6) | 9);
2152 dib8000_write_word(state, 187, (4 << 12) | (8 << 5) | 0x2);
2153 coff_pow = 0x2800;
2154 for (i = 0; i < 6; i++)
2155 dib8000_write_word(state, 181+i, coff_pow);
2156
2157 /* P_ctrl_corm_thres4pre_freq_inh=1, P_ctrl_pre_freq_mode_sat=1 */
2158 /* 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 */
2159 dib8000_write_word(state, 338, (1 << 12) | (1 << 10) | (0 << 9) | (3 << 5) | 1);
2160
2161 /* P_ctrl_pre_freq_win_len=8, P_ctrl_pre_freq_thres_lockin=6 */
2162 dib8000_write_word(state, 340, (8 << 6) | (6 << 0));
2163 /* P_ctrl_pre_freq_thres_lockout=4, P_small_use_tmcc/ac/cp=1 */
2164 dib8000_write_word(state, 341, (4 << 3) | (1 << 2) | (1 << 1) | (1 << 0));
2165
2166 dib8000_write_word(state, 228, 0); /* default value */
2167 dib8000_write_word(state, 265, 31); /* default value */
2168 dib8000_write_word(state, 205, 0x200f); /* init value */
2169 }
2170
2171 /*
2172 * make the cpil_coff_lock more robust but slower p_coff_winlen
2173 * 6bits; p_coff_thres_lock 6bits (for coff lock if needed)
2174 */
2175
2176 if (state->cfg.pll->ifreq == 0)
2177 dib8000_write_word(state, 266, ~state->seg_mask | state->seg_diff_mask | 0x40); /* P_equal_noise_seg_inh */
2178
2179 dib8000_load_ana_fe_coefs(state, ana_fe_coeff_13seg);
2180}
2181
2182static void dib8000_set_subchannel_prbs(struct dib8000_state *state, u16 init_prbs)
2183{
2184 u16 reg_1;
2185
2186 reg_1 = dib8000_read_word(state, 1);
2187 dib8000_write_word(state, 1, (init_prbs << 2) | (reg_1 & 0x3)); /* ADDR 1 */
2188}
2189
2190static void dib8000_small_fine_tune(struct dib8000_state *state)
2191{
2192 u16 i;
2193 const s16 *ncoeff;
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03002194 struct dtv_frontend_properties *c = &state->fe[0]->dtv_property_cache;
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002195
2196 dib8000_write_word(state, 352, state->seg_diff_mask);
2197 dib8000_write_word(state, 353, state->seg_mask);
2198
2199 /* 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 -03002200 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 -03002201
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03002202 if (c->isdbt_sb_mode) {
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002203 /* ---- SMALL ---- */
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03002204 switch (c->transmission_mode) {
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002205 case TRANSMISSION_MODE_2K:
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03002206 if (c->isdbt_partial_reception == 0) { /* 1-seg */
2207 if (c->layer[0].modulation == DQPSK) /* DQPSK */
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002208 ncoeff = coeff_2k_sb_1seg_dqpsk;
2209 else /* QPSK or QAM */
2210 ncoeff = coeff_2k_sb_1seg;
2211 } else { /* 3-segments */
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03002212 if (c->layer[0].modulation == DQPSK) { /* DQPSK on central segment */
2213 if (c->layer[1].modulation == DQPSK) /* DQPSK on external segments */
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002214 ncoeff = coeff_2k_sb_3seg_0dqpsk_1dqpsk;
2215 else /* QPSK or QAM on external segments */
2216 ncoeff = coeff_2k_sb_3seg_0dqpsk;
2217 } else { /* QPSK or QAM on central segment */
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03002218 if (c->layer[1].modulation == DQPSK) /* DQPSK on external segments */
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002219 ncoeff = coeff_2k_sb_3seg_1dqpsk;
2220 else /* QPSK or QAM on external segments */
2221 ncoeff = coeff_2k_sb_3seg;
2222 }
2223 }
2224 break;
2225 case TRANSMISSION_MODE_4K:
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03002226 if (c->isdbt_partial_reception == 0) { /* 1-seg */
2227 if (c->layer[0].modulation == DQPSK) /* DQPSK */
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002228 ncoeff = coeff_4k_sb_1seg_dqpsk;
2229 else /* QPSK or QAM */
2230 ncoeff = coeff_4k_sb_1seg;
2231 } else { /* 3-segments */
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03002232 if (c->layer[0].modulation == DQPSK) { /* DQPSK on central segment */
2233 if (c->layer[1].modulation == DQPSK) /* DQPSK on external segments */
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002234 ncoeff = coeff_4k_sb_3seg_0dqpsk_1dqpsk;
2235 else /* QPSK or QAM on external segments */
2236 ncoeff = coeff_4k_sb_3seg_0dqpsk;
2237 } else { /* QPSK or QAM on central segment */
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03002238 if (c->layer[1].modulation == DQPSK) /* DQPSK on external segments */
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002239 ncoeff = coeff_4k_sb_3seg_1dqpsk;
2240 else /* QPSK or QAM on external segments */
2241 ncoeff = coeff_4k_sb_3seg;
2242 }
2243 }
2244 break;
2245 case TRANSMISSION_MODE_AUTO:
2246 case TRANSMISSION_MODE_8K:
2247 default:
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03002248 if (c->isdbt_partial_reception == 0) { /* 1-seg */
2249 if (c->layer[0].modulation == DQPSK) /* DQPSK */
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002250 ncoeff = coeff_8k_sb_1seg_dqpsk;
2251 else /* QPSK or QAM */
2252 ncoeff = coeff_8k_sb_1seg;
2253 } else { /* 3-segments */
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03002254 if (c->layer[0].modulation == DQPSK) { /* DQPSK on central segment */
2255 if (c->layer[1].modulation == DQPSK) /* DQPSK on external segments */
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002256 ncoeff = coeff_8k_sb_3seg_0dqpsk_1dqpsk;
2257 else /* QPSK or QAM on external segments */
2258 ncoeff = coeff_8k_sb_3seg_0dqpsk;
2259 } else { /* QPSK or QAM on central segment */
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03002260 if (c->layer[1].modulation == DQPSK) /* DQPSK on external segments */
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002261 ncoeff = coeff_8k_sb_3seg_1dqpsk;
2262 else /* QPSK or QAM on external segments */
2263 ncoeff = coeff_8k_sb_3seg;
2264 }
2265 }
2266 break;
2267 }
2268
2269 for (i = 0; i < 8; i++)
2270 dib8000_write_word(state, 343 + i, ncoeff[i]);
2271 }
2272}
2273
2274static const u16 coff_thres_1seg[3] = {300, 150, 80};
2275static const u16 coff_thres_3seg[3] = {350, 300, 250};
2276static void dib8000_set_sb_channel(struct dib8000_state *state)
2277{
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03002278 struct dtv_frontend_properties *c = &state->fe[0]->dtv_property_cache;
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002279 const u16 *coff;
2280 u16 i;
2281
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03002282 if (c->transmission_mode == TRANSMISSION_MODE_2K || c->transmission_mode == TRANSMISSION_MODE_4K) {
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002283 dib8000_write_word(state, 219, dib8000_read_word(state, 219) | 0x1); /* adp_pass =1 */
2284 dib8000_write_word(state, 190, dib8000_read_word(state, 190) | (0x1 << 14)); /* pha3_force_pha_shift = 1 */
2285 } else {
2286 dib8000_write_word(state, 219, dib8000_read_word(state, 219) & 0xfffe); /* adp_pass =0 */
2287 dib8000_write_word(state, 190, dib8000_read_word(state, 190) & 0xbfff); /* pha3_force_pha_shift = 0 */
2288 }
2289
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03002290 if (c->isdbt_partial_reception == 1) /* 3-segments */
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002291 state->seg_mask = 0x00E0;
2292 else /* 1-segment */
2293 state->seg_mask = 0x0040;
2294
2295 dib8000_write_word(state, 268, (dib8000_read_word(state, 268) & 0xF9FF) | 0x0200);
2296
2297 /* ---- COFF ---- Carloff, the most robust --- */
2298 /* 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 -03002299 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 -03002300
2301 dib8000_write_word(state, 340, (16 << 6) | (8 << 0)); /* P_ctrl_pre_freq_win_len=16, P_ctrl_pre_freq_thres_lockin=8 */
2302 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 */
2303
2304 /* Sound Broadcasting mode 1 seg */
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03002305 if (c->isdbt_partial_reception == 0) {
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002306 /* 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) */
2307 if (state->mode == 3)
2308 dib8000_write_word(state, 180, 0x1fcf | ((state->mode - 1) << 14));
2309 else
2310 dib8000_write_word(state, 180, 0x0fcf | ((state->mode - 1) << 14));
2311
2312 /* 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 */
2313 dib8000_write_word(state, 338, (1 << 12) | (1 << 10) | (0 << 9) | (5 << 5) | 4);
2314 coff = &coff_thres_1seg[0];
2315 } else { /* Sound Broadcasting mode 3 seg */
2316 dib8000_write_word(state, 180, 0x1fcf | (1 << 14));
2317 /* 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 */
2318 dib8000_write_word(state, 338, (1 << 12) | (1 << 10) | (0 << 9) | (4 << 5) | 4);
2319 coff = &coff_thres_3seg[0];
2320 }
2321
2322 dib8000_write_word(state, 228, 1); /* P_2d_mode_byp=1 */
2323 dib8000_write_word(state, 205, dib8000_read_word(state, 205) & 0xfff0); /* P_cspu_win_cut = 0 */
2324
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03002325 if (c->isdbt_partial_reception == 0 && c->transmission_mode == TRANSMISSION_MODE_2K)
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002326 dib8000_write_word(state, 265, 15); /* P_equal_noise_sel = 15 */
2327
2328 /* Write COFF thres */
2329 for (i = 0 ; i < 3; i++) {
2330 dib8000_write_word(state, 181+i, coff[i]);
2331 dib8000_write_word(state, 184+i, coff[i]);
2332 }
2333
2334 /*
2335 * make the cpil_coff_lock more robust but slower p_coff_winlen
2336 * 6bits; p_coff_thres_lock 6bits (for coff lock if needed)
2337 */
2338
2339 dib8000_write_word(state, 266, ~state->seg_mask | state->seg_diff_mask); /* P_equal_noise_seg_inh */
2340
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03002341 if (c->isdbt_partial_reception == 0)
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002342 dib8000_write_word(state, 178, 64); /* P_fft_powrange = 64 */
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002343 else
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002344 dib8000_write_word(state, 178, 32); /* P_fft_powrange = 32 */
2345}
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002346
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002347static void dib8000_set_isdbt_common_channel(struct dib8000_state *state, u8 seq, u8 autosearching)
2348{
2349 u16 p_cfr_left_edge = 0, p_cfr_right_edge = 0;
2350 u16 tmcc_pow = 0, ana_gain = 0, tmp = 0, i = 0, nbseg_diff = 0 ;
2351 u16 max_constellation = DQPSK;
2352 int init_prbs;
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03002353 struct dtv_frontend_properties *c = &state->fe[0]->dtv_property_cache;
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002354
2355 /* P_mode */
2356 dib8000_write_word(state, 10, (seq << 4));
2357
2358 /* init mode */
2359 state->mode = fft_to_mode(state);
2360
2361 /* set guard */
2362 tmp = dib8000_read_word(state, 1);
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03002363 dib8000_write_word(state, 1, (tmp&0xfffc) | (c->guard_interval & 0x3));
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002364
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03002365 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 -03002366
2367 /* signal optimization parameter */
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03002368 if (c->isdbt_partial_reception) {
2369 state->seg_diff_mask = (c->layer[0].modulation == DQPSK) << permu_seg[0];
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002370 for (i = 1; 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+1];
2374 } else {
2375 for (i = 0; i < 3; i++)
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03002376 nbseg_diff += (c->layer[i].modulation == DQPSK) * c->layer[i].segment_count;
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002377 for (i = 0; i < nbseg_diff; i++)
2378 state->seg_diff_mask |= 1 << permu_seg[i];
2379 }
2380
2381 if (state->seg_diff_mask)
2382 dib8000_write_word(state, 268, (dib8000_read_word(state, 268) & 0xF9FF) | 0x0200);
2383 else
2384 dib8000_write_word(state, 268, (2 << 9) | 39); /*init value */
2385
2386 for (i = 0; i < 3; i++)
2387 max_constellation = dib8000_set_layer(state, i, max_constellation);
2388 if (autosearching == 0) {
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03002389 state->layer_b_nb_seg = c->layer[1].segment_count;
2390 state->layer_c_nb_seg = c->layer[2].segment_count;
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002391 }
2392
2393 /* WRITE: Mode & Diff mask */
2394 dib8000_write_word(state, 0, (state->mode << 13) | state->seg_diff_mask);
2395
2396 state->differential_constellation = (state->seg_diff_mask != 0);
2397
2398 /* channel estimation fine configuration */
2399 ana_gain = dib8000_adp_fine_tune(state, max_constellation);
2400
2401 /* update ana_gain depending on max constellation */
2402 dib8000_update_ana_gain(state, ana_gain);
2403
2404 /* ---- ANA_FE ---- */
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03002405 if (c->isdbt_partial_reception) /* 3-segments */
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002406 dib8000_load_ana_fe_coefs(state, ana_fe_coeff_3seg);
2407 else
2408 dib8000_load_ana_fe_coefs(state, ana_fe_coeff_1seg); /* 1-segment */
2409
2410 /* TSB or ISDBT ? apply it now */
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03002411 if (c->isdbt_sb_mode) {
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002412 dib8000_set_sb_channel(state);
Mauro Carvalho Chehab746f7ae2013-04-25 11:15:54 -03002413 if (c->isdbt_sb_subchannel < 14)
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03002414 init_prbs = dib8000_get_init_prbs(state, c->isdbt_sb_subchannel);
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002415 else
2416 init_prbs = 0;
2417 } else {
2418 dib8000_set_13seg_channel(state);
2419 init_prbs = 0xfff;
2420 }
2421
2422 /* SMALL */
2423 dib8000_small_fine_tune(state);
2424
2425 dib8000_set_subchannel_prbs(state, init_prbs);
2426
2427 /* ---- CHAN_BLK ---- */
2428 for (i = 0; i < 13; i++) {
2429 if ((((~state->seg_diff_mask) >> i) & 1) == 1) {
2430 p_cfr_left_edge += (1 << i) * ((i == 0) || ((((state->seg_mask & (~state->seg_diff_mask)) >> (i - 1)) & 1) == 0));
2431 p_cfr_right_edge += (1 << i) * ((i == 12) || ((((state->seg_mask & (~state->seg_diff_mask)) >> (i + 1)) & 1) == 0));
2432 }
2433 }
2434 dib8000_write_word(state, 222, p_cfr_left_edge); /* p_cfr_left_edge */
2435 dib8000_write_word(state, 223, p_cfr_right_edge); /* p_cfr_right_edge */
2436 /* "P_cspu_left_edge" & "P_cspu_right_edge" not used => do not care */
2437
2438 dib8000_write_word(state, 189, ~state->seg_mask | state->seg_diff_mask); /* P_lmod4_seg_inh */
2439 dib8000_write_word(state, 192, ~state->seg_mask | state->seg_diff_mask); /* P_pha3_seg_inh */
2440 dib8000_write_word(state, 225, ~state->seg_mask | state->seg_diff_mask); /* P_tac_seg_inh */
2441
2442 if (!autosearching)
2443 dib8000_write_word(state, 288, (~state->seg_mask | state->seg_diff_mask) & 0x1fff); /* P_tmcc_seg_eq_inh */
2444 else
2445 dib8000_write_word(state, 288, 0x1fff); /*disable equalisation of the tmcc when autosearch to be able to find the DQPSK channels. */
2446
2447 dib8000_write_word(state, 211, state->seg_mask & (~state->seg_diff_mask)); /* P_des_seg_enabled */
2448 dib8000_write_word(state, 287, ~state->seg_mask | 0x1000); /* P_tmcc_seg_inh */
2449
2450 dib8000_write_word(state, 178, 32); /* P_fft_powrange = 32 */
2451
2452 /* ---- TMCC ---- */
2453 for (i = 0; i < 3; i++)
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03002454 tmcc_pow += (((c->layer[i].modulation == DQPSK) * 4 + 1) * c->layer[i].segment_count) ;
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002455
2456 /* Quantif of "P_tmcc_dec_thres_?k" is (0, 5+mode, 9); */
2457 /* Threshold is set at 1/4 of max power. */
2458 tmcc_pow *= (1 << (9-2));
2459 dib8000_write_word(state, 290, tmcc_pow); /* P_tmcc_dec_thres_2k */
2460 dib8000_write_word(state, 291, tmcc_pow); /* P_tmcc_dec_thres_4k */
2461 dib8000_write_word(state, 292, tmcc_pow); /* P_tmcc_dec_thres_8k */
2462 /*dib8000_write_word(state, 287, (1 << 13) | 0x1000 ); */
2463
2464 /* ---- PHA3 ---- */
2465 if (state->isdbt_cfg_loaded == 0)
2466 dib8000_write_word(state, 250, 3285); /* p_2d_hspeed_thr0 */
2467
2468 state->isdbt_cfg_loaded = 0;
2469}
2470
Mauro Carvalho Chehab6f7ee062013-04-25 10:36:56 -03002471static u32 dib8000_wait_lock(struct dib8000_state *state, u32 internal,
2472 u32 wait0_ms, u32 wait1_ms, u32 wait2_ms)
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002473{
Mauro Carvalho Chehab13122f92013-04-25 15:22:20 -03002474 u32 value = 0; /* P_search_end0 wait time */
2475 u16 reg = 11; /* P_search_end0 start addr */
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002476
2477 for (reg = 11; reg < 16; reg += 2) {
2478 if (reg == 11) {
2479 if (state->revision == 0x8090)
Mauro Carvalho Chehab13122f92013-04-25 15:22:20 -03002480 value = internal * wait1_ms;
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002481 else
Mauro Carvalho Chehab13122f92013-04-25 15:22:20 -03002482 value = internal * wait0_ms;
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002483 } else if (reg == 13)
Mauro Carvalho Chehab13122f92013-04-25 15:22:20 -03002484 value = internal * wait1_ms;
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002485 else if (reg == 15)
Mauro Carvalho Chehab13122f92013-04-25 15:22:20 -03002486 value = internal * wait2_ms;
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002487 dib8000_write_word(state, reg, (u16)((value >> 16) & 0xffff));
2488 dib8000_write_word(state, (reg + 1), (u16)(value & 0xffff));
2489 }
2490 return value;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002491}
2492
2493static int dib8000_autosearch_start(struct dvb_frontend *fe)
2494{
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002495 struct dib8000_state *state = fe->demodulator_priv;
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03002496 struct dtv_frontend_properties *c = &state->fe[0]->dtv_property_cache;
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002497 u8 slist = 0;
2498 u32 value, internal = state->cfg.pll->internal;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002499
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002500 if (state->revision == 0x8090)
2501 internal = dib8000_read32(state, 23) / 1000;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002502
Olivier Grenied67350f2013-12-12 09:26:22 -03002503 if ((state->revision >= 0x8002) &&
2504 (state->autosearch_state == AS_SEARCHING_FFT)) {
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002505 dib8000_write_word(state, 37, 0x0065); /* P_ctrl_pha_off_max default values */
2506 dib8000_write_word(state, 116, 0x0000); /* P_ana_gain to 0 */
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002507
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002508 dib8000_write_word(state, 0, (dib8000_read_word(state, 0) & 0x1fff) | (0 << 13) | (1 << 15)); /* P_mode = 0, P_restart_search=1 */
2509 dib8000_write_word(state, 1, (dib8000_read_word(state, 1) & 0xfffc) | 0); /* P_guard = 0 */
2510 dib8000_write_word(state, 6, 0); /* P_lock0_mask = 0 */
2511 dib8000_write_word(state, 7, 0); /* P_lock1_mask = 0 */
2512 dib8000_write_word(state, 8, 0); /* P_lock2_mask = 0 */
2513 dib8000_write_word(state, 10, (dib8000_read_word(state, 10) & 0x200) | (16 << 4) | (0 << 0)); /* P_search_list=16, P_search_maxtrial=0 */
2514
2515 if (state->revision == 0x8090)
2516 value = dib8000_wait_lock(state, internal, 10, 10, 10); /* time in ms configure P_search_end0 P_search_end1 P_search_end2 */
2517 else
2518 value = dib8000_wait_lock(state, internal, 20, 20, 20); /* time in ms configure P_search_end0 P_search_end1 P_search_end2 */
2519
2520 dib8000_write_word(state, 17, 0);
2521 dib8000_write_word(state, 18, 200); /* P_search_rstst = 200 */
2522 dib8000_write_word(state, 19, 0);
2523 dib8000_write_word(state, 20, 400); /* P_search_rstend = 400 */
2524 dib8000_write_word(state, 21, (value >> 16) & 0xffff); /* P_search_checkst */
2525 dib8000_write_word(state, 22, value & 0xffff);
2526
2527 if (state->revision == 0x8090)
2528 dib8000_write_word(state, 32, (dib8000_read_word(state, 32) & 0xf0ff) | (0 << 8)); /* P_corm_alpha = 0 */
2529 else
2530 dib8000_write_word(state, 32, (dib8000_read_word(state, 32) & 0xf0ff) | (9 << 8)); /* P_corm_alpha = 3 */
2531 dib8000_write_word(state, 355, 2); /* P_search_param_max = 2 */
2532
2533 /* P_search_param_select = (1 | 1<<4 | 1 << 8) */
2534 dib8000_write_word(state, 356, 0);
2535 dib8000_write_word(state, 357, 0x111);
2536
2537 dib8000_write_word(state, 770, (dib8000_read_word(state, 770) & 0xdfff) | (1 << 13)); /* P_restart_ccg = 1 */
2538 dib8000_write_word(state, 770, (dib8000_read_word(state, 770) & 0xdfff) | (0 << 13)); /* P_restart_ccg = 0 */
2539 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 -03002540 } else if ((state->revision >= 0x8002) &&
2541 (state->autosearch_state == AS_SEARCHING_GUARD)) {
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03002542 c->transmission_mode = TRANSMISSION_MODE_8K;
2543 c->guard_interval = GUARD_INTERVAL_1_8;
2544 c->inversion = 0;
2545 c->layer[0].modulation = QAM_64;
2546 c->layer[0].fec = FEC_2_3;
2547 c->layer[0].interleaving = 0;
2548 c->layer[0].segment_count = 13;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002549
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002550 slist = 16;
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03002551 c->transmission_mode = state->found_nfft;
Patrick Boettcher78f3bc62009-08-17 12:53:51 -03002552
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002553 dib8000_set_isdbt_common_channel(state, slist, 1);
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002554
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002555 /* set lock_mask values */
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002556 dib8000_write_word(state, 6, 0x4);
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002557 if (state->revision == 0x8090)
2558 dib8000_write_word(state, 7, ((1 << 12) | (1 << 11) | (1 << 10)));/* tmcc_dec_lock, tmcc_sync_lock, tmcc_data_lock, tmcc_bch_uncor */
2559 else
2560 dib8000_write_word(state, 7, 0x8);
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002561 dib8000_write_word(state, 8, 0x1000);
2562
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002563 /* set lock_mask wait time values */
2564 if (state->revision == 0x8090)
2565 dib8000_wait_lock(state, internal, 50, 100, 1000); /* time in ms configure P_search_end0 P_search_end1 P_search_end2 */
2566 else
2567 dib8000_wait_lock(state, internal, 50, 200, 1000); /* time in ms configure P_search_end0 P_search_end1 P_search_end2 */
2568
2569 dib8000_write_word(state, 355, 3); /* P_search_param_max = 3 */
2570
2571 /* P_search_param_select = 0xf; look for the 4 different guard intervals */
2572 dib8000_write_word(state, 356, 0);
2573 dib8000_write_word(state, 357, 0xf);
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002574
2575 value = dib8000_read_word(state, 0);
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002576 dib8000_write_word(state, 0, (u16)((1 << 15) | value));
2577 dib8000_read_word(state, 1284); /* reset the INT. n_irq_pending */
2578 dib8000_write_word(state, 0, (u16)value);
2579 } else {
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03002580 c->inversion = 0;
2581 c->layer[0].modulation = QAM_64;
2582 c->layer[0].fec = FEC_2_3;
2583 c->layer[0].interleaving = 0;
2584 c->layer[0].segment_count = 13;
2585 if (!c->isdbt_sb_mode)
2586 c->layer[0].segment_count = 13;
Patrick Boettcher78f3bc62009-08-17 12:53:51 -03002587
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002588 /* choose the right list, in sb, always do everything */
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03002589 if (c->isdbt_sb_mode) {
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002590 slist = 7;
2591 dib8000_write_word(state, 0, (dib8000_read_word(state, 0) & 0x9fff) | (1 << 13));
2592 } else {
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03002593 if (c->guard_interval == GUARD_INTERVAL_AUTO) {
2594 if (c->transmission_mode == TRANSMISSION_MODE_AUTO) {
2595 c->transmission_mode = TRANSMISSION_MODE_8K;
2596 c->guard_interval = GUARD_INTERVAL_1_8;
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002597 slist = 7;
2598 dib8000_write_word(state, 0, (dib8000_read_word(state, 0) & 0x9fff) | (1 << 13)); /* P_mode = 1 to have autosearch start ok with mode2 */
2599 } else {
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03002600 c->guard_interval = GUARD_INTERVAL_1_8;
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002601 slist = 3;
2602 }
2603 } else {
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03002604 if (c->transmission_mode == TRANSMISSION_MODE_AUTO) {
2605 c->transmission_mode = TRANSMISSION_MODE_8K;
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002606 slist = 2;
2607 dib8000_write_word(state, 0, (dib8000_read_word(state, 0) & 0x9fff) | (1 << 13)); /* P_mode = 1 */
2608 } else
2609 slist = 0;
2610 }
2611 }
2612 dprintk("Using list for autosearch : %d", slist);
2613
2614 dib8000_set_isdbt_common_channel(state, slist, 1);
2615
2616 /* set lock_mask values */
2617 dib8000_write_word(state, 6, 0x4);
2618 if (state->revision == 0x8090)
2619 dib8000_write_word(state, 7, (1 << 12) | (1 << 11) | (1 << 10));
2620 else
2621 dib8000_write_word(state, 7, 0x8);
2622 dib8000_write_word(state, 8, 0x1000);
2623
2624 /* set lock_mask wait time values */
2625 if (state->revision == 0x8090)
2626 dib8000_wait_lock(state, internal, 50, 200, 1000); /* time in ms configure P_search_end0 P_search_end1 P_search_end2 */
2627 else
2628 dib8000_wait_lock(state, internal, 50, 100, 1000); /* time in ms configure P_search_end0 P_search_end1 P_search_end2 */
2629
2630 value = dib8000_read_word(state, 0);
2631 dib8000_write_word(state, 0, (u16)((1 << 15) | value));
2632 dib8000_read_word(state, 1284); /* reset the INT. n_irq_pending */
2633 dib8000_write_word(state, 0, (u16)value);
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002634 }
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002635 return 0;
2636}
2637
2638static int dib8000_autosearch_irq(struct dvb_frontend *fe)
2639{
2640 struct dib8000_state *state = fe->demodulator_priv;
2641 u16 irq_pending = dib8000_read_word(state, 1284);
2642
Olivier Grenied67350f2013-12-12 09:26:22 -03002643 if ((state->revision >= 0x8002) &&
2644 (state->autosearch_state == AS_SEARCHING_FFT)) {
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002645 if (irq_pending & 0x1) {
2646 dprintk("dib8000_autosearch_irq: max correlation result available");
2647 return 3;
2648 }
2649 } else {
2650 if (irq_pending & 0x1) { /* failed */
2651 dprintk("dib8000_autosearch_irq failed");
2652 return 1;
2653 }
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002654
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002655 if (irq_pending & 0x2) { /* succeeded */
2656 dprintk("dib8000_autosearch_irq succeeded");
2657 return 2;
2658 }
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002659 }
2660
2661 return 0; // still pending
2662}
2663
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002664static void dib8000_viterbi_state(struct dib8000_state *state, u8 onoff)
2665{
2666 u16 tmp;
2667
2668 tmp = dib8000_read_word(state, 771);
2669 if (onoff) /* start P_restart_chd : channel_decoder */
2670 dib8000_write_word(state, 771, tmp & 0xfffd);
2671 else /* stop P_restart_chd : channel_decoder */
2672 dib8000_write_word(state, 771, tmp | (1<<1));
2673}
2674
2675static void dib8000_set_dds(struct dib8000_state *state, s32 offset_khz)
2676{
2677 s16 unit_khz_dds_val;
2678 u32 abs_offset_khz = ABS(offset_khz);
2679 u32 dds = state->cfg.pll->ifreq & 0x1ffffff;
2680 u8 invert = !!(state->cfg.pll->ifreq & (1 << 25));
2681 u8 ratio;
2682
2683 if (state->revision == 0x8090) {
2684 ratio = 4;
2685 unit_khz_dds_val = (1<<26) / (dib8000_read32(state, 23) / 1000);
2686 if (offset_khz < 0)
2687 dds = (1 << 26) - (abs_offset_khz * unit_khz_dds_val);
2688 else
2689 dds = (abs_offset_khz * unit_khz_dds_val);
2690
2691 if (invert)
2692 dds = (1<<26) - dds;
2693 } else {
2694 ratio = 2;
2695 unit_khz_dds_val = (u16) (67108864 / state->cfg.pll->internal);
2696
2697 if (offset_khz < 0)
2698 unit_khz_dds_val *= -1;
2699
2700 /* IF tuner */
2701 if (invert)
2702 dds -= abs_offset_khz * unit_khz_dds_val;
2703 else
2704 dds += abs_offset_khz * unit_khz_dds_val;
2705 }
2706
2707 dprintk("setting a DDS frequency offset of %c%dkHz", invert ? '-' : ' ', dds / unit_khz_dds_val);
2708
2709 if (abs_offset_khz <= (state->cfg.pll->internal / ratio)) {
2710 /* Max dds offset is the half of the demod freq */
2711 dib8000_write_word(state, 26, invert);
2712 dib8000_write_word(state, 27, (u16)(dds >> 16) & 0x1ff);
2713 dib8000_write_word(state, 28, (u16)(dds & 0xffff));
2714 }
2715}
2716
2717static void dib8000_set_frequency_offset(struct dib8000_state *state)
2718{
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03002719 struct dtv_frontend_properties *c = &state->fe[0]->dtv_property_cache;
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002720 int i;
2721 u32 current_rf;
2722 int total_dds_offset_khz;
2723
2724 if (state->fe[0]->ops.tuner_ops.get_frequency)
2725 state->fe[0]->ops.tuner_ops.get_frequency(state->fe[0], &current_rf);
2726 else
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03002727 current_rf = c->frequency;
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002728 current_rf /= 1000;
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03002729 total_dds_offset_khz = (int)current_rf - (int)c->frequency / 1000;
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002730
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03002731 if (c->isdbt_sb_mode) {
2732 state->subchannel = c->isdbt_sb_subchannel;
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002733
2734 i = dib8000_read_word(state, 26) & 1; /* P_dds_invspec */
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03002735 dib8000_write_word(state, 26, c->inversion ^ i);
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002736
2737 if (state->cfg.pll->ifreq == 0) { /* low if tuner */
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03002738 if ((c->inversion ^ i) == 0)
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002739 dib8000_write_word(state, 26, dib8000_read_word(state, 26) | 1);
2740 } else {
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03002741 if ((c->inversion ^ i) == 0)
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002742 total_dds_offset_khz *= -1;
2743 }
2744 }
2745
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03002746 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 -03002747
2748 /* apply dds offset now */
2749 dib8000_set_dds(state, total_dds_offset_khz);
2750}
2751
2752static u16 LUT_isdbt_symbol_duration[4] = { 26, 101, 63 };
Mauro Carvalho Chehab6f7ee062013-04-25 10:36:56 -03002753
2754static u32 dib8000_get_symbol_duration(struct dib8000_state *state)
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002755{
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03002756 struct dtv_frontend_properties *c = &state->fe[0]->dtv_property_cache;
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002757 u16 i;
2758
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03002759 switch (c->transmission_mode) {
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002760 case TRANSMISSION_MODE_2K:
2761 i = 0;
2762 break;
2763 case TRANSMISSION_MODE_4K:
2764 i = 2;
2765 break;
2766 default:
2767 case TRANSMISSION_MODE_AUTO:
2768 case TRANSMISSION_MODE_8K:
2769 i = 1;
2770 break;
2771 }
2772
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03002773 return (LUT_isdbt_symbol_duration[i] / (c->bandwidth_hz / 1000)) + 1;
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002774}
2775
2776static void dib8000_set_isdbt_loop_params(struct dib8000_state *state, enum param_loop_step loop_step)
2777{
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03002778 struct dtv_frontend_properties *c = &state->fe[0]->dtv_property_cache;
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002779 u16 reg_32 = 0, reg_37 = 0;
2780
2781 switch (loop_step) {
2782 case LOOP_TUNE_1:
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03002783 if (c->isdbt_sb_mode) {
2784 if (c->isdbt_partial_reception == 0) {
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002785 reg_32 = ((11 - state->mode) << 12) | (6 << 8) | 0x40; /* P_timf_alpha = (11-P_mode), P_corm_alpha=6, P_corm_thres=0x40 */
2786 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) */
2787 } else { /* Sound Broadcasting mode 3 seg */
2788 reg_32 = ((10 - state->mode) << 12) | (6 << 8) | 0x60; /* P_timf_alpha = (10-P_mode), P_corm_alpha=6, P_corm_thres=0x60 */
2789 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) */
2790 }
2791 } else { /* 13-seg start conf offset loop parameters */
2792 reg_32 = ((9 - state->mode) << 12) | (6 << 8) | 0x80; /* P_timf_alpha = (9-P_mode, P_corm_alpha=6, P_corm_thres=0x80 */
2793 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 */
2794 }
2795 break;
2796 case LOOP_TUNE_2:
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03002797 if (c->isdbt_sb_mode) {
2798 if (c->isdbt_partial_reception == 0) { /* Sound Broadcasting mode 1 seg */
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002799 reg_32 = ((13-state->mode) << 12) | (6 << 8) | 0x40; /* P_timf_alpha = (13-P_mode) , P_corm_alpha=6, P_corm_thres=0x40*/
2800 reg_37 = (12-state->mode) | ((5 + state->mode) << 5);
2801 } else { /* Sound Broadcasting mode 3 seg */
2802 reg_32 = ((12-state->mode) << 12) | (6 << 8) | 0x60; /* P_timf_alpha = (12-P_mode) , P_corm_alpha=6, P_corm_thres=0x60 */
2803 reg_37 = (11-state->mode) | ((5 + state->mode) << 5);
2804 }
2805 } else { /* 13 seg */
2806 reg_32 = ((11-state->mode) << 12) | (6 << 8) | 0x80; /* P_timf_alpha = 8 , P_corm_alpha=6, P_corm_thres=0x80 */
2807 reg_37 = ((5+state->mode) << 5) | (10 - state->mode);
2808 }
2809 break;
2810 }
2811 dib8000_write_word(state, 32, reg_32);
2812 dib8000_write_word(state, 37, reg_37);
2813}
2814
2815static void dib8000_demod_restart(struct dib8000_state *state)
2816{
2817 dib8000_write_word(state, 770, 0x4000);
2818 dib8000_write_word(state, 770, 0x0000);
2819 return;
2820}
2821
2822static void dib8000_set_sync_wait(struct dib8000_state *state)
2823{
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03002824 struct dtv_frontend_properties *c = &state->fe[0]->dtv_property_cache;
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002825 u16 sync_wait = 64;
2826
2827 /* P_dvsy_sync_wait - reuse mode */
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03002828 switch (c->transmission_mode) {
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002829 case TRANSMISSION_MODE_8K:
2830 sync_wait = 256;
2831 break;
2832 case TRANSMISSION_MODE_4K:
2833 sync_wait = 128;
2834 break;
2835 default:
2836 case TRANSMISSION_MODE_2K:
2837 sync_wait = 64;
2838 break;
2839 }
2840
2841 if (state->cfg.diversity_delay == 0)
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03002842 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 -03002843 else
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03002844 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 -03002845
2846 dib8000_write_word(state, 273, (dib8000_read_word(state, 273) & 0x000f) | (sync_wait << 4));
2847}
2848
2849static u32 dib8000_get_timeout(struct dib8000_state *state, u32 delay, enum timeout_mode mode)
2850{
2851 if (mode == SYMBOL_DEPENDENT_ON)
2852 return systime() + (delay * state->symbol_duration);
2853 else
2854 return systime() + delay;
2855}
2856
2857static s32 dib8000_get_status(struct dvb_frontend *fe)
2858{
2859 struct dib8000_state *state = fe->demodulator_priv;
2860 return state->status;
2861}
2862
Mauro Carvalho Chehabd44913c2014-05-29 09:20:17 -03002863static enum frontend_tune_state dib8000_get_tune_state(struct dvb_frontend *fe)
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002864{
2865 struct dib8000_state *state = fe->demodulator_priv;
2866 return state->tune_state;
2867}
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002868
Mauro Carvalho Chehabd44913c2014-05-29 09:20:17 -03002869static int dib8000_set_tune_state(struct dvb_frontend *fe, enum frontend_tune_state tune_state)
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002870{
2871 struct dib8000_state *state = fe->demodulator_priv;
2872
2873 state->tune_state = tune_state;
2874 return 0;
2875}
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002876
2877static int dib8000_tune_restart_from_demod(struct dvb_frontend *fe)
2878{
2879 struct dib8000_state *state = fe->demodulator_priv;
2880
2881 state->status = FE_STATUS_TUNE_PENDING;
2882 state->tune_state = CT_DEMOD_START;
2883 return 0;
2884}
2885
2886static u16 dib8000_read_lock(struct dvb_frontend *fe)
2887{
2888 struct dib8000_state *state = fe->demodulator_priv;
2889
2890 if (state->revision == 0x8090)
2891 return dib8000_read_word(state, 570);
2892 return dib8000_read_word(state, 568);
2893}
2894
2895static int dib8090p_init_sdram(struct dib8000_state *state)
2896{
2897 u16 reg = 0;
2898 dprintk("init sdram");
2899
2900 reg = dib8000_read_word(state, 274) & 0xfff0;
2901 dib8000_write_word(state, 274, reg | 0x7); /* P_dintlv_delay_ram = 7 because of MobileSdram */
2902
2903 dib8000_write_word(state, 1803, (7 << 2));
2904
2905 reg = dib8000_read_word(state, 1280);
2906 dib8000_write_word(state, 1280, reg | (1 << 2)); /* force restart P_restart_sdram */
2907 dib8000_write_word(state, 1280, reg); /* release restart P_restart_sdram */
2908
2909 return 0;
2910}
2911
Mauro Carvalho Chehabad976182013-12-15 09:57:40 -03002912/**
2913 * is_manual_mode - Check if TMCC should be used for parameters settings
2914 * @c: struct dvb_frontend_properties
2915 *
2916 * By default, TMCC table should be used for parameter settings on most
2917 * usercases. However, sometimes it is desirable to lock the demod to
2918 * use the manual parameters.
2919 *
2920 * On manual mode, the current dib8000_tune state machine is very restrict:
2921 * It requires that both per-layer and per-transponder parameters to be
2922 * properly specified, otherwise the device won't lock.
2923 *
2924 * Check if all those conditions are properly satisfied before allowing
2925 * the device to use the manual frequency lock mode.
2926 */
2927static int is_manual_mode(struct dtv_frontend_properties *c)
2928{
2929 int i, n_segs = 0;
2930
2931 /* Use auto mode on DVB-T compat mode */
2932 if (c->delivery_system != SYS_ISDBT)
2933 return 0;
2934
2935 /*
2936 * Transmission mode is only detected on auto mode, currently
2937 */
2938 if (c->transmission_mode == TRANSMISSION_MODE_AUTO) {
2939 dprintk("transmission mode auto");
2940 return 0;
2941 }
2942
2943 /*
2944 * Guard interval is only detected on auto mode, currently
2945 */
2946 if (c->guard_interval == GUARD_INTERVAL_AUTO) {
2947 dprintk("guard interval auto");
2948 return 0;
2949 }
2950
2951 /*
2952 * If no layer is enabled, assume auto mode, as at least one
2953 * layer should be enabled
2954 */
2955 if (!c->isdbt_layer_enabled) {
2956 dprintk("no layer modulation specified");
2957 return 0;
2958 }
2959
2960 /*
2961 * Check if the per-layer parameters aren't auto and
2962 * disable a layer if segment count is 0 or invalid.
2963 */
2964 for (i = 0; i < 3; i++) {
2965 if (!(c->isdbt_layer_enabled & 1 << i))
2966 continue;
2967
2968 if ((c->layer[i].segment_count > 13) ||
2969 (c->layer[i].segment_count == 0)) {
2970 c->isdbt_layer_enabled &= ~(1 << i);
2971 continue;
2972 }
2973
2974 n_segs += c->layer[i].segment_count;
2975
2976 if ((c->layer[i].modulation == QAM_AUTO) ||
2977 (c->layer[i].fec == FEC_AUTO)) {
2978 dprintk("layer %c has either modulation or FEC auto",
2979 'A' + i);
2980 return 0;
2981 }
2982 }
2983
2984 /*
2985 * Userspace specified a wrong number of segments.
2986 * fallback to auto mode.
2987 */
2988 if (n_segs == 0 || n_segs > 13) {
2989 dprintk("number of segments is invalid");
2990 return 0;
2991 }
2992
2993 /* Everything looks ok for manual mode */
2994 return 1;
2995}
2996
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002997static int dib8000_tune(struct dvb_frontend *fe)
2998{
2999 struct dib8000_state *state = fe->demodulator_priv;
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03003000 struct dtv_frontend_properties *c = &state->fe[0]->dtv_property_cache;
Patrick Boettcher173a64c2013-04-22 12:45:52 -03003001 enum frontend_tune_state *tune_state = &state->tune_state;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003002
Patrick Boettcher173a64c2013-04-22 12:45:52 -03003003 u16 locks, deeper_interleaver = 0, i;
3004 int ret = 1; /* 1 symbol duration (in 100us unit) delay most of the time */
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003005
Patrick Boettcher173a64c2013-04-22 12:45:52 -03003006 u32 *timeout = &state->timeout;
3007 u32 now = systime();
3008#ifdef DIB8000_AGC_FREEZE
3009 u16 agc1, agc2;
3010#endif
Dan Carpentere04f4b22012-07-20 07:11:57 -03003011
Patrick Boettcher173a64c2013-04-22 12:45:52 -03003012 u32 corm[4] = {0, 0, 0, 0};
3013 u8 find_index, max_value;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003014
Patrick Boettcher173a64c2013-04-22 12:45:52 -03003015#if 0
3016 if (*tune_state < CT_DEMOD_STOP)
3017 dprintk("IN: context status = %d, TUNE_STATE %d autosearch step = %u systime = %u", state->channel_parameters_set, *tune_state, state->autosearch_state, now);
3018#endif
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003019
Patrick Boettcher173a64c2013-04-22 12:45:52 -03003020 switch (*tune_state) {
3021 case CT_DEMOD_START: /* 30 */
Mauro Carvalho Chehab6ef06e72013-12-16 19:10:59 -03003022 dib8000_reset_stats(fe);
3023
Patrick Boettcher173a64c2013-04-22 12:45:52 -03003024 if (state->revision == 0x8090)
3025 dib8090p_init_sdram(state);
3026 state->status = FE_STATUS_TUNE_PENDING;
Mauro Carvalho Chehabad976182013-12-15 09:57:40 -03003027 state->channel_parameters_set = is_manual_mode(c);
3028
3029 dprintk("Tuning channel on %s search mode",
3030 state->channel_parameters_set ? "manual" : "auto");
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003031
Patrick Boettcher173a64c2013-04-22 12:45:52 -03003032 dib8000_viterbi_state(state, 0); /* force chan dec in restart */
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003033
Mauro Carvalho Chehabad976182013-12-15 09:57:40 -03003034 /* Layer monitor */
Patrick Boettcher173a64c2013-04-22 12:45:52 -03003035 dib8000_write_word(state, 285, dib8000_read_word(state, 285) & 0x60);
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003036
Patrick Boettcher173a64c2013-04-22 12:45:52 -03003037 dib8000_set_frequency_offset(state);
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03003038 dib8000_set_bandwidth(fe, c->bandwidth_hz / 1000);
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003039
Patrick Boettcher173a64c2013-04-22 12:45:52 -03003040 if (state->channel_parameters_set == 0) { /* The channel struct is unknown, search it ! */
3041#ifdef DIB8000_AGC_FREEZE
3042 if (state->revision != 0x8090) {
3043 state->agc1_max = dib8000_read_word(state, 108);
3044 state->agc1_min = dib8000_read_word(state, 109);
3045 state->agc2_max = dib8000_read_word(state, 110);
3046 state->agc2_min = dib8000_read_word(state, 111);
3047 agc1 = dib8000_read_word(state, 388);
3048 agc2 = dib8000_read_word(state, 389);
3049 dib8000_write_word(state, 108, agc1);
3050 dib8000_write_word(state, 109, agc1);
3051 dib8000_write_word(state, 110, agc2);
3052 dib8000_write_word(state, 111, agc2);
3053 }
3054#endif
3055 state->autosearch_state = AS_SEARCHING_FFT;
3056 state->found_nfft = TRANSMISSION_MODE_AUTO;
3057 state->found_guard = GUARD_INTERVAL_AUTO;
3058 *tune_state = CT_DEMOD_SEARCH_NEXT;
3059 } else { /* we already know the channel struct so TUNE only ! */
3060 state->autosearch_state = AS_DONE;
3061 *tune_state = CT_DEMOD_STEP_3;
3062 }
3063 state->symbol_duration = dib8000_get_symbol_duration(state);
3064 break;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003065
Patrick Boettcher173a64c2013-04-22 12:45:52 -03003066 case CT_DEMOD_SEARCH_NEXT: /* 51 */
3067 dib8000_autosearch_start(fe);
3068 if (state->revision == 0x8090)
3069 ret = 50;
3070 else
3071 ret = 15;
3072 *tune_state = CT_DEMOD_STEP_1;
3073 break;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003074
Patrick Boettcher173a64c2013-04-22 12:45:52 -03003075 case CT_DEMOD_STEP_1: /* 31 */
3076 switch (dib8000_autosearch_irq(fe)) {
3077 case 1: /* fail */
3078 state->status = FE_STATUS_TUNE_FAILED;
3079 state->autosearch_state = AS_DONE;
3080 *tune_state = CT_DEMOD_STOP; /* else we are done here */
3081 break;
3082 case 2: /* Succes */
3083 state->status = FE_STATUS_FFT_SUCCESS; /* signal to the upper layer, that there was a channel found and the parameters can be read */
3084 *tune_state = CT_DEMOD_STEP_3;
3085 if (state->autosearch_state == AS_SEARCHING_GUARD)
3086 *tune_state = CT_DEMOD_STEP_2;
3087 else
3088 state->autosearch_state = AS_DONE;
3089 break;
3090 case 3: /* Autosearch FFT max correlation endded */
3091 *tune_state = CT_DEMOD_STEP_2;
3092 break;
3093 }
3094 break;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003095
Patrick Boettcher173a64c2013-04-22 12:45:52 -03003096 case CT_DEMOD_STEP_2:
3097 switch (state->autosearch_state) {
3098 case AS_SEARCHING_FFT:
3099 /* searching for the correct FFT */
3100 if (state->revision == 0x8090) {
3101 corm[2] = (dib8000_read_word(state, 596) << 16) | (dib8000_read_word(state, 597));
3102 corm[1] = (dib8000_read_word(state, 598) << 16) | (dib8000_read_word(state, 599));
3103 corm[0] = (dib8000_read_word(state, 600) << 16) | (dib8000_read_word(state, 601));
3104 } else {
3105 corm[2] = (dib8000_read_word(state, 594) << 16) | (dib8000_read_word(state, 595));
3106 corm[1] = (dib8000_read_word(state, 596) << 16) | (dib8000_read_word(state, 597));
3107 corm[0] = (dib8000_read_word(state, 598) << 16) | (dib8000_read_word(state, 599));
3108 }
3109 /* dprintk("corm fft: %u %u %u", corm[0], corm[1], corm[2]); */
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003110
Patrick Boettcher173a64c2013-04-22 12:45:52 -03003111 max_value = 0;
3112 for (find_index = 1 ; find_index < 3 ; find_index++) {
3113 if (corm[max_value] < corm[find_index])
3114 max_value = find_index ;
3115 }
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003116
Patrick Boettcher173a64c2013-04-22 12:45:52 -03003117 switch (max_value) {
3118 case 0:
3119 state->found_nfft = TRANSMISSION_MODE_2K;
3120 break;
3121 case 1:
3122 state->found_nfft = TRANSMISSION_MODE_4K;
3123 break;
3124 case 2:
3125 default:
3126 state->found_nfft = TRANSMISSION_MODE_8K;
3127 break;
3128 }
3129 /* dprintk("Autosearch FFT has found Mode %d", max_value + 1); */
3130
3131 *tune_state = CT_DEMOD_SEARCH_NEXT;
3132 state->autosearch_state = AS_SEARCHING_GUARD;
3133 if (state->revision == 0x8090)
3134 ret = 50;
3135 else
3136 ret = 10;
3137 break;
3138 case AS_SEARCHING_GUARD:
3139 /* searching for the correct guard interval */
3140 if (state->revision == 0x8090)
3141 state->found_guard = dib8000_read_word(state, 572) & 0x3;
3142 else
3143 state->found_guard = dib8000_read_word(state, 570) & 0x3;
3144 /* dprintk("guard interval found=%i", state->found_guard); */
3145
3146 *tune_state = CT_DEMOD_STEP_3;
3147 break;
3148 default:
3149 /* the demod should never be in this state */
3150 state->status = FE_STATUS_TUNE_FAILED;
3151 state->autosearch_state = AS_DONE;
3152 *tune_state = CT_DEMOD_STOP; /* else we are done here */
3153 break;
3154 }
3155 break;
3156
3157 case CT_DEMOD_STEP_3: /* 33 */
3158 state->symbol_duration = dib8000_get_symbol_duration(state);
3159 dib8000_set_isdbt_loop_params(state, LOOP_TUNE_1);
3160 dib8000_set_isdbt_common_channel(state, 0, 0);/* setting the known channel parameters here */
3161 *tune_state = CT_DEMOD_STEP_4;
3162 break;
3163
3164 case CT_DEMOD_STEP_4: /* (34) */
3165 dib8000_demod_restart(state);
3166
3167 dib8000_set_sync_wait(state);
3168 dib8000_set_diversity_in(state->fe[0], state->diversity_onoff);
3169
3170 locks = (dib8000_read_word(state, 180) >> 6) & 0x3f; /* P_coff_winlen ? */
Jonathan McCrohan39c1cb22013-10-20 21:34:01 -03003171 /* coff should lock over P_coff_winlen ofdm symbols : give 3 times this length to lock */
Patrick Boettcher173a64c2013-04-22 12:45:52 -03003172 *timeout = dib8000_get_timeout(state, 2 * locks, SYMBOL_DEPENDENT_ON);
3173 *tune_state = CT_DEMOD_STEP_5;
3174 break;
3175
3176 case CT_DEMOD_STEP_5: /* (35) */
3177 locks = dib8000_read_lock(fe);
3178 if (locks & (0x3 << 11)) { /* coff-lock and off_cpil_lock achieved */
3179 dib8000_update_timf(state); /* we achieved a coff_cpil_lock - it's time to update the timf */
3180 if (!state->differential_constellation) {
3181 /* 2 times lmod4_win_len + 10 symbols (pipe delay after coff + nb to compute a 1st correlation) */
3182 *timeout = dib8000_get_timeout(state, (20 * ((dib8000_read_word(state, 188)>>5)&0x1f)), SYMBOL_DEPENDENT_ON);
3183 *tune_state = CT_DEMOD_STEP_7;
3184 } else {
3185 *tune_state = CT_DEMOD_STEP_8;
3186 }
3187 } else if (now > *timeout) {
3188 *tune_state = CT_DEMOD_STEP_6; /* goto check for diversity input connection */
3189 }
3190 break;
3191
3192 case CT_DEMOD_STEP_6: /* (36) if there is an input (diversity) */
3193 if ((state->fe[1] != NULL) && (state->output_mode != OUTMODE_DIVERSITY)) {
3194 /* 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 */
3195 if (dib8000_get_status(state->fe[1]) <= FE_STATUS_STD_SUCCESS) /* Something is locked on the input fe */
3196 *tune_state = CT_DEMOD_STEP_8; /* go for mpeg */
3197 else if (dib8000_get_status(state->fe[1]) >= FE_STATUS_TUNE_TIME_TOO_SHORT) { /* fe in input failled also, break the current one */
3198 *tune_state = CT_DEMOD_STOP; /* else we are done here ; step 8 will close the loops and exit */
3199 dib8000_viterbi_state(state, 1); /* start viterbi chandec */
3200 dib8000_set_isdbt_loop_params(state, LOOP_TUNE_2);
3201 state->status = FE_STATUS_TUNE_FAILED;
3202 }
3203 } else {
3204 dib8000_viterbi_state(state, 1); /* start viterbi chandec */
3205 dib8000_set_isdbt_loop_params(state, LOOP_TUNE_2);
3206 *tune_state = CT_DEMOD_STOP; /* else we are done here ; step 8 will close the loops and exit */
3207 state->status = FE_STATUS_TUNE_FAILED;
3208 }
3209 break;
3210
3211 case CT_DEMOD_STEP_7: /* 37 */
3212 locks = dib8000_read_lock(fe);
3213 if (locks & (1<<10)) { /* lmod4_lock */
3214 ret = 14; /* wait for 14 symbols */
3215 *tune_state = CT_DEMOD_STEP_8;
3216 } else if (now > *timeout)
3217 *tune_state = CT_DEMOD_STEP_6; /* goto check for diversity input connection */
3218 break;
3219
3220 case CT_DEMOD_STEP_8: /* 38 */
3221 dib8000_viterbi_state(state, 1); /* start viterbi chandec */
3222 dib8000_set_isdbt_loop_params(state, LOOP_TUNE_2);
3223
3224 /* mpeg will never lock on this condition because init_prbs is not set : search for it !*/
Mauro Carvalho Chehab746f7ae2013-04-25 11:15:54 -03003225 if (c->isdbt_sb_mode
3226 && c->isdbt_sb_subchannel < 14
3227 && !state->differential_constellation) {
Patrick Boettcher173a64c2013-04-22 12:45:52 -03003228 state->subchannel = 0;
3229 *tune_state = CT_DEMOD_STEP_11;
3230 } else {
3231 *tune_state = CT_DEMOD_STEP_9;
3232 state->status = FE_STATUS_LOCKED;
3233 }
3234 break;
3235
3236 case CT_DEMOD_STEP_9: /* 39 */
3237 if ((state->revision == 0x8090) || ((dib8000_read_word(state, 1291) >> 9) & 0x1)) { /* fe capable of deinterleaving : esram */
Jonathan McCrohan39c1cb22013-10-20 21:34:01 -03003238 /* defines timeout for mpeg lock depending on interleaver length of longest layer */
Patrick Boettcher173a64c2013-04-22 12:45:52 -03003239 for (i = 0; i < 3; i++) {
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03003240 if (c->layer[i].interleaving >= deeper_interleaver) {
3241 dprintk("layer%i: time interleaver = %d ", i, c->layer[i].interleaving);
3242 if (c->layer[i].segment_count > 0) { /* valid layer */
3243 deeper_interleaver = c->layer[0].interleaving;
Patrick Boettcher173a64c2013-04-22 12:45:52 -03003244 state->longest_intlv_layer = i;
3245 }
3246 }
3247 }
3248
3249 if (deeper_interleaver == 0)
3250 locks = 2; /* locks is the tmp local variable name */
3251 else if (deeper_interleaver == 3)
3252 locks = 8;
3253 else
3254 locks = 2 * deeper_interleaver;
3255
3256 if (state->diversity_onoff != 0) /* because of diversity sync */
3257 locks *= 2;
3258
3259 *timeout = now + (2000 * locks); /* give the mpeg lock 800ms if sram is present */
3260 dprintk("Deeper interleaver mode = %d on layer %d : timeout mult factor = %d => will use timeout = %d", deeper_interleaver, state->longest_intlv_layer, locks, *timeout);
3261
3262 *tune_state = CT_DEMOD_STEP_10;
3263 } else
3264 *tune_state = CT_DEMOD_STOP;
3265 break;
3266
3267 case CT_DEMOD_STEP_10: /* 40 */
3268 locks = dib8000_read_lock(fe);
3269 if (locks&(1<<(7-state->longest_intlv_layer))) { /* mpeg lock : check the longest one */
3270 dprintk("Mpeg locks [ L0 : %d | L1 : %d | L2 : %d ]", (locks>>7)&0x1, (locks>>6)&0x1, (locks>>5)&0x1);
Mauro Carvalho Chehab746f7ae2013-04-25 11:15:54 -03003271 if (c->isdbt_sb_mode
3272 && c->isdbt_sb_subchannel < 14
3273 && !state->differential_constellation)
Patrick Boettcher173a64c2013-04-22 12:45:52 -03003274 /* signal to the upper layer, that there was a channel found and the parameters can be read */
3275 state->status = FE_STATUS_DEMOD_SUCCESS;
3276 else
3277 state->status = FE_STATUS_DATA_LOCKED;
3278 *tune_state = CT_DEMOD_STOP;
3279 } else if (now > *timeout) {
Mauro Carvalho Chehab746f7ae2013-04-25 11:15:54 -03003280 if (c->isdbt_sb_mode
3281 && c->isdbt_sb_subchannel < 14
3282 && !state->differential_constellation) { /* continue to try init prbs autosearch */
Patrick Boettcher173a64c2013-04-22 12:45:52 -03003283 state->subchannel += 3;
3284 *tune_state = CT_DEMOD_STEP_11;
3285 } 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 */
3286 if (locks & (0x7<<5)) {
3287 dprintk("Mpeg locks [ L0 : %d | L1 : %d | L2 : %d ]", (locks>>7)&0x1, (locks>>6)&0x1, (locks>>5)&0x1);
3288 state->status = FE_STATUS_DATA_LOCKED;
3289 } else
3290 state->status = FE_STATUS_TUNE_FAILED;
3291 *tune_state = CT_DEMOD_STOP;
3292 }
3293 }
3294 break;
3295
3296 case CT_DEMOD_STEP_11: /* 41 : init prbs autosearch */
3297 if (state->subchannel <= 41) {
3298 dib8000_set_subchannel_prbs(state, dib8000_get_init_prbs(state, state->subchannel));
3299 *tune_state = CT_DEMOD_STEP_9;
3300 } else {
3301 *tune_state = CT_DEMOD_STOP;
3302 state->status = FE_STATUS_TUNE_FAILED;
3303 }
3304 break;
3305
3306 default:
3307 break;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003308 }
3309
Patrick Boettcher173a64c2013-04-22 12:45:52 -03003310 /* tuning is finished - cleanup the demod */
3311 switch (*tune_state) {
3312 case CT_DEMOD_STOP: /* (42) */
3313#ifdef DIB8000_AGC_FREEZE
3314 if ((state->revision != 0x8090) && (state->agc1_max != 0)) {
3315 dib8000_write_word(state, 108, state->agc1_max);
3316 dib8000_write_word(state, 109, state->agc1_min);
3317 dib8000_write_word(state, 110, state->agc2_max);
3318 dib8000_write_word(state, 111, state->agc2_min);
3319 state->agc1_max = 0;
3320 state->agc1_min = 0;
3321 state->agc2_max = 0;
3322 state->agc2_min = 0;
3323 }
3324#endif
3325 ret = FE_CALLBACK_TIME_NEVER;
3326 break;
3327 default:
3328 break;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003329 }
3330
Patrick Boettcher173a64c2013-04-22 12:45:52 -03003331 if ((ret > 0) && (*tune_state > CT_DEMOD_STEP_3))
3332 return ret * state->symbol_duration;
3333 if ((ret > 0) && (ret < state->symbol_duration))
3334 return state->symbol_duration; /* at least one symbol */
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003335 return ret;
3336}
3337
3338static int dib8000_wakeup(struct dvb_frontend *fe)
3339{
3340 struct dib8000_state *state = fe->demodulator_priv;
Olivier Grenie4c70e072011-01-03 15:33:37 -03003341 u8 index_frontend;
3342 int ret;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003343
Olivier Grenie0c32dbd2011-08-10 05:17:18 -03003344 dib8000_set_power_mode(state, DIB8000_POWER_ALL);
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003345 dib8000_set_adc_state(state, DIBX000_ADC_ON);
3346 if (dib8000_set_adc_state(state, DIBX000_SLOW_ADC_ON) != 0)
3347 dprintk("could not start Slow ADC");
3348
Patrick Boettcher173a64c2013-04-22 12:45:52 -03003349 if (state->revision == 0x8090)
Olivier Grenie0c32dbd2011-08-10 05:17:18 -03003350 dib8000_sad_calib(state);
3351
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03003352 for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
Olivier Grenie4c70e072011-01-03 15:33:37 -03003353 ret = state->fe[index_frontend]->ops.init(state->fe[index_frontend]);
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03003354 if (ret < 0)
Olivier Grenie4c70e072011-01-03 15:33:37 -03003355 return ret;
3356 }
3357
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003358 return 0;
3359}
3360
3361static int dib8000_sleep(struct dvb_frontend *fe)
3362{
Olivier Grenie4c70e072011-01-03 15:33:37 -03003363 struct dib8000_state *state = fe->demodulator_priv;
3364 u8 index_frontend;
3365 int ret;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003366
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03003367 for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
Olivier Grenie4c70e072011-01-03 15:33:37 -03003368 ret = state->fe[index_frontend]->ops.sleep(state->fe[index_frontend]);
3369 if (ret < 0)
3370 return ret;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003371 }
Olivier Grenie4c70e072011-01-03 15:33:37 -03003372
Olivier Grenie0c32dbd2011-08-10 05:17:18 -03003373 if (state->revision != 0x8090)
3374 dib8000_set_output_mode(fe, OUTMODE_HIGH_Z);
3375 dib8000_set_power_mode(state, DIB8000_POWER_INTERFACE_ONLY);
Olivier Grenie4c70e072011-01-03 15:33:37 -03003376 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 -03003377}
3378
Mauro Carvalho Chehab70315b32013-12-15 07:41:20 -02003379static int dib8000_read_status(struct dvb_frontend *fe, fe_status_t * stat);
3380
Mauro Carvalho Chehab7c61d802011-12-30 11:30:21 -03003381static int dib8000_get_frontend(struct dvb_frontend *fe)
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003382{
3383 struct dib8000_state *state = fe->demodulator_priv;
3384 u16 i, val = 0;
Mauro Carvalho Chehab70315b32013-12-15 07:41:20 -02003385 fe_status_t stat = 0;
Olivier Grenie4c70e072011-01-03 15:33:37 -03003386 u8 index_frontend, sub_index_frontend;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003387
3388 fe->dtv_property_cache.bandwidth_hz = 6000000;
3389
Mauro Carvalho Chehab70315b32013-12-15 07:41:20 -02003390 /*
3391 * If called to early, get_frontend makes dib8000_tune to either
3392 * not lock or not sync. This causes dvbv5-scan/dvbv5-zap to fail.
3393 * So, let's just return if frontend 0 has not locked.
3394 */
3395 dib8000_read_status(fe, &stat);
3396 if (!(stat & FE_HAS_SYNC))
3397 return 0;
3398
3399 dprintk("TMCC lock");
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03003400 for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
Olivier Grenie4c70e072011-01-03 15:33:37 -03003401 state->fe[index_frontend]->ops.read_status(state->fe[index_frontend], &stat);
3402 if (stat&FE_HAS_SYNC) {
3403 dprintk("TMCC lock on the slave%i", index_frontend);
3404 /* synchronize the cache with the other frontends */
Mauro Carvalho Chehab7c61d802011-12-30 11:30:21 -03003405 state->fe[index_frontend]->ops.get_frontend(state->fe[index_frontend]);
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03003406 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 -03003407 if (sub_index_frontend != index_frontend) {
3408 state->fe[sub_index_frontend]->dtv_property_cache.isdbt_sb_mode = state->fe[index_frontend]->dtv_property_cache.isdbt_sb_mode;
3409 state->fe[sub_index_frontend]->dtv_property_cache.inversion = state->fe[index_frontend]->dtv_property_cache.inversion;
3410 state->fe[sub_index_frontend]->dtv_property_cache.transmission_mode = state->fe[index_frontend]->dtv_property_cache.transmission_mode;
3411 state->fe[sub_index_frontend]->dtv_property_cache.guard_interval = state->fe[index_frontend]->dtv_property_cache.guard_interval;
3412 state->fe[sub_index_frontend]->dtv_property_cache.isdbt_partial_reception = state->fe[index_frontend]->dtv_property_cache.isdbt_partial_reception;
3413 for (i = 0; i < 3; i++) {
3414 state->fe[sub_index_frontend]->dtv_property_cache.layer[i].segment_count = state->fe[index_frontend]->dtv_property_cache.layer[i].segment_count;
3415 state->fe[sub_index_frontend]->dtv_property_cache.layer[i].interleaving = state->fe[index_frontend]->dtv_property_cache.layer[i].interleaving;
3416 state->fe[sub_index_frontend]->dtv_property_cache.layer[i].fec = state->fe[index_frontend]->dtv_property_cache.layer[i].fec;
3417 state->fe[sub_index_frontend]->dtv_property_cache.layer[i].modulation = state->fe[index_frontend]->dtv_property_cache.layer[i].modulation;
3418 }
3419 }
3420 }
3421 return 0;
3422 }
3423 }
3424
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003425 fe->dtv_property_cache.isdbt_sb_mode = dib8000_read_word(state, 508) & 0x1;
3426
Olivier Grenie0c32dbd2011-08-10 05:17:18 -03003427 if (state->revision == 0x8090)
3428 val = dib8000_read_word(state, 572);
3429 else
3430 val = dib8000_read_word(state, 570);
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003431 fe->dtv_property_cache.inversion = (val & 0x40) >> 6;
3432 switch ((val & 0x30) >> 4) {
3433 case 1:
3434 fe->dtv_property_cache.transmission_mode = TRANSMISSION_MODE_2K;
3435 break;
3436 case 3:
3437 default:
3438 fe->dtv_property_cache.transmission_mode = TRANSMISSION_MODE_8K;
3439 break;
3440 }
3441
3442 switch (val & 0x3) {
3443 case 0:
3444 fe->dtv_property_cache.guard_interval = GUARD_INTERVAL_1_32;
3445 dprintk("dib8000_get_frontend GI = 1/32 ");
3446 break;
3447 case 1:
3448 fe->dtv_property_cache.guard_interval = GUARD_INTERVAL_1_16;
3449 dprintk("dib8000_get_frontend GI = 1/16 ");
3450 break;
3451 case 2:
3452 dprintk("dib8000_get_frontend GI = 1/8 ");
3453 fe->dtv_property_cache.guard_interval = GUARD_INTERVAL_1_8;
3454 break;
3455 case 3:
3456 dprintk("dib8000_get_frontend GI = 1/4 ");
3457 fe->dtv_property_cache.guard_interval = GUARD_INTERVAL_1_4;
3458 break;
3459 }
3460
3461 val = dib8000_read_word(state, 505);
3462 fe->dtv_property_cache.isdbt_partial_reception = val & 1;
3463 dprintk("dib8000_get_frontend : partial_reception = %d ", fe->dtv_property_cache.isdbt_partial_reception);
3464
3465 for (i = 0; i < 3; i++) {
3466 val = dib8000_read_word(state, 493 + i);
3467 fe->dtv_property_cache.layer[i].segment_count = val & 0x0F;
3468 dprintk("dib8000_get_frontend : Layer %d segments = %d ", i, fe->dtv_property_cache.layer[i].segment_count);
3469
Mauro Carvalho Chehab51fea112013-12-16 04:16:59 -03003470 val = dib8000_read_word(state, 499 + i) & 0x3;
3471 /* Interleaving can be 0, 1, 2 or 4 */
3472 if (val == 3)
3473 val = 4;
3474 fe->dtv_property_cache.layer[i].interleaving = val;
3475 dprintk("dib8000_get_frontend : Layer %d time_intlv = %d ",
3476 i, fe->dtv_property_cache.layer[i].interleaving);
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003477
3478 val = dib8000_read_word(state, 481 + i);
3479 switch (val & 0x7) {
3480 case 1:
3481 fe->dtv_property_cache.layer[i].fec = FEC_1_2;
3482 dprintk("dib8000_get_frontend : Layer %d Code Rate = 1/2 ", i);
3483 break;
3484 case 2:
3485 fe->dtv_property_cache.layer[i].fec = FEC_2_3;
3486 dprintk("dib8000_get_frontend : Layer %d Code Rate = 2/3 ", i);
3487 break;
3488 case 3:
3489 fe->dtv_property_cache.layer[i].fec = FEC_3_4;
3490 dprintk("dib8000_get_frontend : Layer %d Code Rate = 3/4 ", i);
3491 break;
3492 case 5:
3493 fe->dtv_property_cache.layer[i].fec = FEC_5_6;
3494 dprintk("dib8000_get_frontend : Layer %d Code Rate = 5/6 ", i);
3495 break;
3496 default:
3497 fe->dtv_property_cache.layer[i].fec = FEC_7_8;
3498 dprintk("dib8000_get_frontend : Layer %d Code Rate = 7/8 ", i);
3499 break;
3500 }
3501
3502 val = dib8000_read_word(state, 487 + i);
3503 switch (val & 0x3) {
3504 case 0:
3505 dprintk("dib8000_get_frontend : Layer %d DQPSK ", i);
3506 fe->dtv_property_cache.layer[i].modulation = DQPSK;
3507 break;
3508 case 1:
3509 fe->dtv_property_cache.layer[i].modulation = QPSK;
3510 dprintk("dib8000_get_frontend : Layer %d QPSK ", i);
3511 break;
3512 case 2:
3513 fe->dtv_property_cache.layer[i].modulation = QAM_16;
3514 dprintk("dib8000_get_frontend : Layer %d QAM16 ", i);
3515 break;
3516 case 3:
3517 default:
3518 dprintk("dib8000_get_frontend : Layer %d QAM64 ", i);
3519 fe->dtv_property_cache.layer[i].modulation = QAM_64;
3520 break;
3521 }
3522 }
Olivier Grenie4c70e072011-01-03 15:33:37 -03003523
3524 /* synchronize the cache with the other frontends */
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03003525 for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
Olivier Grenie4c70e072011-01-03 15:33:37 -03003526 state->fe[index_frontend]->dtv_property_cache.isdbt_sb_mode = fe->dtv_property_cache.isdbt_sb_mode;
3527 state->fe[index_frontend]->dtv_property_cache.inversion = fe->dtv_property_cache.inversion;
3528 state->fe[index_frontend]->dtv_property_cache.transmission_mode = fe->dtv_property_cache.transmission_mode;
3529 state->fe[index_frontend]->dtv_property_cache.guard_interval = fe->dtv_property_cache.guard_interval;
3530 state->fe[index_frontend]->dtv_property_cache.isdbt_partial_reception = fe->dtv_property_cache.isdbt_partial_reception;
3531 for (i = 0; i < 3; i++) {
3532 state->fe[index_frontend]->dtv_property_cache.layer[i].segment_count = fe->dtv_property_cache.layer[i].segment_count;
3533 state->fe[index_frontend]->dtv_property_cache.layer[i].interleaving = fe->dtv_property_cache.layer[i].interleaving;
3534 state->fe[index_frontend]->dtv_property_cache.layer[i].fec = fe->dtv_property_cache.layer[i].fec;
3535 state->fe[index_frontend]->dtv_property_cache.layer[i].modulation = fe->dtv_property_cache.layer[i].modulation;
3536 }
3537 }
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003538 return 0;
3539}
3540
Mauro Carvalho Chehab490ecd62011-12-22 20:38:27 -03003541static int dib8000_set_frontend(struct dvb_frontend *fe)
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003542{
3543 struct dib8000_state *state = fe->demodulator_priv;
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03003544 struct dtv_frontend_properties *c = &state->fe[0]->dtv_property_cache;
Geert Uytterhoeven4d8d5d92013-06-02 13:52:17 -03003545 int l, i, active, time, time_slave = FE_CALLBACK_TIME_NEVER;
Patrick Boettcher173a64c2013-04-22 12:45:52 -03003546 u8 exit_condition, index_frontend;
3547 u32 delay, callback_time;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003548
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03003549 if (c->frequency == 0) {
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003550 dprintk("dib8000: must at least specify frequency ");
3551 return 0;
3552 }
3553
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03003554 if (c->bandwidth_hz == 0) {
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003555 dprintk("dib8000: no bandwidth specified, set to default ");
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03003556 c->bandwidth_hz = 6000000;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003557 }
3558
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03003559 for (index_frontend = 0; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
Olivier Grenie4c70e072011-01-03 15:33:37 -03003560 /* synchronization of the cache */
3561 state->fe[index_frontend]->dtv_property_cache.delivery_system = SYS_ISDBT;
3562 memcpy(&state->fe[index_frontend]->dtv_property_cache, &fe->dtv_property_cache, sizeof(struct dtv_frontend_properties));
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003563
Patrick Boettcher173a64c2013-04-22 12:45:52 -03003564 /* set output mode and diversity input */
3565 if (state->revision != 0x8090) {
3566 dib8000_set_diversity_in(state->fe[index_frontend], 1);
3567 if (index_frontend != 0)
3568 dib8000_set_output_mode(state->fe[index_frontend],
3569 OUTMODE_DIVERSITY);
3570 else
3571 dib8000_set_output_mode(state->fe[0], OUTMODE_HIGH_Z);
3572 } else {
3573 dib8096p_set_diversity_in(state->fe[index_frontend], 1);
3574 if (index_frontend != 0)
3575 dib8096p_set_output_mode(state->fe[index_frontend],
3576 OUTMODE_DIVERSITY);
3577 else
3578 dib8096p_set_output_mode(state->fe[0], OUTMODE_HIGH_Z);
3579 }
3580
3581 /* tune the tuner */
Olivier Grenie4c70e072011-01-03 15:33:37 -03003582 if (state->fe[index_frontend]->ops.tuner_ops.set_params)
Mauro Carvalho Chehab14d24d12011-12-24 12:24:33 -03003583 state->fe[index_frontend]->ops.tuner_ops.set_params(state->fe[index_frontend]);
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003584
Olivier Grenie4c70e072011-01-03 15:33:37 -03003585 dib8000_set_tune_state(state->fe[index_frontend], CT_AGC_START);
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003586 }
3587
Patrick Boettcher173a64c2013-04-22 12:45:52 -03003588 /* turn off the diversity of the last chip */
3589 if (state->revision != 0x8090)
3590 dib8000_set_diversity_in(state->fe[index_frontend - 1], 0);
3591 else
3592 dib8096p_set_diversity_in(state->fe[index_frontend - 1], 0);
3593
Olivier Grenie4c70e072011-01-03 15:33:37 -03003594 /* start up the AGC */
3595 do {
3596 time = dib8000_agc_startup(state->fe[0]);
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03003597 for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
Olivier Grenie4c70e072011-01-03 15:33:37 -03003598 time_slave = dib8000_agc_startup(state->fe[index_frontend]);
3599 if (time == FE_CALLBACK_TIME_NEVER)
3600 time = time_slave;
3601 else if ((time_slave != FE_CALLBACK_TIME_NEVER) && (time_slave > time))
3602 time = time_slave;
3603 }
3604 if (time != FE_CALLBACK_TIME_NEVER)
3605 msleep(time / 10);
3606 else
3607 break;
3608 exit_condition = 1;
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03003609 for (index_frontend = 0; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
Olivier Grenie4c70e072011-01-03 15:33:37 -03003610 if (dib8000_get_tune_state(state->fe[index_frontend]) != CT_AGC_STOP) {
3611 exit_condition = 0;
3612 break;
3613 }
3614 }
3615 } while (exit_condition == 0);
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003616
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03003617 for (index_frontend = 0; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++)
Olivier Grenie4c70e072011-01-03 15:33:37 -03003618 dib8000_set_tune_state(state->fe[index_frontend], CT_DEMOD_START);
3619
Patrick Boettcher173a64c2013-04-22 12:45:52 -03003620 active = 1;
3621 do {
3622 callback_time = FE_CALLBACK_TIME_NEVER;
Mauro Carvalho Chehab2c2c4412011-01-16 13:02:52 -02003623 for (index_frontend = 0; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
Patrick Boettcher173a64c2013-04-22 12:45:52 -03003624 delay = dib8000_tune(state->fe[index_frontend]);
3625 if (delay != FE_CALLBACK_TIME_NEVER)
3626 delay += systime();
Olivier Grenie4c70e072011-01-03 15:33:37 -03003627
Patrick Boettcher173a64c2013-04-22 12:45:52 -03003628 /* we are in autosearch */
3629 if (state->channel_parameters_set == 0) { /* searching */
3630 if ((dib8000_get_status(state->fe[index_frontend]) == FE_STATUS_DEMOD_SUCCESS) || (dib8000_get_status(state->fe[index_frontend]) == FE_STATUS_FFT_SUCCESS)) {
3631 dprintk("autosearch succeeded on fe%i", index_frontend);
3632 dib8000_get_frontend(state->fe[index_frontend]); /* we read the channel parameters from the frontend which was successful */
3633 state->channel_parameters_set = 1;
3634
3635 for (l = 0; (l < MAX_NUMBER_OF_FRONTENDS) && (state->fe[l] != NULL); l++) {
3636 if (l != index_frontend) { /* and for all frontend except the successful one */
3637 dib8000_tune_restart_from_demod(state->fe[l]);
3638
3639 state->fe[l]->dtv_property_cache.isdbt_sb_mode = state->fe[index_frontend]->dtv_property_cache.isdbt_sb_mode;
3640 state->fe[l]->dtv_property_cache.inversion = state->fe[index_frontend]->dtv_property_cache.inversion;
3641 state->fe[l]->dtv_property_cache.transmission_mode = state->fe[index_frontend]->dtv_property_cache.transmission_mode;
3642 state->fe[l]->dtv_property_cache.guard_interval = state->fe[index_frontend]->dtv_property_cache.guard_interval;
3643 state->fe[l]->dtv_property_cache.isdbt_partial_reception = state->fe[index_frontend]->dtv_property_cache.isdbt_partial_reception;
3644 for (i = 0; i < 3; i++) {
3645 state->fe[l]->dtv_property_cache.layer[i].segment_count = state->fe[index_frontend]->dtv_property_cache.layer[i].segment_count;
3646 state->fe[l]->dtv_property_cache.layer[i].interleaving = state->fe[index_frontend]->dtv_property_cache.layer[i].interleaving;
3647 state->fe[l]->dtv_property_cache.layer[i].fec = state->fe[index_frontend]->dtv_property_cache.layer[i].fec;
3648 state->fe[l]->dtv_property_cache.layer[i].modulation = state->fe[index_frontend]->dtv_property_cache.layer[i].modulation;
3649 }
3650
3651 }
Mauro Carvalho Chehab2c2c4412011-01-16 13:02:52 -02003652 }
3653 }
3654 }
Patrick Boettcher173a64c2013-04-22 12:45:52 -03003655 if (delay < callback_time)
3656 callback_time = delay;
3657 }
3658 /* tuning is done when the master frontend is done (failed or success) */
3659 if (dib8000_get_status(state->fe[0]) == FE_STATUS_TUNE_FAILED ||
3660 dib8000_get_status(state->fe[0]) == FE_STATUS_LOCKED ||
3661 dib8000_get_status(state->fe[0]) == FE_STATUS_DATA_LOCKED) {
3662 active = 0;
3663 /* we need to wait for all frontends to be finished */
3664 for (index_frontend = 0; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
3665 if (dib8000_get_tune_state(state->fe[index_frontend]) != CT_DEMOD_STOP)
3666 active = 1;
3667 }
3668 if (active == 0)
3669 dprintk("tuning done with status %d", dib8000_get_status(state->fe[0]));
Mauro Carvalho Chehab2c2c4412011-01-16 13:02:52 -02003670 }
Olivier Grenie4c70e072011-01-03 15:33:37 -03003671
Patrick Boettcher173a64c2013-04-22 12:45:52 -03003672 if ((active == 1) && (callback_time == FE_CALLBACK_TIME_NEVER)) {
3673 dprintk("strange callback time something went wrong");
3674 active = 0;
3675 }
Olivier Grenie4c70e072011-01-03 15:33:37 -03003676
Patrick Boettcher173a64c2013-04-22 12:45:52 -03003677 while ((active == 1) && (systime() < callback_time))
3678 msleep(100);
3679 } while (active);
Olivier Grenie4c70e072011-01-03 15:33:37 -03003680
Patrick Boettcher173a64c2013-04-22 12:45:52 -03003681 /* set output mode */
3682 if (state->revision != 0x8090)
Olivier Grenie0c32dbd2011-08-10 05:17:18 -03003683 dib8000_set_output_mode(state->fe[0], state->cfg.output_mode);
Patrick Boettcher173a64c2013-04-22 12:45:52 -03003684 else {
Olivier Grenie0c32dbd2011-08-10 05:17:18 -03003685 dib8096p_set_output_mode(state->fe[0], state->cfg.output_mode);
3686 if (state->cfg.enMpegOutput == 0) {
3687 dib8096p_setDibTxMux(state, MPEG_ON_DIBTX);
3688 dib8096p_setHostBusMux(state, DIBTX_ON_HOSTBUS);
3689 }
Olivier Grenie0c32dbd2011-08-10 05:17:18 -03003690 }
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003691
Geert Uytterhoeven4d8d5d92013-06-02 13:52:17 -03003692 return 0;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003693}
3694
Mauro Carvalho Chehab6ef06e72013-12-16 19:10:59 -03003695static int dib8000_get_stats(struct dvb_frontend *fe, fe_status_t stat);
3696
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003697static int dib8000_read_status(struct dvb_frontend *fe, fe_status_t * stat)
3698{
3699 struct dib8000_state *state = fe->demodulator_priv;
Olivier Grenie0c32dbd2011-08-10 05:17:18 -03003700 u16 lock_slave = 0, lock;
Olivier Grenie4c70e072011-01-03 15:33:37 -03003701 u8 index_frontend;
3702
Patrick Boettcher173a64c2013-04-22 12:45:52 -03003703 lock = dib8000_read_lock(fe);
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03003704 for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++)
Olivier Grenie4c70e072011-01-03 15:33:37 -03003705 lock_slave |= dib8000_read_lock(state->fe[index_frontend]);
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003706
3707 *stat = 0;
3708
Olivier Grenie4c70e072011-01-03 15:33:37 -03003709 if (((lock >> 13) & 1) || ((lock_slave >> 13) & 1))
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003710 *stat |= FE_HAS_SIGNAL;
3711
Olivier Grenie4c70e072011-01-03 15:33:37 -03003712 if (((lock >> 8) & 1) || ((lock_slave >> 8) & 1)) /* Equal */
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003713 *stat |= FE_HAS_CARRIER;
3714
Olivier Grenie4c70e072011-01-03 15:33:37 -03003715 if ((((lock >> 1) & 0xf) == 0xf) || (((lock_slave >> 1) & 0xf) == 0xf)) /* TMCC_SYNC */
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003716 *stat |= FE_HAS_SYNC;
3717
Olivier Grenie4c70e072011-01-03 15:33:37 -03003718 if ((((lock >> 12) & 1) || ((lock_slave >> 12) & 1)) && ((lock >> 5) & 7)) /* FEC MPEG */
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003719 *stat |= FE_HAS_LOCK;
3720
Olivier Grenie4c70e072011-01-03 15:33:37 -03003721 if (((lock >> 12) & 1) || ((lock_slave >> 12) & 1)) {
Olivier Grenie89dfc552009-11-30 06:38:49 -03003722 lock = dib8000_read_word(state, 554); /* Viterbi Layer A */
3723 if (lock & 0x01)
3724 *stat |= FE_HAS_VITERBI;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003725
Olivier Grenie89dfc552009-11-30 06:38:49 -03003726 lock = dib8000_read_word(state, 555); /* Viterbi Layer B */
3727 if (lock & 0x01)
3728 *stat |= FE_HAS_VITERBI;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003729
Olivier Grenie89dfc552009-11-30 06:38:49 -03003730 lock = dib8000_read_word(state, 556); /* Viterbi Layer C */
3731 if (lock & 0x01)
3732 *stat |= FE_HAS_VITERBI;
3733 }
Mauro Carvalho Chehab6ef06e72013-12-16 19:10:59 -03003734 dib8000_get_stats(fe, *stat);
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003735
3736 return 0;
3737}
3738
3739static int dib8000_read_ber(struct dvb_frontend *fe, u32 * ber)
3740{
3741 struct dib8000_state *state = fe->demodulator_priv;
Olivier Grenie0c32dbd2011-08-10 05:17:18 -03003742
3743 /* 13 segments */
3744 if (state->revision == 0x8090)
3745 *ber = (dib8000_read_word(state, 562) << 16) |
3746 dib8000_read_word(state, 563);
3747 else
3748 *ber = (dib8000_read_word(state, 560) << 16) |
3749 dib8000_read_word(state, 561);
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003750 return 0;
3751}
3752
3753static int dib8000_read_unc_blocks(struct dvb_frontend *fe, u32 * unc)
3754{
3755 struct dib8000_state *state = fe->demodulator_priv;
Olivier Grenie0c32dbd2011-08-10 05:17:18 -03003756
3757 /* packet error on 13 seg */
3758 if (state->revision == 0x8090)
3759 *unc = dib8000_read_word(state, 567);
3760 else
3761 *unc = dib8000_read_word(state, 565);
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003762 return 0;
3763}
3764
3765static int dib8000_read_signal_strength(struct dvb_frontend *fe, u16 * strength)
3766{
3767 struct dib8000_state *state = fe->demodulator_priv;
Olivier Grenie4c70e072011-01-03 15:33:37 -03003768 u8 index_frontend;
3769 u16 val;
3770
3771 *strength = 0;
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03003772 for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
Olivier Grenie4c70e072011-01-03 15:33:37 -03003773 state->fe[index_frontend]->ops.read_signal_strength(state->fe[index_frontend], &val);
3774 if (val > 65535 - *strength)
3775 *strength = 65535;
3776 else
3777 *strength += val;
3778 }
3779
3780 val = 65535 - dib8000_read_word(state, 390);
3781 if (val > 65535 - *strength)
3782 *strength = 65535;
3783 else
3784 *strength += val;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003785 return 0;
3786}
3787
Olivier Grenie4c70e072011-01-03 15:33:37 -03003788static u32 dib8000_get_snr(struct dvb_frontend *fe)
3789{
3790 struct dib8000_state *state = fe->demodulator_priv;
3791 u32 n, s, exp;
3792 u16 val;
3793
Olivier Grenie0c32dbd2011-08-10 05:17:18 -03003794 if (state->revision != 0x8090)
3795 val = dib8000_read_word(state, 542);
3796 else
3797 val = dib8000_read_word(state, 544);
Olivier Grenie4c70e072011-01-03 15:33:37 -03003798 n = (val >> 6) & 0xff;
3799 exp = (val & 0x3f);
3800 if ((exp & 0x20) != 0)
3801 exp -= 0x40;
3802 n <<= exp+16;
3803
Olivier Grenie0c32dbd2011-08-10 05:17:18 -03003804 if (state->revision != 0x8090)
3805 val = dib8000_read_word(state, 543);
3806 else
3807 val = dib8000_read_word(state, 545);
Olivier Grenie4c70e072011-01-03 15:33:37 -03003808 s = (val >> 6) & 0xff;
3809 exp = (val & 0x3f);
3810 if ((exp & 0x20) != 0)
3811 exp -= 0x40;
3812 s <<= exp+16;
3813
3814 if (n > 0) {
3815 u32 t = (s/n) << 16;
3816 return t + ((s << 16) - n*t) / n;
3817 }
3818 return 0xffffffff;
3819}
3820
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003821static int dib8000_read_snr(struct dvb_frontend *fe, u16 * snr)
3822{
3823 struct dib8000_state *state = fe->demodulator_priv;
Olivier Grenie4c70e072011-01-03 15:33:37 -03003824 u8 index_frontend;
3825 u32 snr_master;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003826
Olivier Grenie4c70e072011-01-03 15:33:37 -03003827 snr_master = dib8000_get_snr(fe);
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03003828 for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++)
Olivier Grenie4c70e072011-01-03 15:33:37 -03003829 snr_master += dib8000_get_snr(state->fe[index_frontend]);
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003830
Olivier Grenie1f6bfcc2011-07-04 12:33:54 -03003831 if ((snr_master >> 16) != 0) {
Olivier Grenie4c70e072011-01-03 15:33:37 -03003832 snr_master = 10*intlog10(snr_master>>16);
3833 *snr = snr_master / ((1 << 24) / 10);
3834 }
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003835 else
Olivier Grenie4c70e072011-01-03 15:33:37 -03003836 *snr = 0;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003837
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003838 return 0;
3839}
3840
Mauro Carvalho Chehab6ef06e72013-12-16 19:10:59 -03003841struct per_layer_regs {
3842 u16 lock, ber, per;
3843};
3844
3845static const struct per_layer_regs per_layer_regs[] = {
3846 { 554, 560, 562 },
3847 { 555, 576, 578 },
3848 { 556, 581, 583 },
3849};
3850
Mauro Carvalho Chehab42ff76b2013-12-16 21:45:19 -03003851struct linear_segments {
3852 unsigned x;
3853 signed y;
3854};
3855
3856/*
3857 * Table to estimate signal strength in dBm.
3858 * This table was empirically determinated by measuring the signal
3859 * strength generated by a DTA-2111 RF generator directly connected into
3860 * a dib8076 device (a PixelView PV-D231U stick), using a good quality
3861 * 3 meters RC6 cable and good RC6 connectors.
3862 * The real value can actually be different on other devices, depending
3863 * on several factors, like if LNA is enabled or not, if diversity is
3864 * enabled, type of connectors, etc.
3865 * Yet, it is better to use this measure in dB than a random non-linear
3866 * percentage value, especially for antenna adjustments.
3867 * On my tests, the precision of the measure using this table is about
3868 * 0.5 dB, with sounds reasonable enough.
3869 */
3870static struct linear_segments strength_to_db_table[] = {
3871 { 55953, 108500 }, /* -22.5 dBm */
3872 { 55394, 108000 },
3873 { 53834, 107000 },
3874 { 52863, 106000 },
3875 { 52239, 105000 },
3876 { 52012, 104000 },
3877 { 51803, 103000 },
3878 { 51566, 102000 },
3879 { 51356, 101000 },
3880 { 51112, 100000 },
3881 { 50869, 99000 },
3882 { 50600, 98000 },
3883 { 50363, 97000 },
3884 { 50117, 96000 }, /* -35 dBm */
3885 { 49889, 95000 },
3886 { 49680, 94000 },
3887 { 49493, 93000 },
3888 { 49302, 92000 },
3889 { 48929, 91000 },
3890 { 48416, 90000 },
3891 { 48035, 89000 },
3892 { 47593, 88000 },
3893 { 47282, 87000 },
3894 { 46953, 86000 },
3895 { 46698, 85000 },
3896 { 45617, 84000 },
3897 { 44773, 83000 },
3898 { 43845, 82000 },
3899 { 43020, 81000 },
3900 { 42010, 80000 }, /* -51 dBm */
3901 { 0, 0 },
3902};
3903
3904static u32 interpolate_value(u32 value, struct linear_segments *segments,
3905 unsigned len)
3906{
3907 u64 tmp64;
3908 u32 dx;
3909 s32 dy;
3910 int i, ret;
3911
3912 if (value >= segments[0].x)
3913 return segments[0].y;
3914 if (value < segments[len-1].x)
3915 return segments[len-1].y;
3916
3917 for (i = 1; i < len - 1; i++) {
3918 /* If value is identical, no need to interpolate */
3919 if (value == segments[i].x)
3920 return segments[i].y;
3921 if (value > segments[i].x)
3922 break;
3923 }
3924
3925 /* Linear interpolation between the two (x,y) points */
3926 dy = segments[i - 1].y - segments[i].y;
3927 dx = segments[i - 1].x - segments[i].x;
3928
3929 tmp64 = value - segments[i].x;
3930 tmp64 *= dy;
3931 do_div(tmp64, dx);
3932 ret = segments[i].y + tmp64;
3933
3934 return ret;
3935}
3936
Mauro Carvalho Chehab704f01b2013-12-17 10:08:20 -03003937static u32 dib8000_get_time_us(struct dvb_frontend *fe, int layer)
3938{
3939 struct dib8000_state *state = fe->demodulator_priv;
3940 struct dtv_frontend_properties *c = &state->fe[0]->dtv_property_cache;
3941 int ini_layer, end_layer, i;
Mauro Carvalho Chehab4bf48152013-12-20 08:11:31 -02003942 u64 time_us, tmp64;
Mauro Carvalho Chehab704f01b2013-12-17 10:08:20 -03003943 u32 tmp, denom;
Mauro Carvalho Chehabe4a3bc12014-01-13 15:14:33 -02003944 int guard, rate_num, rate_denum = 1, bits_per_symbol, nsegs;
3945 int interleaving = 0, fft_div;
Mauro Carvalho Chehab704f01b2013-12-17 10:08:20 -03003946
3947 if (layer >= 0) {
3948 ini_layer = layer;
3949 end_layer = layer + 1;
3950 } else {
3951 ini_layer = 0;
3952 end_layer = 3;
3953 }
3954
3955 switch (c->guard_interval) {
3956 case GUARD_INTERVAL_1_4:
3957 guard = 4;
3958 break;
3959 case GUARD_INTERVAL_1_8:
3960 guard = 8;
3961 break;
3962 case GUARD_INTERVAL_1_16:
3963 guard = 16;
3964 break;
3965 default:
3966 case GUARD_INTERVAL_1_32:
3967 guard = 32;
3968 break;
3969 }
3970
3971 switch (c->transmission_mode) {
3972 case TRANSMISSION_MODE_2K:
3973 fft_div = 4;
3974 break;
3975 case TRANSMISSION_MODE_4K:
3976 fft_div = 2;
3977 break;
3978 default:
3979 case TRANSMISSION_MODE_8K:
3980 fft_div = 1;
3981 break;
3982 }
3983
3984 denom = 0;
3985 for (i = ini_layer; i < end_layer; i++) {
3986 nsegs = c->layer[i].segment_count;
3987 if (nsegs == 0 || nsegs > 13)
3988 continue;
3989
3990 switch (c->layer[i].modulation) {
3991 case DQPSK:
3992 case QPSK:
3993 bits_per_symbol = 2;
3994 break;
3995 case QAM_16:
3996 bits_per_symbol = 4;
3997 break;
3998 default:
3999 case QAM_64:
4000 bits_per_symbol = 6;
4001 break;
4002 }
4003
4004 switch (c->layer[i].fec) {
4005 case FEC_1_2:
4006 rate_num = 1;
4007 rate_denum = 2;
4008 break;
4009 case FEC_2_3:
4010 rate_num = 2;
4011 rate_denum = 3;
4012 break;
4013 case FEC_3_4:
4014 rate_num = 3;
4015 rate_denum = 4;
4016 break;
4017 case FEC_5_6:
4018 rate_num = 5;
4019 rate_denum = 6;
4020 break;
4021 default:
4022 case FEC_7_8:
4023 rate_num = 7;
4024 rate_denum = 8;
4025 break;
4026 }
4027
4028 interleaving = c->layer[i].interleaving;
4029
4030 denom += bits_per_symbol * rate_num * fft_div * nsegs * 384;
4031 }
4032
4033 /* If all goes wrong, wait for 1s for the next stats */
4034 if (!denom)
4035 return 0;
4036
4037 /* Estimate the period for the total bit rate */
4038 time_us = rate_denum * (1008 * 1562500L);
Mauro Carvalho Chehab4bf48152013-12-20 08:11:31 -02004039 tmp64 = time_us;
4040 do_div(tmp64, guard);
4041 time_us = time_us + tmp64;
Mauro Carvalho Chehab704f01b2013-12-17 10:08:20 -03004042 time_us += denom / 2;
4043 do_div(time_us, denom);
4044
4045 tmp = 1008 * 96 * interleaving;
4046 time_us += tmp + tmp / guard;
4047
4048 return time_us;
4049}
4050
Mauro Carvalho Chehab6ef06e72013-12-16 19:10:59 -03004051static int dib8000_get_stats(struct dvb_frontend *fe, fe_status_t stat)
4052{
4053 struct dib8000_state *state = fe->demodulator_priv;
4054 struct dtv_frontend_properties *c = &state->fe[0]->dtv_property_cache;
Mauro Carvalho Chehab704f01b2013-12-17 10:08:20 -03004055 int i;
Mauro Carvalho Chehab0400c532013-12-17 11:34:22 -03004056 int show_per_stats = 0;
4057 u32 time_us = 0, snr, val;
4058 u64 blocks;
Mauro Carvalho Chehab42ff76b2013-12-16 21:45:19 -03004059 s32 db;
Mauro Carvalho Chehab6ef06e72013-12-16 19:10:59 -03004060 u16 strength;
4061
4062 /* Get Signal strength */
4063 dib8000_read_signal_strength(fe, &strength);
Mauro Carvalho Chehab42ff76b2013-12-16 21:45:19 -03004064 val = strength;
4065 db = interpolate_value(val,
4066 strength_to_db_table,
4067 ARRAY_SIZE(strength_to_db_table)) - 131000;
4068 c->strength.stat[0].svalue = db;
Mauro Carvalho Chehab6ef06e72013-12-16 19:10:59 -03004069
Mauro Carvalho Chehab704f01b2013-12-17 10:08:20 -03004070 /* UCB/BER/CNR measures require lock */
Mauro Carvalho Chehab6ef06e72013-12-16 19:10:59 -03004071 if (!(stat & FE_HAS_LOCK)) {
Mauro Carvalho Chehab704f01b2013-12-17 10:08:20 -03004072 c->cnr.len = 1;
Mauro Carvalho Chehab0400c532013-12-17 11:34:22 -03004073 c->block_count.len = 1;
Mauro Carvalho Chehab6ef06e72013-12-16 19:10:59 -03004074 c->block_error.len = 1;
4075 c->post_bit_error.len = 1;
4076 c->post_bit_count.len = 1;
Mauro Carvalho Chehab704f01b2013-12-17 10:08:20 -03004077 c->cnr.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
Mauro Carvalho Chehab6ef06e72013-12-16 19:10:59 -03004078 c->post_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
4079 c->post_bit_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
4080 c->block_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
Mauro Carvalho Chehab0400c532013-12-17 11:34:22 -03004081 c->block_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
Mauro Carvalho Chehab6ef06e72013-12-16 19:10:59 -03004082 return 0;
4083 }
4084
Mauro Carvalho Chehab704f01b2013-12-17 10:08:20 -03004085 /* Check if time for stats was elapsed */
Mauro Carvalho Chehab0400c532013-12-17 11:34:22 -03004086 if (time_after(jiffies, state->per_jiffies_stats)) {
4087 state->per_jiffies_stats = jiffies + msecs_to_jiffies(1000);
Mauro Carvalho Chehab6ef06e72013-12-16 19:10:59 -03004088
Mauro Carvalho Chehab704f01b2013-12-17 10:08:20 -03004089 /* Get SNR */
4090 snr = dib8000_get_snr(fe);
4091 for (i = 1; i < MAX_NUMBER_OF_FRONTENDS; i++) {
4092 if (state->fe[i])
4093 snr += dib8000_get_snr(state->fe[i]);
4094 }
4095 snr = snr >> 16;
Mauro Carvalho Chehab6ef06e72013-12-16 19:10:59 -03004096
Mauro Carvalho Chehab704f01b2013-12-17 10:08:20 -03004097 if (snr) {
4098 snr = 10 * intlog10(snr);
4099 snr = (1000L * snr) >> 24;
4100 } else {
4101 snr = 0;
4102 }
4103 c->cnr.stat[0].svalue = snr;
4104 c->cnr.stat[0].scale = FE_SCALE_DECIBEL;
Mauro Carvalho Chehab6ef06e72013-12-16 19:10:59 -03004105
Mauro Carvalho Chehab0400c532013-12-17 11:34:22 -03004106 /* Get UCB measures */
4107 dib8000_read_unc_blocks(fe, &val);
4108 if (val < state->init_ucb)
Mauro Carvalho Chehab5dc85262014-01-13 15:05:44 -02004109 state->init_ucb += 0x100000000LL;
Mauro Carvalho Chehab0400c532013-12-17 11:34:22 -03004110
4111 c->block_error.stat[0].scale = FE_SCALE_COUNTER;
4112 c->block_error.stat[0].uvalue = val + state->init_ucb;
4113
4114 /* Estimate the number of packets based on bitrate */
4115 if (!time_us)
4116 time_us = dib8000_get_time_us(fe, -1);
4117
4118 if (time_us) {
Mauro Carvalho Chehab5dc85262014-01-13 15:05:44 -02004119 blocks = 1250000ULL * 1000000ULL;
Mauro Carvalho Chehab0400c532013-12-17 11:34:22 -03004120 do_div(blocks, time_us * 8 * 204);
4121 c->block_count.stat[0].scale = FE_SCALE_COUNTER;
4122 c->block_count.stat[0].uvalue += blocks;
4123 }
4124
4125 show_per_stats = 1;
4126 }
4127
4128 /* Get post-BER measures */
4129 if (time_after(jiffies, state->ber_jiffies_stats)) {
4130 time_us = dib8000_get_time_us(fe, -1);
4131 state->ber_jiffies_stats = jiffies + msecs_to_jiffies((time_us + 500) / 1000);
4132
4133 dprintk("Next all layers stats available in %u us.", time_us);
Mauro Carvalho Chehab704f01b2013-12-17 10:08:20 -03004134
4135 dib8000_read_ber(fe, &val);
4136 c->post_bit_error.stat[0].scale = FE_SCALE_COUNTER;
4137 c->post_bit_error.stat[0].uvalue += val;
4138
4139 c->post_bit_count.stat[0].scale = FE_SCALE_COUNTER;
4140 c->post_bit_count.stat[0].uvalue += 100000000;
Mauro Carvalho Chehab704f01b2013-12-17 10:08:20 -03004141 }
Mauro Carvalho Chehab6ef06e72013-12-16 19:10:59 -03004142
4143 if (state->revision < 0x8002)
4144 return 0;
4145
4146 c->block_error.len = 4;
4147 c->post_bit_error.len = 4;
4148 c->post_bit_count.len = 4;
4149
4150 for (i = 0; i < 3; i++) {
Mauro Carvalho Chehab0400c532013-12-17 11:34:22 -03004151 unsigned nsegs = c->layer[i].segment_count;
4152
4153 if (nsegs == 0 || nsegs > 13)
Mauro Carvalho Chehab704f01b2013-12-17 10:08:20 -03004154 continue;
Mauro Carvalho Chehab6ef06e72013-12-16 19:10:59 -03004155
Mauro Carvalho Chehab0400c532013-12-17 11:34:22 -03004156 time_us = 0;
Mauro Carvalho Chehab6ef06e72013-12-16 19:10:59 -03004157
Mauro Carvalho Chehab0400c532013-12-17 11:34:22 -03004158 if (time_after(jiffies, state->ber_jiffies_stats_layer[i])) {
4159 time_us = dib8000_get_time_us(fe, i);
Mauro Carvalho Chehab6ef06e72013-12-16 19:10:59 -03004160
Mauro Carvalho Chehab0400c532013-12-17 11:34:22 -03004161 state->ber_jiffies_stats_layer[i] = jiffies + msecs_to_jiffies((time_us + 500) / 1000);
4162 dprintk("Next layer %c stats will be available in %u us\n",
4163 'A' + i, time_us);
Mauro Carvalho Chehab704f01b2013-12-17 10:08:20 -03004164
Mauro Carvalho Chehab0400c532013-12-17 11:34:22 -03004165 val = dib8000_read_word(state, per_layer_regs[i].ber);
4166 c->post_bit_error.stat[1 + i].scale = FE_SCALE_COUNTER;
4167 c->post_bit_error.stat[1 + i].uvalue += val;
Mauro Carvalho Chehab704f01b2013-12-17 10:08:20 -03004168
Mauro Carvalho Chehab0400c532013-12-17 11:34:22 -03004169 c->post_bit_count.stat[1 + i].scale = FE_SCALE_COUNTER;
4170 c->post_bit_count.stat[1 + i].uvalue += 100000000;
4171 }
4172
4173 if (show_per_stats) {
4174 val = dib8000_read_word(state, per_layer_regs[i].per);
4175
4176 c->block_error.stat[1 + i].scale = FE_SCALE_COUNTER;
4177 c->block_error.stat[1 + i].uvalue += val;
4178
4179 if (!time_us)
4180 time_us = dib8000_get_time_us(fe, i);
4181 if (time_us) {
Mauro Carvalho Chehab5dc85262014-01-13 15:05:44 -02004182 blocks = 1250000ULL * 1000000ULL;
Mauro Carvalho Chehab0400c532013-12-17 11:34:22 -03004183 do_div(blocks, time_us * 8 * 204);
4184 c->block_count.stat[0].scale = FE_SCALE_COUNTER;
4185 c->block_count.stat[0].uvalue += blocks;
4186 }
4187 }
Mauro Carvalho Chehab6ef06e72013-12-16 19:10:59 -03004188 }
4189 return 0;
4190}
4191
Mauro Carvalho Chehabd44913c2014-05-29 09:20:17 -03004192static int dib8000_set_slave_frontend(struct dvb_frontend *fe, struct dvb_frontend *fe_slave)
Olivier Grenie4c70e072011-01-03 15:33:37 -03004193{
4194 struct dib8000_state *state = fe->demodulator_priv;
4195 u8 index_frontend = 1;
4196
4197 while ((index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL))
4198 index_frontend++;
4199 if (index_frontend < MAX_NUMBER_OF_FRONTENDS) {
4200 dprintk("set slave fe %p to index %i", fe_slave, index_frontend);
4201 state->fe[index_frontend] = fe_slave;
4202 return 0;
4203 }
4204
4205 dprintk("too many slave frontend");
4206 return -ENOMEM;
4207}
Olivier Grenie4c70e072011-01-03 15:33:37 -03004208
Mauro Carvalho Chehabd44913c2014-05-29 09:20:17 -03004209static int dib8000_remove_slave_frontend(struct dvb_frontend *fe)
Olivier Grenie4c70e072011-01-03 15:33:37 -03004210{
4211 struct dib8000_state *state = fe->demodulator_priv;
4212 u8 index_frontend = 1;
4213
4214 while ((index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL))
4215 index_frontend++;
4216 if (index_frontend != 1) {
4217 dprintk("remove slave fe %p (index %i)", state->fe[index_frontend-1], index_frontend-1);
4218 state->fe[index_frontend] = NULL;
4219 return 0;
4220 }
4221
4222 dprintk("no frontend to be removed");
4223 return -ENODEV;
4224}
Olivier Grenie4c70e072011-01-03 15:33:37 -03004225
Mauro Carvalho Chehabd44913c2014-05-29 09:20:17 -03004226static struct dvb_frontend *dib8000_get_slave_frontend(struct dvb_frontend *fe, int slave_index)
Olivier Grenie4c70e072011-01-03 15:33:37 -03004227{
4228 struct dib8000_state *state = fe->demodulator_priv;
4229
4230 if (slave_index >= MAX_NUMBER_OF_FRONTENDS)
4231 return NULL;
4232 return state->fe[slave_index];
4233}
Olivier Grenie4c70e072011-01-03 15:33:37 -03004234
Mauro Carvalho Chehabd44913c2014-05-29 09:20:17 -03004235static int dib8000_i2c_enumeration(struct i2c_adapter *host, int no_of_demods,
Olivier Grenie0c32dbd2011-08-10 05:17:18 -03004236 u8 default_addr, u8 first_addr, u8 is_dib8096p)
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03004237{
Olivier Grenie5a0deee2011-05-03 12:27:33 -03004238 int k = 0, ret = 0;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03004239 u8 new_addr = 0;
4240 struct i2c_device client = {.adap = host };
4241
Olivier Grenie5a0deee2011-05-03 12:27:33 -03004242 client.i2c_write_buffer = kzalloc(4 * sizeof(u8), GFP_KERNEL);
4243 if (!client.i2c_write_buffer) {
4244 dprintk("%s: not enough memory", __func__);
4245 return -ENOMEM;
4246 }
4247 client.i2c_read_buffer = kzalloc(4 * sizeof(u8), GFP_KERNEL);
4248 if (!client.i2c_read_buffer) {
4249 dprintk("%s: not enough memory", __func__);
4250 ret = -ENOMEM;
Patrick Boettcher79fcce32011-08-03 12:08:21 -03004251 goto error_memory_read;
Olivier Grenie5a0deee2011-05-03 12:27:33 -03004252 }
Patrick Boettcher79fcce32011-08-03 12:08:21 -03004253 client.i2c_buffer_lock = kzalloc(sizeof(struct mutex), GFP_KERNEL);
4254 if (!client.i2c_buffer_lock) {
4255 dprintk("%s: not enough memory", __func__);
4256 ret = -ENOMEM;
4257 goto error_memory_lock;
4258 }
4259 mutex_init(client.i2c_buffer_lock);
Olivier Grenie5a0deee2011-05-03 12:27:33 -03004260
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03004261 for (k = no_of_demods - 1; k >= 0; k--) {
4262 /* designated i2c address */
4263 new_addr = first_addr + (k << 1);
4264
4265 client.addr = new_addr;
Olivier Grenie0c32dbd2011-08-10 05:17:18 -03004266 if (!is_dib8096p)
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03004267 dib8000_i2c_write16(&client, 1287, 0x0003); /* sram lead in, rdy */
Olivier Grenie0c32dbd2011-08-10 05:17:18 -03004268 if (dib8000_identify(&client) == 0) {
4269 /* sram lead in, rdy */
4270 if (!is_dib8096p)
4271 dib8000_i2c_write16(&client, 1287, 0x0003);
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03004272 client.addr = default_addr;
4273 if (dib8000_identify(&client) == 0) {
4274 dprintk("#%d: not identified", k);
Olivier Grenie5a0deee2011-05-03 12:27:33 -03004275 ret = -EINVAL;
4276 goto error;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03004277 }
4278 }
4279
4280 /* start diversity to pull_down div_str - just for i2c-enumeration */
4281 dib8000_i2c_write16(&client, 1286, (1 << 10) | (4 << 6));
4282
4283 /* set new i2c address and force divstart */
4284 dib8000_i2c_write16(&client, 1285, (new_addr << 2) | 0x2);
4285 client.addr = new_addr;
4286 dib8000_identify(&client);
4287
4288 dprintk("IC %d initialized (to i2c_address 0x%x)", k, new_addr);
4289 }
4290
4291 for (k = 0; k < no_of_demods; k++) {
4292 new_addr = first_addr | (k << 1);
4293 client.addr = new_addr;
4294
4295 // unforce divstr
4296 dib8000_i2c_write16(&client, 1285, new_addr << 2);
4297
4298 /* deactivate div - it was just for i2c-enumeration */
4299 dib8000_i2c_write16(&client, 1286, 0);
4300 }
4301
Olivier Grenie5a0deee2011-05-03 12:27:33 -03004302error:
Patrick Boettcher79fcce32011-08-03 12:08:21 -03004303 kfree(client.i2c_buffer_lock);
4304error_memory_lock:
Olivier Grenie5a0deee2011-05-03 12:27:33 -03004305 kfree(client.i2c_read_buffer);
Patrick Boettcher79fcce32011-08-03 12:08:21 -03004306error_memory_read:
Olivier Grenie5a0deee2011-05-03 12:27:33 -03004307 kfree(client.i2c_write_buffer);
4308
4309 return ret;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03004310}
4311
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03004312static int dib8000_fe_get_tune_settings(struct dvb_frontend *fe, struct dvb_frontend_tune_settings *tune)
4313{
4314 tune->min_delay_ms = 1000;
4315 tune->step_size = 0;
4316 tune->max_drift = 0;
4317 return 0;
4318}
4319
4320static void dib8000_release(struct dvb_frontend *fe)
4321{
4322 struct dib8000_state *st = fe->demodulator_priv;
Olivier Grenie4c70e072011-01-03 15:33:37 -03004323 u8 index_frontend;
4324
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03004325 for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (st->fe[index_frontend] != NULL); index_frontend++)
Olivier Grenie4c70e072011-01-03 15:33:37 -03004326 dvb_frontend_detach(st->fe[index_frontend]);
4327
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03004328 dibx000_exit_i2c_master(&st->i2c_master);
Olivier Grenie0c32dbd2011-08-10 05:17:18 -03004329 i2c_del_adapter(&st->dib8096p_tuner_adap);
Olivier Grenie4c70e072011-01-03 15:33:37 -03004330 kfree(st->fe[0]);
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03004331 kfree(st);
4332}
4333
Mauro Carvalho Chehabd44913c2014-05-29 09:20:17 -03004334static 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 -03004335{
4336 struct dib8000_state *st = fe->demodulator_priv;
4337 return dibx000_get_i2c_adapter(&st->i2c_master, intf, gating);
4338}
4339
Mauro Carvalho Chehabd44913c2014-05-29 09:20:17 -03004340static int dib8000_pid_filter_ctrl(struct dvb_frontend *fe, u8 onoff)
Olivier Grenief8731f42009-09-18 04:08:43 -03004341{
4342 struct dib8000_state *st = fe->demodulator_priv;
Olivier Grenie4c70e072011-01-03 15:33:37 -03004343 u16 val = dib8000_read_word(st, 299) & 0xffef;
4344 val |= (onoff & 0x1) << 4;
Olivier Grenief8731f42009-09-18 04:08:43 -03004345
Olivier Grenie4c70e072011-01-03 15:33:37 -03004346 dprintk("pid filter enabled %d", onoff);
4347 return dib8000_write_word(st, 299, val);
Olivier Grenief8731f42009-09-18 04:08:43 -03004348}
Olivier Grenief8731f42009-09-18 04:08:43 -03004349
Mauro Carvalho Chehabd44913c2014-05-29 09:20:17 -03004350static int dib8000_pid_filter(struct dvb_frontend *fe, u8 id, u16 pid, u8 onoff)
Olivier Grenief8731f42009-09-18 04:08:43 -03004351{
4352 struct dib8000_state *st = fe->demodulator_priv;
Olivier Grenie4c70e072011-01-03 15:33:37 -03004353 dprintk("Index %x, PID %d, OnOff %d", id, pid, onoff);
4354 return dib8000_write_word(st, 305 + id, onoff ? (1 << 13) | pid : 0);
Olivier Grenief8731f42009-09-18 04:08:43 -03004355}
Olivier Grenief8731f42009-09-18 04:08:43 -03004356
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03004357static const struct dvb_frontend_ops dib8000_ops = {
Mauro Carvalho Chehab490ecd62011-12-22 20:38:27 -03004358 .delsys = { SYS_ISDBT },
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03004359 .info = {
4360 .name = "DiBcom 8000 ISDB-T",
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03004361 .frequency_min = 44250000,
4362 .frequency_max = 867250000,
4363 .frequency_stepsize = 62500,
4364 .caps = FE_CAN_INVERSION_AUTO |
4365 FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
4366 FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
4367 FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO |
4368 FE_CAN_TRANSMISSION_MODE_AUTO | FE_CAN_GUARD_INTERVAL_AUTO | FE_CAN_RECOVER | FE_CAN_HIERARCHY_AUTO,
4369 },
4370
4371 .release = dib8000_release,
4372
4373 .init = dib8000_wakeup,
4374 .sleep = dib8000_sleep,
4375
Mauro Carvalho Chehab490ecd62011-12-22 20:38:27 -03004376 .set_frontend = dib8000_set_frontend,
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03004377 .get_tune_settings = dib8000_fe_get_tune_settings,
Mauro Carvalho Chehab490ecd62011-12-22 20:38:27 -03004378 .get_frontend = dib8000_get_frontend,
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03004379
4380 .read_status = dib8000_read_status,
4381 .read_ber = dib8000_read_ber,
4382 .read_signal_strength = dib8000_read_signal_strength,
4383 .read_snr = dib8000_read_snr,
4384 .read_ucblocks = dib8000_read_unc_blocks,
4385};
4386
Mauro Carvalho Chehabd44913c2014-05-29 09:20:17 -03004387static struct dvb_frontend *dib8000_init(struct i2c_adapter *i2c_adap, u8 i2c_addr, struct dib8000_config *cfg)
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03004388{
4389 struct dvb_frontend *fe;
4390 struct dib8000_state *state;
4391
Mauro Carvalho Chehabb9bc7d52014-05-29 09:20:16 -03004392 dprintk("dib8000_init");
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03004393
4394 state = kzalloc(sizeof(struct dib8000_state), GFP_KERNEL);
4395 if (state == NULL)
4396 return NULL;
Olivier Grenie4c70e072011-01-03 15:33:37 -03004397 fe = kzalloc(sizeof(struct dvb_frontend), GFP_KERNEL);
4398 if (fe == NULL)
Dan Carpentered54c0e2011-01-19 11:27:58 -03004399 goto error;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03004400
4401 memcpy(&state->cfg, cfg, sizeof(struct dib8000_config));
4402 state->i2c.adap = i2c_adap;
4403 state->i2c.addr = i2c_addr;
Olivier Grenie5a0deee2011-05-03 12:27:33 -03004404 state->i2c.i2c_write_buffer = state->i2c_write_buffer;
4405 state->i2c.i2c_read_buffer = state->i2c_read_buffer;
Patrick Boettcher79fcce32011-08-03 12:08:21 -03004406 mutex_init(&state->i2c_buffer_lock);
4407 state->i2c.i2c_buffer_lock = &state->i2c_buffer_lock;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03004408 state->gpio_val = cfg->gpio_val;
4409 state->gpio_dir = cfg->gpio_dir;
4410
4411 /* Ensure the output mode remains at the previous default if it's
4412 * not specifically set by the caller.
4413 */
4414 if ((state->cfg.output_mode != OUTMODE_MPEG2_SERIAL) && (state->cfg.output_mode != OUTMODE_MPEG2_PAR_GATED_CLK))
4415 state->cfg.output_mode = OUTMODE_MPEG2_FIFO;
4416
Olivier Grenie4c70e072011-01-03 15:33:37 -03004417 state->fe[0] = fe;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03004418 fe->demodulator_priv = state;
Olivier Grenie4c70e072011-01-03 15:33:37 -03004419 memcpy(&state->fe[0]->ops, &dib8000_ops, sizeof(struct dvb_frontend_ops));
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03004420
4421 state->timf_default = cfg->pll->timf;
4422
4423 if (dib8000_identify(&state->i2c) == 0)
4424 goto error;
4425
4426 dibx000_init_i2c_master(&state->i2c_master, DIB8000, state->i2c.adap, state->i2c.addr);
4427
Olivier Grenie0c32dbd2011-08-10 05:17:18 -03004428 /* init 8096p tuner adapter */
4429 strncpy(state->dib8096p_tuner_adap.name, "DiB8096P tuner interface",
4430 sizeof(state->dib8096p_tuner_adap.name));
4431 state->dib8096p_tuner_adap.algo = &dib8096p_tuner_xfer_algo;
4432 state->dib8096p_tuner_adap.algo_data = NULL;
4433 state->dib8096p_tuner_adap.dev.parent = state->i2c.adap->dev.parent;
4434 i2c_set_adapdata(&state->dib8096p_tuner_adap, state);
4435 i2c_add_adapter(&state->dib8096p_tuner_adap);
4436
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03004437 dib8000_reset(fe);
4438
4439 dib8000_write_word(state, 285, (dib8000_read_word(state, 285) & ~0x60) | (3 << 5)); /* ber_rs_len = 3 */
Patrick Boettcher173a64c2013-04-22 12:45:52 -03004440 state->current_demod_bw = 6000;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03004441
4442 return fe;
4443
Patrick Boettcher173a64c2013-04-22 12:45:52 -03004444error:
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03004445 kfree(state);
4446 return NULL;
4447}
4448
Mauro Carvalho Chehabd44913c2014-05-29 09:20:17 -03004449void *dib8000_attach(struct dib8000_ops *ops)
4450{
4451 if (!ops)
4452 return NULL;
4453
4454 ops->pwm_agc_reset = dib8000_pwm_agc_reset;
4455 ops->get_dc_power = dib8090p_get_dc_power;
4456 ops->set_gpio = dib8000_set_gpio;
4457 ops->get_slave_frontend = dib8000_get_slave_frontend;
4458 ops->set_tune_state = dib8000_set_tune_state;
4459 ops->pid_filter_ctrl = dib8000_pid_filter_ctrl;
4460 ops->remove_slave_frontend = dib8000_remove_slave_frontend;
4461 ops->get_adc_power = dib8000_get_adc_power;
4462 ops->update_pll = dib8000_update_pll;
4463 ops->tuner_sleep = dib8096p_tuner_sleep;
4464 ops->get_tune_state = dib8000_get_tune_state;
4465 ops->get_i2c_tuner = dib8096p_get_i2c_tuner;
4466 ops->set_slave_frontend = dib8000_set_slave_frontend;
4467 ops->pid_filter = dib8000_pid_filter;
4468 ops->ctrl_timf = dib8000_ctrl_timf;
4469 ops->init = dib8000_init;
4470 ops->get_i2c_master = dib8000_get_i2c_master;
4471 ops->i2c_enumeration = dib8000_i2c_enumeration;
4472 ops->set_wbd_ref = dib8000_set_wbd_ref;
4473
4474 return ops;
4475}
4476EXPORT_SYMBOL(dib8000_attach);
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03004477
4478MODULE_AUTHOR("Olivier Grenie <Olivier.Grenie@dibcom.fr, " "Patrick Boettcher <pboettcher@dibcom.fr>");
4479MODULE_DESCRIPTION("Driver for the DiBcom 8000 ISDB-T demodulator");
4480MODULE_LICENSE("GPL");