blob: 61e31f2d2f71c3f3246eaa28cc35a01b2b7e9bdb [file] [log] [blame]
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001/*
2 * Linux-DVB Driver for DiBcom's DiB8000 chip (ISDB-T).
3 *
4 * Copyright (C) 2009 DiBcom (http://www.dibcom.fr/)
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License as
8 * published by the Free Software Foundation, version 2.
9 */
10#include <linux/kernel.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090011#include <linux/slab.h>
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -030012#include <linux/i2c.h>
Patrick Boettcher79fcce32011-08-03 12:08:21 -030013#include <linux/mutex.h>
Mauro Carvalho Chehabb4600d72013-12-16 20:00:34 -030014#include <asm/div64.h>
Patrick Boettcher79fcce32011-08-03 12:08:21 -030015
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -030016#include "dvb_math.h"
17
18#include "dvb_frontend.h"
19
20#include "dib8000.h"
21
22#define LAYER_ALL -1
23#define LAYER_A 1
24#define LAYER_B 2
25#define LAYER_C 3
26
Olivier Grenie4c70e072011-01-03 15:33:37 -030027#define MAX_NUMBER_OF_FRONTENDS 6
Patrick Boettcher173a64c2013-04-22 12:45:52 -030028/* #define DIB8000_AGC_FREEZE */
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -030029
Patrick Boettcher78f3bc62009-08-17 12:53:51 -030030static int debug;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -030031module_param(debug, int, 0644);
32MODULE_PARM_DESC(debug, "turn on debugging (default: 0)");
33
34#define dprintk(args...) do { if (debug) { printk(KERN_DEBUG "DiB8000: "); printk(args); printk("\n"); } } while (0)
35
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -030036struct i2c_device {
37 struct i2c_adapter *adap;
38 u8 addr;
Olivier Grenie5a0deee2011-05-03 12:27:33 -030039 u8 *i2c_write_buffer;
40 u8 *i2c_read_buffer;
Patrick Boettcher79fcce32011-08-03 12:08:21 -030041 struct mutex *i2c_buffer_lock;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -030042};
43
Patrick Boettcher173a64c2013-04-22 12:45:52 -030044enum param_loop_step {
45 LOOP_TUNE_1,
46 LOOP_TUNE_2
47};
48
49enum dib8000_autosearch_step {
50 AS_START = 0,
51 AS_SEARCHING_FFT,
52 AS_SEARCHING_GUARD,
53 AS_DONE = 100,
54};
55
56enum timeout_mode {
57 SYMBOL_DEPENDENT_OFF = 0,
58 SYMBOL_DEPENDENT_ON,
59};
60
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -030061struct dib8000_state {
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -030062 struct dib8000_config cfg;
63
64 struct i2c_device i2c;
65
66 struct dibx000_i2c_master i2c_master;
67
68 u16 wbd_ref;
69
70 u8 current_band;
71 u32 current_bandwidth;
72 struct dibx000_agc_config *current_agc;
73 u32 timf;
74 u32 timf_default;
75
76 u8 div_force_off:1;
77 u8 div_state:1;
78 u16 div_sync_wait;
79
80 u8 agc_state;
81 u8 differential_constellation;
82 u8 diversity_onoff;
83
84 s16 ber_monitored_layer;
85 u16 gpio_dir;
86 u16 gpio_val;
87
88 u16 revision;
89 u8 isdbt_cfg_loaded;
90 enum frontend_tune_state tune_state;
Patrick Boettcher173a64c2013-04-22 12:45:52 -030091 s32 status;
Olivier Grenie4c70e072011-01-03 15:33:37 -030092
93 struct dvb_frontend *fe[MAX_NUMBER_OF_FRONTENDS];
Olivier Grenie5a0deee2011-05-03 12:27:33 -030094
95 /* for the I2C transfer */
96 struct i2c_msg msg[2];
97 u8 i2c_write_buffer[4];
98 u8 i2c_read_buffer[2];
Patrick Boettcher79fcce32011-08-03 12:08:21 -030099 struct mutex i2c_buffer_lock;
Olivier Grenie0c32dbd2011-08-10 05:17:18 -0300100 u8 input_mode_mpeg;
101
102 u16 tuner_enable;
103 struct i2c_adapter dib8096p_tuner_adap;
Patrick Boettcher173a64c2013-04-22 12:45:52 -0300104 u16 current_demod_bw;
105
106 u16 seg_mask;
107 u16 seg_diff_mask;
108 u16 mode;
109 u8 layer_b_nb_seg;
110 u8 layer_c_nb_seg;
111
112 u8 channel_parameters_set;
113 u16 autosearch_state;
114 u16 found_nfft;
115 u16 found_guard;
116 u8 subchannel;
117 u8 symbol_duration;
Mauro Carvalho Chehabd6c62b72014-07-04 14:15:37 -0300118 unsigned long timeout;
Patrick Boettcher173a64c2013-04-22 12:45:52 -0300119 u8 longest_intlv_layer;
120 u16 output_mode;
121
Mauro Carvalho Chehab704f01b2013-12-17 10:08:20 -0300122 /* for DVBv5 stats */
Mauro Carvalho Chehab7a9d85d2013-12-17 04:55:26 -0300123 s64 init_ucb;
Mauro Carvalho Chehab0400c532013-12-17 11:34:22 -0300124 unsigned long per_jiffies_stats;
125 unsigned long ber_jiffies_stats;
126 unsigned long ber_jiffies_stats_layer[3];
Mauro Carvalho Chehab704f01b2013-12-17 10:08:20 -0300127
Patrick Boettcher173a64c2013-04-22 12:45:52 -0300128#ifdef DIB8000_AGC_FREEZE
129 u16 agc1_max;
130 u16 agc1_min;
131 u16 agc2_max;
132 u16 agc2_min;
133#endif
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300134};
135
136enum dib8000_power_mode {
Olivier Grenie0c32dbd2011-08-10 05:17:18 -0300137 DIB8000_POWER_ALL = 0,
138 DIB8000_POWER_INTERFACE_ONLY,
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300139};
140
141static u16 dib8000_i2c_read16(struct i2c_device *i2c, u16 reg)
142{
Patrick Boettcher79fcce32011-08-03 12:08:21 -0300143 u16 ret;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300144 struct i2c_msg msg[2] = {
Patrick Boettcher79fcce32011-08-03 12:08:21 -0300145 {.addr = i2c->addr >> 1, .flags = 0, .len = 2},
146 {.addr = i2c->addr >> 1, .flags = I2C_M_RD, .len = 2},
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300147 };
148
Patrick Boettcher79fcce32011-08-03 12:08:21 -0300149 if (mutex_lock_interruptible(i2c->i2c_buffer_lock) < 0) {
150 dprintk("could not acquire lock");
151 return 0;
152 }
153
154 msg[0].buf = i2c->i2c_write_buffer;
Olivier Grenie5a0deee2011-05-03 12:27:33 -0300155 msg[0].buf[0] = reg >> 8;
156 msg[0].buf[1] = reg & 0xff;
Patrick Boettcher79fcce32011-08-03 12:08:21 -0300157 msg[1].buf = i2c->i2c_read_buffer;
Olivier Grenie5a0deee2011-05-03 12:27:33 -0300158
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300159 if (i2c_transfer(i2c->adap, msg, 2) != 2)
160 dprintk("i2c read error on %d", reg);
161
Patrick Boettcher79fcce32011-08-03 12:08:21 -0300162 ret = (msg[1].buf[0] << 8) | msg[1].buf[1];
163 mutex_unlock(i2c->i2c_buffer_lock);
164 return ret;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300165}
166
Mauro Carvalho Chehab5ac64ba2013-12-13 10:35:03 -0300167static u16 __dib8000_read_word(struct dib8000_state *state, u16 reg)
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300168{
Patrick Boettcher79fcce32011-08-03 12:08:21 -0300169 u16 ret;
170
Olivier Grenie5a0deee2011-05-03 12:27:33 -0300171 state->i2c_write_buffer[0] = reg >> 8;
172 state->i2c_write_buffer[1] = reg & 0xff;
173
174 memset(state->msg, 0, 2 * sizeof(struct i2c_msg));
175 state->msg[0].addr = state->i2c.addr >> 1;
176 state->msg[0].flags = 0;
177 state->msg[0].buf = state->i2c_write_buffer;
178 state->msg[0].len = 2;
179 state->msg[1].addr = state->i2c.addr >> 1;
180 state->msg[1].flags = I2C_M_RD;
181 state->msg[1].buf = state->i2c_read_buffer;
182 state->msg[1].len = 2;
183
184 if (i2c_transfer(state->i2c.adap, state->msg, 2) != 2)
185 dprintk("i2c read error on %d", reg);
186
Patrick Boettcher79fcce32011-08-03 12:08:21 -0300187 ret = (state->i2c_read_buffer[0] << 8) | state->i2c_read_buffer[1];
Mauro Carvalho Chehab5ac64ba2013-12-13 10:35:03 -0300188
189 return ret;
190}
191
192static u16 dib8000_read_word(struct dib8000_state *state, u16 reg)
193{
194 u16 ret;
195
196 if (mutex_lock_interruptible(&state->i2c_buffer_lock) < 0) {
197 dprintk("could not acquire lock");
198 return 0;
199 }
200
201 ret = __dib8000_read_word(state, reg);
202
Patrick Boettcher79fcce32011-08-03 12:08:21 -0300203 mutex_unlock(&state->i2c_buffer_lock);
204
205 return ret;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300206}
207
208static u32 dib8000_read32(struct dib8000_state *state, u16 reg)
209{
210 u16 rw[2];
211
Mauro Carvalho Chehab5ac64ba2013-12-13 10:35:03 -0300212 if (mutex_lock_interruptible(&state->i2c_buffer_lock) < 0) {
213 dprintk("could not acquire lock");
214 return 0;
215 }
216
217 rw[0] = __dib8000_read_word(state, reg + 0);
218 rw[1] = __dib8000_read_word(state, reg + 1);
219
220 mutex_unlock(&state->i2c_buffer_lock);
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300221
222 return ((rw[0] << 16) | (rw[1]));
223}
224
225static int dib8000_i2c_write16(struct i2c_device *i2c, u16 reg, u16 val)
226{
Patrick Boettcher79fcce32011-08-03 12:08:21 -0300227 struct i2c_msg msg = {.addr = i2c->addr >> 1, .flags = 0, .len = 4};
Olivier Grenie5a0deee2011-05-03 12:27:33 -0300228 int ret = 0;
229
Patrick Boettcher79fcce32011-08-03 12:08:21 -0300230 if (mutex_lock_interruptible(i2c->i2c_buffer_lock) < 0) {
231 dprintk("could not acquire lock");
232 return -EINVAL;
233 }
234
235 msg.buf = i2c->i2c_write_buffer;
Olivier Grenie5a0deee2011-05-03 12:27:33 -0300236 msg.buf[0] = (reg >> 8) & 0xff;
237 msg.buf[1] = reg & 0xff;
238 msg.buf[2] = (val >> 8) & 0xff;
239 msg.buf[3] = val & 0xff;
240
241 ret = i2c_transfer(i2c->adap, &msg, 1) != 1 ? -EREMOTEIO : 0;
Patrick Boettcher79fcce32011-08-03 12:08:21 -0300242 mutex_unlock(i2c->i2c_buffer_lock);
Olivier Grenie5a0deee2011-05-03 12:27:33 -0300243
244 return ret;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300245}
246
247static int dib8000_write_word(struct dib8000_state *state, u16 reg, u16 val)
248{
Patrick Boettcher79fcce32011-08-03 12:08:21 -0300249 int ret;
250
251 if (mutex_lock_interruptible(&state->i2c_buffer_lock) < 0) {
252 dprintk("could not acquire lock");
253 return -EINVAL;
254 }
255
Olivier Grenie5a0deee2011-05-03 12:27:33 -0300256 state->i2c_write_buffer[0] = (reg >> 8) & 0xff;
257 state->i2c_write_buffer[1] = reg & 0xff;
258 state->i2c_write_buffer[2] = (val >> 8) & 0xff;
259 state->i2c_write_buffer[3] = val & 0xff;
260
261 memset(&state->msg[0], 0, sizeof(struct i2c_msg));
262 state->msg[0].addr = state->i2c.addr >> 1;
263 state->msg[0].flags = 0;
264 state->msg[0].buf = state->i2c_write_buffer;
265 state->msg[0].len = 4;
266
Patrick Boettcher79fcce32011-08-03 12:08:21 -0300267 ret = (i2c_transfer(state->i2c.adap, state->msg, 1) != 1 ?
268 -EREMOTEIO : 0);
269 mutex_unlock(&state->i2c_buffer_lock);
270
271 return ret;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300272}
273
Olivier Grenie4c70e072011-01-03 15:33:37 -0300274static const s16 coeff_2k_sb_1seg_dqpsk[8] = {
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300275 (769 << 5) | 0x0a, (745 << 5) | 0x03, (595 << 5) | 0x0d, (769 << 5) | 0x0a, (920 << 5) | 0x09, (784 << 5) | 0x02, (519 << 5) | 0x0c,
Olivier Grenie4c70e072011-01-03 15:33:37 -0300276 (920 << 5) | 0x09
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300277};
278
Olivier Grenie4c70e072011-01-03 15:33:37 -0300279static const s16 coeff_2k_sb_1seg[8] = {
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300280 (692 << 5) | 0x0b, (683 << 5) | 0x01, (519 << 5) | 0x09, (692 << 5) | 0x0b, 0 | 0x1f, 0 | 0x1f, 0 | 0x1f, 0 | 0x1f
281};
282
Olivier Grenie4c70e072011-01-03 15:33:37 -0300283static const s16 coeff_2k_sb_3seg_0dqpsk_1dqpsk[8] = {
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300284 (832 << 5) | 0x10, (912 << 5) | 0x05, (900 << 5) | 0x12, (832 << 5) | 0x10, (-931 << 5) | 0x0f, (912 << 5) | 0x04, (807 << 5) | 0x11,
Olivier Grenie4c70e072011-01-03 15:33:37 -0300285 (-931 << 5) | 0x0f
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300286};
287
Olivier Grenie4c70e072011-01-03 15:33:37 -0300288static const s16 coeff_2k_sb_3seg_0dqpsk[8] = {
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300289 (622 << 5) | 0x0c, (941 << 5) | 0x04, (796 << 5) | 0x10, (622 << 5) | 0x0c, (982 << 5) | 0x0c, (519 << 5) | 0x02, (572 << 5) | 0x0e,
Olivier Grenie4c70e072011-01-03 15:33:37 -0300290 (982 << 5) | 0x0c
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300291};
292
Olivier Grenie4c70e072011-01-03 15:33:37 -0300293static const s16 coeff_2k_sb_3seg_1dqpsk[8] = {
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300294 (699 << 5) | 0x14, (607 << 5) | 0x04, (944 << 5) | 0x13, (699 << 5) | 0x14, (-720 << 5) | 0x0d, (640 << 5) | 0x03, (866 << 5) | 0x12,
Olivier Grenie4c70e072011-01-03 15:33:37 -0300295 (-720 << 5) | 0x0d
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300296};
297
Olivier Grenie4c70e072011-01-03 15:33:37 -0300298static const s16 coeff_2k_sb_3seg[8] = {
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300299 (664 << 5) | 0x0c, (925 << 5) | 0x03, (937 << 5) | 0x10, (664 << 5) | 0x0c, (-610 << 5) | 0x0a, (697 << 5) | 0x01, (836 << 5) | 0x0e,
Olivier Grenie4c70e072011-01-03 15:33:37 -0300300 (-610 << 5) | 0x0a
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300301};
302
Olivier Grenie4c70e072011-01-03 15:33:37 -0300303static const s16 coeff_4k_sb_1seg_dqpsk[8] = {
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300304 (-955 << 5) | 0x0e, (687 << 5) | 0x04, (818 << 5) | 0x10, (-955 << 5) | 0x0e, (-922 << 5) | 0x0d, (750 << 5) | 0x03, (665 << 5) | 0x0f,
Olivier Grenie4c70e072011-01-03 15:33:37 -0300305 (-922 << 5) | 0x0d
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300306};
307
Olivier Grenie4c70e072011-01-03 15:33:37 -0300308static const s16 coeff_4k_sb_1seg[8] = {
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300309 (638 << 5) | 0x0d, (683 << 5) | 0x02, (638 << 5) | 0x0d, (638 << 5) | 0x0d, (-655 << 5) | 0x0a, (517 << 5) | 0x00, (698 << 5) | 0x0d,
Olivier Grenie4c70e072011-01-03 15:33:37 -0300310 (-655 << 5) | 0x0a
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300311};
312
Olivier Grenie4c70e072011-01-03 15:33:37 -0300313static const s16 coeff_4k_sb_3seg_0dqpsk_1dqpsk[8] = {
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300314 (-707 << 5) | 0x14, (910 << 5) | 0x06, (889 << 5) | 0x16, (-707 << 5) | 0x14, (-958 << 5) | 0x13, (993 << 5) | 0x05, (523 << 5) | 0x14,
Olivier Grenie4c70e072011-01-03 15:33:37 -0300315 (-958 << 5) | 0x13
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300316};
317
Olivier Grenie4c70e072011-01-03 15:33:37 -0300318static const s16 coeff_4k_sb_3seg_0dqpsk[8] = {
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300319 (-723 << 5) | 0x13, (910 << 5) | 0x05, (777 << 5) | 0x14, (-723 << 5) | 0x13, (-568 << 5) | 0x0f, (547 << 5) | 0x03, (696 << 5) | 0x12,
Olivier Grenie4c70e072011-01-03 15:33:37 -0300320 (-568 << 5) | 0x0f
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300321};
322
Olivier Grenie4c70e072011-01-03 15:33:37 -0300323static const s16 coeff_4k_sb_3seg_1dqpsk[8] = {
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300324 (-940 << 5) | 0x15, (607 << 5) | 0x05, (915 << 5) | 0x16, (-940 << 5) | 0x15, (-848 << 5) | 0x13, (683 << 5) | 0x04, (543 << 5) | 0x14,
Olivier Grenie4c70e072011-01-03 15:33:37 -0300325 (-848 << 5) | 0x13
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300326};
327
Olivier Grenie4c70e072011-01-03 15:33:37 -0300328static const s16 coeff_4k_sb_3seg[8] = {
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300329 (612 << 5) | 0x12, (910 << 5) | 0x04, (864 << 5) | 0x14, (612 << 5) | 0x12, (-869 << 5) | 0x13, (683 << 5) | 0x02, (869 << 5) | 0x12,
Olivier Grenie4c70e072011-01-03 15:33:37 -0300330 (-869 << 5) | 0x13
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300331};
332
Olivier Grenie4c70e072011-01-03 15:33:37 -0300333static const s16 coeff_8k_sb_1seg_dqpsk[8] = {
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300334 (-835 << 5) | 0x12, (684 << 5) | 0x05, (735 << 5) | 0x14, (-835 << 5) | 0x12, (-598 << 5) | 0x10, (781 << 5) | 0x04, (739 << 5) | 0x13,
Olivier Grenie4c70e072011-01-03 15:33:37 -0300335 (-598 << 5) | 0x10
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300336};
337
Olivier Grenie4c70e072011-01-03 15:33:37 -0300338static const s16 coeff_8k_sb_1seg[8] = {
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300339 (673 << 5) | 0x0f, (683 << 5) | 0x03, (808 << 5) | 0x12, (673 << 5) | 0x0f, (585 << 5) | 0x0f, (512 << 5) | 0x01, (780 << 5) | 0x0f,
Olivier Grenie4c70e072011-01-03 15:33:37 -0300340 (585 << 5) | 0x0f
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300341};
342
Olivier Grenie4c70e072011-01-03 15:33:37 -0300343static const s16 coeff_8k_sb_3seg_0dqpsk_1dqpsk[8] = {
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300344 (863 << 5) | 0x17, (930 << 5) | 0x07, (878 << 5) | 0x19, (863 << 5) | 0x17, (0 << 5) | 0x14, (521 << 5) | 0x05, (980 << 5) | 0x18,
Olivier Grenie4c70e072011-01-03 15:33:37 -0300345 (0 << 5) | 0x14
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300346};
347
Olivier Grenie4c70e072011-01-03 15:33:37 -0300348static const s16 coeff_8k_sb_3seg_0dqpsk[8] = {
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300349 (-924 << 5) | 0x17, (910 << 5) | 0x06, (774 << 5) | 0x17, (-924 << 5) | 0x17, (-877 << 5) | 0x15, (565 << 5) | 0x04, (553 << 5) | 0x15,
Olivier Grenie4c70e072011-01-03 15:33:37 -0300350 (-877 << 5) | 0x15
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300351};
352
Olivier Grenie4c70e072011-01-03 15:33:37 -0300353static const s16 coeff_8k_sb_3seg_1dqpsk[8] = {
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300354 (-921 << 5) | 0x19, (607 << 5) | 0x06, (881 << 5) | 0x19, (-921 << 5) | 0x19, (-921 << 5) | 0x14, (713 << 5) | 0x05, (1018 << 5) | 0x18,
Olivier Grenie4c70e072011-01-03 15:33:37 -0300355 (-921 << 5) | 0x14
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300356};
357
Olivier Grenie4c70e072011-01-03 15:33:37 -0300358static const s16 coeff_8k_sb_3seg[8] = {
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300359 (514 << 5) | 0x14, (910 << 5) | 0x05, (861 << 5) | 0x17, (514 << 5) | 0x14, (690 << 5) | 0x14, (683 << 5) | 0x03, (662 << 5) | 0x15,
Olivier Grenie4c70e072011-01-03 15:33:37 -0300360 (690 << 5) | 0x14
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300361};
362
Olivier Grenie4c70e072011-01-03 15:33:37 -0300363static const s16 ana_fe_coeff_3seg[24] = {
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300364 81, 80, 78, 74, 68, 61, 54, 45, 37, 28, 19, 11, 4, 1022, 1017, 1013, 1010, 1008, 1008, 1008, 1008, 1010, 1014, 1017
365};
366
Olivier Grenie4c70e072011-01-03 15:33:37 -0300367static const s16 ana_fe_coeff_1seg[24] = {
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300368 249, 226, 164, 82, 5, 981, 970, 988, 1018, 20, 31, 26, 8, 1012, 1000, 1018, 1012, 8, 15, 14, 9, 3, 1017, 1003
369};
370
Olivier Grenie4c70e072011-01-03 15:33:37 -0300371static const s16 ana_fe_coeff_13seg[24] = {
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300372 396, 305, 105, -51, -77, -12, 41, 31, -11, -30, -11, 14, 15, -2, -13, -7, 5, 8, 1, -6, -7, -3, 0, 1
373};
374
375static u16 fft_to_mode(struct dib8000_state *state)
376{
377 u16 mode;
Olivier Grenie4c70e072011-01-03 15:33:37 -0300378 switch (state->fe[0]->dtv_property_cache.transmission_mode) {
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300379 case TRANSMISSION_MODE_2K:
380 mode = 1;
381 break;
382 case TRANSMISSION_MODE_4K:
383 mode = 2;
384 break;
385 default:
386 case TRANSMISSION_MODE_AUTO:
387 case TRANSMISSION_MODE_8K:
388 mode = 3;
389 break;
390 }
391 return mode;
392}
393
394static void dib8000_set_acquisition_mode(struct dib8000_state *state)
395{
396 u16 nud = dib8000_read_word(state, 298);
397 nud |= (1 << 3) | (1 << 0);
398 dprintk("acquisition mode activated");
399 dib8000_write_word(state, 298, nud);
400}
Olivier Grenie4c70e072011-01-03 15:33:37 -0300401static int dib8000_set_output_mode(struct dvb_frontend *fe, int mode)
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300402{
Olivier Grenie4c70e072011-01-03 15:33:37 -0300403 struct dib8000_state *state = fe->demodulator_priv;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300404 u16 outreg, fifo_threshold, smo_mode, sram = 0x0205; /* by default SDRAM deintlv is enabled */
405
Patrick Boettcher173a64c2013-04-22 12:45:52 -0300406 state->output_mode = mode;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300407 outreg = 0;
408 fifo_threshold = 1792;
409 smo_mode = (dib8000_read_word(state, 299) & 0x0050) | (1 << 1);
410
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300411 dprintk("-I- Setting output mode for demod %p to %d",
412 &state->fe[0], mode);
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300413
414 switch (mode) {
415 case OUTMODE_MPEG2_PAR_GATED_CLK: // STBs with parallel gated clock
416 outreg = (1 << 10); /* 0x0400 */
417 break;
418 case OUTMODE_MPEG2_PAR_CONT_CLK: // STBs with parallel continues clock
419 outreg = (1 << 10) | (1 << 6); /* 0x0440 */
420 break;
421 case OUTMODE_MPEG2_SERIAL: // STBs with serial input
422 outreg = (1 << 10) | (2 << 6) | (0 << 1); /* 0x0482 */
423 break;
424 case OUTMODE_DIVERSITY:
425 if (state->cfg.hostbus_diversity) {
426 outreg = (1 << 10) | (4 << 6); /* 0x0500 */
427 sram &= 0xfdff;
428 } else
429 sram |= 0x0c00;
430 break;
431 case OUTMODE_MPEG2_FIFO: // e.g. USB feeding
432 smo_mode |= (3 << 1);
433 fifo_threshold = 512;
434 outreg = (1 << 10) | (5 << 6);
435 break;
436 case OUTMODE_HIGH_Z: // disable
437 outreg = 0;
438 break;
439
440 case OUTMODE_ANALOG_ADC:
441 outreg = (1 << 10) | (3 << 6);
442 dib8000_set_acquisition_mode(state);
443 break;
444
445 default:
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300446 dprintk("Unhandled output_mode passed to be set for demod %p",
447 &state->fe[0]);
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300448 return -EINVAL;
449 }
450
451 if (state->cfg.output_mpeg2_in_188_bytes)
452 smo_mode |= (1 << 5);
453
454 dib8000_write_word(state, 299, smo_mode);
455 dib8000_write_word(state, 300, fifo_threshold); /* synchronous fread */
456 dib8000_write_word(state, 1286, outreg);
457 dib8000_write_word(state, 1291, sram);
458
459 return 0;
460}
461
462static int dib8000_set_diversity_in(struct dvb_frontend *fe, int onoff)
463{
464 struct dib8000_state *state = fe->demodulator_priv;
Patrick Boettcher173a64c2013-04-22 12:45:52 -0300465 u16 tmp, sync_wait = dib8000_read_word(state, 273) & 0xfff0;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300466
Patrick Boettcher173a64c2013-04-22 12:45:52 -0300467 dprintk("set diversity input to %i", onoff);
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300468 if (!state->differential_constellation) {
469 dib8000_write_word(state, 272, 1 << 9); //dvsy_off_lmod4 = 1
470 dib8000_write_word(state, 273, sync_wait | (1 << 2) | 2); // sync_enable = 1; comb_mode = 2
471 } else {
472 dib8000_write_word(state, 272, 0); //dvsy_off_lmod4 = 0
473 dib8000_write_word(state, 273, sync_wait); // sync_enable = 0; comb_mode = 0
474 }
475 state->diversity_onoff = onoff;
476
477 switch (onoff) {
478 case 0: /* only use the internal way - not the diversity input */
479 dib8000_write_word(state, 270, 1);
480 dib8000_write_word(state, 271, 0);
481 break;
482 case 1: /* both ways */
483 dib8000_write_word(state, 270, 6);
484 dib8000_write_word(state, 271, 6);
485 break;
486 case 2: /* only the diversity input */
487 dib8000_write_word(state, 270, 0);
488 dib8000_write_word(state, 271, 1);
489 break;
490 }
Patrick Boettcher173a64c2013-04-22 12:45:52 -0300491
492 if (state->revision == 0x8002) {
493 tmp = dib8000_read_word(state, 903);
494 dib8000_write_word(state, 903, tmp & ~(1 << 3));
495 msleep(30);
496 dib8000_write_word(state, 903, tmp | (1 << 3));
497 }
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300498 return 0;
499}
500
501static void dib8000_set_power_mode(struct dib8000_state *state, enum dib8000_power_mode mode)
502{
503 /* by default everything is going to be powered off */
504 u16 reg_774 = 0x3fff, reg_775 = 0xffff, reg_776 = 0xffff,
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300505 reg_900 = (dib8000_read_word(state, 900) & 0xfffc) | 0x3,
Olivier Grenie0c32dbd2011-08-10 05:17:18 -0300506 reg_1280;
507
508 if (state->revision != 0x8090)
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300509 reg_1280 = (dib8000_read_word(state, 1280) & 0x00ff) | 0xff00;
Olivier Grenie0c32dbd2011-08-10 05:17:18 -0300510 else
511 reg_1280 = (dib8000_read_word(state, 1280) & 0x707f) | 0x8f80;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300512
513 /* now, depending on the requested mode, we power on */
514 switch (mode) {
515 /* power up everything in the demod */
Olivier Grenie0c32dbd2011-08-10 05:17:18 -0300516 case DIB8000_POWER_ALL:
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300517 reg_774 = 0x0000;
518 reg_775 = 0x0000;
519 reg_776 = 0x0000;
520 reg_900 &= 0xfffc;
Olivier Grenie0c32dbd2011-08-10 05:17:18 -0300521 if (state->revision != 0x8090)
522 reg_1280 &= 0x00ff;
523 else
524 reg_1280 &= 0x707f;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300525 break;
Olivier Grenie0c32dbd2011-08-10 05:17:18 -0300526 case DIB8000_POWER_INTERFACE_ONLY:
527 if (state->revision != 0x8090)
528 reg_1280 &= 0x00ff;
529 else
530 reg_1280 &= 0xfa7b;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300531 break;
532 }
533
534 dprintk("powermode : 774 : %x ; 775 : %x; 776 : %x ; 900 : %x; 1280 : %x", reg_774, reg_775, reg_776, reg_900, reg_1280);
535 dib8000_write_word(state, 774, reg_774);
536 dib8000_write_word(state, 775, reg_775);
537 dib8000_write_word(state, 776, reg_776);
538 dib8000_write_word(state, 900, reg_900);
539 dib8000_write_word(state, 1280, reg_1280);
540}
541
542static int dib8000_set_adc_state(struct dib8000_state *state, enum dibx000_adc_states no)
543{
544 int ret = 0;
Olivier Grenie0c32dbd2011-08-10 05:17:18 -0300545 u16 reg, reg_907 = dib8000_read_word(state, 907);
546 u16 reg_908 = dib8000_read_word(state, 908);
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300547
548 switch (no) {
549 case DIBX000_SLOW_ADC_ON:
Olivier Grenie0c32dbd2011-08-10 05:17:18 -0300550 if (state->revision != 0x8090) {
551 reg_908 |= (1 << 1) | (1 << 0);
552 ret |= dib8000_write_word(state, 908, reg_908);
553 reg_908 &= ~(1 << 1);
554 } else {
555 reg = dib8000_read_word(state, 1925);
556 /* en_slowAdc = 1 & reset_sladc = 1 */
557 dib8000_write_word(state, 1925, reg |
558 (1<<4) | (1<<2));
559
560 /* read acces to make it works... strange ... */
561 reg = dib8000_read_word(state, 1925);
562 msleep(20);
563 /* en_slowAdc = 1 & reset_sladc = 0 */
564 dib8000_write_word(state, 1925, reg & ~(1<<4));
565
566 reg = dib8000_read_word(state, 921) & ~((0x3 << 14)
567 | (0x3 << 12));
568 /* ref = Vin1 => Vbg ; sel = Vin0 or Vin3 ;
569 (Vin2 = Vcm) */
570 dib8000_write_word(state, 921, reg | (1 << 14)
571 | (3 << 12));
572 }
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300573 break;
574
575 case DIBX000_SLOW_ADC_OFF:
Olivier Grenie0c32dbd2011-08-10 05:17:18 -0300576 if (state->revision == 0x8090) {
577 reg = dib8000_read_word(state, 1925);
578 /* reset_sladc = 1 en_slowAdc = 0 */
579 dib8000_write_word(state, 1925,
580 (reg & ~(1<<2)) | (1<<4));
581 }
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300582 reg_908 |= (1 << 1) | (1 << 0);
583 break;
584
585 case DIBX000_ADC_ON:
586 reg_907 &= 0x0fff;
587 reg_908 &= 0x0003;
588 break;
589
590 case DIBX000_ADC_OFF: // leave the VBG voltage on
Mauro Carvalho Chehabc063c7c2014-07-04 14:15:28 -0300591 reg_907 = (1 << 13) | (1 << 12);
592 reg_908 = (1 << 6) | (1 << 5) | (1 << 4) | (1 << 3) | (1 << 1);
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300593 break;
594
595 case DIBX000_VBG_ENABLE:
596 reg_907 &= ~(1 << 15);
597 break;
598
599 case DIBX000_VBG_DISABLE:
600 reg_907 |= (1 << 15);
601 break;
602
603 default:
604 break;
605 }
606
607 ret |= dib8000_write_word(state, 907, reg_907);
608 ret |= dib8000_write_word(state, 908, reg_908);
609
610 return ret;
611}
612
Olivier Grenie4c70e072011-01-03 15:33:37 -0300613static int dib8000_set_bandwidth(struct dvb_frontend *fe, u32 bw)
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300614{
Olivier Grenie4c70e072011-01-03 15:33:37 -0300615 struct dib8000_state *state = fe->demodulator_priv;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300616 u32 timf;
617
618 if (bw == 0)
619 bw = 6000;
620
621 if (state->timf == 0) {
622 dprintk("using default timf");
623 timf = state->timf_default;
624 } else {
625 dprintk("using updated timf");
626 timf = state->timf;
627 }
628
629 dib8000_write_word(state, 29, (u16) ((timf >> 16) & 0xffff));
630 dib8000_write_word(state, 30, (u16) ((timf) & 0xffff));
631
632 return 0;
633}
634
635static int dib8000_sad_calib(struct dib8000_state *state)
636{
Patrick Boettcher173a64c2013-04-22 12:45:52 -0300637 u8 sad_sel = 3;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300638
Patrick Boettcher173a64c2013-04-22 12:45:52 -0300639 if (state->revision == 0x8090) {
640 dib8000_write_word(state, 922, (sad_sel << 2));
641 dib8000_write_word(state, 923, 2048);
642
643 dib8000_write_word(state, 922, (sad_sel << 2) | 0x1);
644 dib8000_write_word(state, 922, (sad_sel << 2));
645 } else {
646 /* internal */
647 dib8000_write_word(state, 923, (0 << 1) | (0 << 0));
648 dib8000_write_word(state, 924, 776);
649
650 /* do the calibration */
651 dib8000_write_word(state, 923, (1 << 0));
652 dib8000_write_word(state, 923, (0 << 0));
653 }
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300654
655 msleep(1);
656 return 0;
657}
658
Mauro Carvalho Chehabd44913c2014-05-29 09:20:17 -0300659static int dib8000_set_wbd_ref(struct dvb_frontend *fe, u16 value)
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300660{
661 struct dib8000_state *state = fe->demodulator_priv;
662 if (value > 4095)
663 value = 4095;
664 state->wbd_ref = value;
665 return dib8000_write_word(state, 106, value);
666}
Patrick Boettcher173a64c2013-04-22 12:45:52 -0300667
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300668static void dib8000_reset_pll_common(struct dib8000_state *state, const struct dibx000_bandwidth_config *bw)
669{
670 dprintk("ifreq: %d %x, inversion: %d", bw->ifreq, bw->ifreq, bw->ifreq >> 25);
Olivier Grenie0c32dbd2011-08-10 05:17:18 -0300671 if (state->revision != 0x8090) {
672 dib8000_write_word(state, 23,
673 (u16) (((bw->internal * 1000) >> 16) & 0xffff));
674 dib8000_write_word(state, 24,
675 (u16) ((bw->internal * 1000) & 0xffff));
676 } else {
677 dib8000_write_word(state, 23, (u16) (((bw->internal / 2 * 1000) >> 16) & 0xffff));
678 dib8000_write_word(state, 24,
679 (u16) ((bw->internal / 2 * 1000) & 0xffff));
680 }
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300681 dib8000_write_word(state, 27, (u16) ((bw->ifreq >> 16) & 0x01ff));
682 dib8000_write_word(state, 28, (u16) (bw->ifreq & 0xffff));
683 dib8000_write_word(state, 26, (u16) ((bw->ifreq >> 25) & 0x0003));
684
Olivier Grenie0c32dbd2011-08-10 05:17:18 -0300685 if (state->revision != 0x8090)
686 dib8000_write_word(state, 922, bw->sad_cfg);
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300687}
688
689static void dib8000_reset_pll(struct dib8000_state *state)
690{
691 const struct dibx000_bandwidth_config *pll = state->cfg.pll;
Olivier Grenie0c32dbd2011-08-10 05:17:18 -0300692 u16 clk_cfg1, reg;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300693
Olivier Grenie0c32dbd2011-08-10 05:17:18 -0300694 if (state->revision != 0x8090) {
695 dib8000_write_word(state, 901,
696 (pll->pll_prediv << 8) | (pll->pll_ratio << 0));
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300697
Olivier Grenie0c32dbd2011-08-10 05:17:18 -0300698 clk_cfg1 = (1 << 10) | (0 << 9) | (pll->IO_CLK_en_core << 8) |
699 (pll->bypclk_div << 5) | (pll->enable_refdiv << 4) |
700 (1 << 3) | (pll->pll_range << 1) |
701 (pll->pll_reset << 0);
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300702
Olivier Grenie0c32dbd2011-08-10 05:17:18 -0300703 dib8000_write_word(state, 902, clk_cfg1);
704 clk_cfg1 = (clk_cfg1 & 0xfff7) | (pll->pll_bypass << 3);
705 dib8000_write_word(state, 902, clk_cfg1);
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300706
Olivier Grenie0c32dbd2011-08-10 05:17:18 -0300707 dprintk("clk_cfg1: 0x%04x", clk_cfg1);
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300708
Olivier Grenie0c32dbd2011-08-10 05:17:18 -0300709 /* smpl_cfg: P_refclksel=2, P_ensmplsel=1 nodivsmpl=1 */
710 if (state->cfg.pll->ADClkSrc == 0)
711 dib8000_write_word(state, 904,
712 (0 << 15) | (0 << 12) | (0 << 10) |
713 (pll->modulo << 8) |
714 (pll->ADClkSrc << 7) | (0 << 1));
715 else if (state->cfg.refclksel != 0)
716 dib8000_write_word(state, 904, (0 << 15) | (1 << 12) |
717 ((state->cfg.refclksel & 0x3) << 10) |
718 (pll->modulo << 8) |
719 (pll->ADClkSrc << 7) | (0 << 1));
720 else
721 dib8000_write_word(state, 904, (0 << 15) | (1 << 12) |
722 (3 << 10) | (pll->modulo << 8) |
723 (pll->ADClkSrc << 7) | (0 << 1));
724 } else {
725 dib8000_write_word(state, 1856, (!pll->pll_reset<<13) |
726 (pll->pll_range<<12) | (pll->pll_ratio<<6) |
727 (pll->pll_prediv));
728
729 reg = dib8000_read_word(state, 1857);
730 dib8000_write_word(state, 1857, reg|(!pll->pll_bypass<<15));
731
732 reg = dib8000_read_word(state, 1858); /* Force clk out pll /2 */
733 dib8000_write_word(state, 1858, reg | 1);
734
735 dib8000_write_word(state, 904, (pll->modulo << 8));
736 }
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300737
738 dib8000_reset_pll_common(state, pll);
739}
740
Mauro Carvalho Chehabd44913c2014-05-29 09:20:17 -0300741static int dib8000_update_pll(struct dvb_frontend *fe,
Patrick Boettcher173a64c2013-04-22 12:45:52 -0300742 struct dibx000_bandwidth_config *pll, u32 bw, u8 ratio)
Olivier Grenie0c32dbd2011-08-10 05:17:18 -0300743{
744 struct dib8000_state *state = fe->demodulator_priv;
745 u16 reg_1857, reg_1856 = dib8000_read_word(state, 1856);
Patrick Boettcher173a64c2013-04-22 12:45:52 -0300746 u8 loopdiv, prediv, oldprediv = state->cfg.pll->pll_prediv ;
Olivier Grenie0c32dbd2011-08-10 05:17:18 -0300747 u32 internal, xtal;
748
749 /* get back old values */
750 prediv = reg_1856 & 0x3f;
751 loopdiv = (reg_1856 >> 6) & 0x3f;
752
Patrick Boettcher173a64c2013-04-22 12:45:52 -0300753 if ((pll == NULL) || (pll->pll_prediv == prediv &&
754 pll->pll_ratio == loopdiv))
755 return -EINVAL;
756
757 dprintk("Updating pll (prediv: old = %d new = %d ; loopdiv : old = %d new = %d)", prediv, pll->pll_prediv, loopdiv, pll->pll_ratio);
758 if (state->revision == 0x8090) {
Olivier Grenie0c32dbd2011-08-10 05:17:18 -0300759 reg_1856 &= 0xf000;
760 reg_1857 = dib8000_read_word(state, 1857);
761 /* disable PLL */
762 dib8000_write_word(state, 1857, reg_1857 & ~(1 << 15));
763
764 dib8000_write_word(state, 1856, reg_1856 |
765 ((pll->pll_ratio & 0x3f) << 6) |
766 (pll->pll_prediv & 0x3f));
767
768 /* write new system clk into P_sec_len */
769 internal = dib8000_read32(state, 23) / 1000;
770 dprintk("Old Internal = %d", internal);
771 xtal = 2 * (internal / loopdiv) * prediv;
772 internal = 1000 * (xtal/pll->pll_prediv) * pll->pll_ratio;
773 dprintk("Xtal = %d , New Fmem = %d New Fdemod = %d, New Fsampling = %d", xtal, internal/1000, internal/2000, internal/8000);
774 dprintk("New Internal = %d", internal);
775
776 dib8000_write_word(state, 23,
777 (u16) (((internal / 2) >> 16) & 0xffff));
778 dib8000_write_word(state, 24, (u16) ((internal / 2) & 0xffff));
779 /* enable PLL */
780 dib8000_write_word(state, 1857, reg_1857 | (1 << 15));
781
782 while (((dib8000_read_word(state, 1856)>>15)&0x1) != 1)
783 dprintk("Waiting for PLL to lock");
784
785 /* verify */
786 reg_1856 = dib8000_read_word(state, 1856);
787 dprintk("PLL Updated with prediv = %d and loopdiv = %d",
788 reg_1856&0x3f, (reg_1856>>6)&0x3f);
Patrick Boettcher173a64c2013-04-22 12:45:52 -0300789 } else {
790 if (bw != state->current_demod_bw) {
791 /** Bandwidth change => force PLL update **/
792 dprintk("PLL: Bandwidth Change %d MHz -> %d MHz (prediv: %d->%d)", state->current_demod_bw / 1000, bw / 1000, oldprediv, state->cfg.pll->pll_prediv);
Olivier Grenie0c32dbd2011-08-10 05:17:18 -0300793
Patrick Boettcher173a64c2013-04-22 12:45:52 -0300794 if (state->cfg.pll->pll_prediv != oldprediv) {
795 /** Full PLL change only if prediv is changed **/
796
797 /** full update => bypass and reconfigure **/
798 dprintk("PLL: New Setting for %d MHz Bandwidth (prediv: %d, ratio: %d)", bw/1000, state->cfg.pll->pll_prediv, state->cfg.pll->pll_ratio);
799 dib8000_write_word(state, 902, dib8000_read_word(state, 902) | (1<<3)); /* bypass PLL */
800 dib8000_reset_pll(state);
801 dib8000_write_word(state, 898, 0x0004); /* sad */
802 } else
803 ratio = state->cfg.pll->pll_ratio;
804
805 state->current_demod_bw = bw;
806 }
807
808 if (ratio != 0) {
809 /** ratio update => only change ratio **/
810 dprintk("PLL: Update ratio (prediv: %d, ratio: %d)", state->cfg.pll->pll_prediv, ratio);
811 dib8000_write_word(state, 901, (state->cfg.pll->pll_prediv << 8) | (ratio << 0)); /* only the PLL ratio is updated. */
812 }
Mauro Carvalho Chehab6ef06e72013-12-16 19:10:59 -0300813 }
Patrick Boettcher173a64c2013-04-22 12:45:52 -0300814
815 return 0;
Olivier Grenie0c32dbd2011-08-10 05:17:18 -0300816}
Olivier Grenie0c32dbd2011-08-10 05:17:18 -0300817
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300818static int dib8000_reset_gpio(struct dib8000_state *st)
819{
820 /* reset the GPIOs */
821 dib8000_write_word(st, 1029, st->cfg.gpio_dir);
822 dib8000_write_word(st, 1030, st->cfg.gpio_val);
823
824 /* TODO 782 is P_gpio_od */
825
826 dib8000_write_word(st, 1032, st->cfg.gpio_pwm_pos);
827
828 dib8000_write_word(st, 1037, st->cfg.pwm_freq_div);
829 return 0;
830}
831
832static int dib8000_cfg_gpio(struct dib8000_state *st, u8 num, u8 dir, u8 val)
833{
834 st->cfg.gpio_dir = dib8000_read_word(st, 1029);
835 st->cfg.gpio_dir &= ~(1 << num); /* reset the direction bit */
836 st->cfg.gpio_dir |= (dir & 0x1) << num; /* set the new direction */
837 dib8000_write_word(st, 1029, st->cfg.gpio_dir);
838
839 st->cfg.gpio_val = dib8000_read_word(st, 1030);
840 st->cfg.gpio_val &= ~(1 << num); /* reset the direction bit */
841 st->cfg.gpio_val |= (val & 0x01) << num; /* set the new value */
842 dib8000_write_word(st, 1030, st->cfg.gpio_val);
843
844 dprintk("gpio dir: %x: gpio val: %x", st->cfg.gpio_dir, st->cfg.gpio_val);
845
846 return 0;
847}
848
Mauro Carvalho Chehabd44913c2014-05-29 09:20:17 -0300849static int dib8000_set_gpio(struct dvb_frontend *fe, u8 num, u8 dir, u8 val)
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300850{
851 struct dib8000_state *state = fe->demodulator_priv;
852 return dib8000_cfg_gpio(state, num, dir, val);
853}
854
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300855static const u16 dib8000_defaults[] = {
856 /* auto search configuration - lock0 by default waiting
857 * for cpil_lock; lock1 cpil_lock; lock2 tmcc_sync_lock */
858 3, 7,
859 0x0004,
860 0x0400,
861 0x0814,
862
863 12, 11,
864 0x001b,
865 0x7740,
866 0x005b,
867 0x8d80,
868 0x01c9,
869 0xc380,
870 0x0000,
871 0x0080,
872 0x0000,
873 0x0090,
874 0x0001,
875 0xd4c0,
876
877 /*1, 32,
Olivier Grenie4c70e072011-01-03 15:33:37 -0300878 0x6680 // P_corm_thres Lock algorithms configuration */
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300879
880 11, 80, /* set ADC level to -16 */
881 (1 << 13) - 825 - 117,
882 (1 << 13) - 837 - 117,
883 (1 << 13) - 811 - 117,
884 (1 << 13) - 766 - 117,
885 (1 << 13) - 737 - 117,
886 (1 << 13) - 693 - 117,
887 (1 << 13) - 648 - 117,
888 (1 << 13) - 619 - 117,
889 (1 << 13) - 575 - 117,
890 (1 << 13) - 531 - 117,
891 (1 << 13) - 501 - 117,
892
893 4, 108,
894 0,
895 0,
896 0,
897 0,
898
899 1, 175,
900 0x0410,
901 1, 179,
902 8192, // P_fft_nb_to_cut
903
904 6, 181,
905 0x2800, // P_coff_corthres_ ( 2k 4k 8k ) 0x2800
906 0x2800,
907 0x2800,
908 0x2800, // P_coff_cpilthres_ ( 2k 4k 8k ) 0x2800
909 0x2800,
910 0x2800,
911
912 2, 193,
913 0x0666, // P_pha3_thres
914 0x0000, // P_cti_use_cpe, P_cti_use_prog
915
916 2, 205,
917 0x200f, // P_cspu_regul, P_cspu_win_cut
918 0x000f, // P_des_shift_work
919
920 5, 215,
921 0x023d, // P_adp_regul_cnt
922 0x00a4, // P_adp_noise_cnt
923 0x00a4, // P_adp_regul_ext
924 0x7ff0, // P_adp_noise_ext
925 0x3ccc, // P_adp_fil
926
927 1, 230,
928 0x0000, // P_2d_byp_ti_num
929
930 1, 263,
931 0x800, //P_equal_thres_wgn
932
933 1, 268,
934 (2 << 9) | 39, // P_equal_ctrl_synchro, P_equal_speedmode
935
936 1, 270,
937 0x0001, // P_div_lock0_wait
938 1, 285,
939 0x0020, //p_fec_
940 1, 299,
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300941 0x0062, /* P_smo_mode, P_smo_rs_discard, P_smo_fifo_flush, P_smo_pid_parse, P_smo_error_discard */
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300942
943 1, 338,
944 (1 << 12) | // P_ctrl_corm_thres4pre_freq_inh=1
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300945 (1 << 10) |
946 (0 << 9) | /* P_ctrl_pre_freq_inh=0 */
947 (3 << 5) | /* P_ctrl_pre_freq_step=3 */
948 (1 << 0), /* P_pre_freq_win_len=1 */
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300949
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300950 0,
951};
952
953static u16 dib8000_identify(struct i2c_device *client)
954{
955 u16 value;
956
957 //because of glitches sometimes
958 value = dib8000_i2c_read16(client, 896);
959
960 if ((value = dib8000_i2c_read16(client, 896)) != 0x01b3) {
961 dprintk("wrong Vendor ID (read=0x%x)", value);
962 return 0;
963 }
964
965 value = dib8000_i2c_read16(client, 897);
Olivier Grenie0c32dbd2011-08-10 05:17:18 -0300966 if (value != 0x8000 && value != 0x8001 &&
967 value != 0x8002 && value != 0x8090) {
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300968 dprintk("wrong Device ID (%x)", value);
969 return 0;
970 }
971
972 switch (value) {
973 case 0x8000:
974 dprintk("found DiB8000A");
975 break;
976 case 0x8001:
977 dprintk("found DiB8000B");
978 break;
979 case 0x8002:
980 dprintk("found DiB8000C");
981 break;
Olivier Grenie0c32dbd2011-08-10 05:17:18 -0300982 case 0x8090:
983 dprintk("found DiB8096P");
984 break;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300985 }
986 return value;
987}
988
Mauro Carvalho Chehab7a9d85d2013-12-17 04:55:26 -0300989static int dib8000_read_unc_blocks(struct dvb_frontend *fe, u32 *unc);
990
Mauro Carvalho Chehab6ef06e72013-12-16 19:10:59 -0300991static void dib8000_reset_stats(struct dvb_frontend *fe)
992{
993 struct dib8000_state *state = fe->demodulator_priv;
994 struct dtv_frontend_properties *c = &state->fe[0]->dtv_property_cache;
Mauro Carvalho Chehab7a9d85d2013-12-17 04:55:26 -0300995 u32 ucb;
Mauro Carvalho Chehab6ef06e72013-12-16 19:10:59 -0300996
997 memset(&c->strength, 0, sizeof(c->strength));
998 memset(&c->cnr, 0, sizeof(c->cnr));
999 memset(&c->post_bit_error, 0, sizeof(c->post_bit_error));
1000 memset(&c->post_bit_count, 0, sizeof(c->post_bit_count));
1001 memset(&c->block_error, 0, sizeof(c->block_error));
1002
1003 c->strength.len = 1;
1004 c->cnr.len = 1;
1005 c->block_error.len = 1;
Mauro Carvalho Chehab0400c532013-12-17 11:34:22 -03001006 c->block_count.len = 1;
Mauro Carvalho Chehab6ef06e72013-12-16 19:10:59 -03001007 c->post_bit_error.len = 1;
1008 c->post_bit_count.len = 1;
1009
Mauro Carvalho Chehabb4600d72013-12-16 20:00:34 -03001010 c->strength.stat[0].scale = FE_SCALE_DECIBEL;
Mauro Carvalho Chehab6ef06e72013-12-16 19:10:59 -03001011 c->strength.stat[0].uvalue = 0;
1012
1013 c->cnr.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
1014 c->block_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
Mauro Carvalho Chehab0400c532013-12-17 11:34:22 -03001015 c->block_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
Mauro Carvalho Chehab6ef06e72013-12-16 19:10:59 -03001016 c->post_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
1017 c->post_bit_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
Mauro Carvalho Chehab7a9d85d2013-12-17 04:55:26 -03001018
1019 dib8000_read_unc_blocks(fe, &ucb);
Mauro Carvalho Chehab704f01b2013-12-17 10:08:20 -03001020
Mauro Carvalho Chehab7a9d85d2013-12-17 04:55:26 -03001021 state->init_ucb = -ucb;
Mauro Carvalho Chehab0400c532013-12-17 11:34:22 -03001022 state->ber_jiffies_stats = 0;
1023 state->per_jiffies_stats = 0;
1024 memset(&state->ber_jiffies_stats_layer, 0,
1025 sizeof(state->ber_jiffies_stats_layer));
Mauro Carvalho Chehab6ef06e72013-12-16 19:10:59 -03001026}
1027
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001028static int dib8000_reset(struct dvb_frontend *fe)
1029{
1030 struct dib8000_state *state = fe->demodulator_priv;
1031
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001032 if ((state->revision = dib8000_identify(&state->i2c)) == 0)
1033 return -EINVAL;
1034
Olivier Grenie0c32dbd2011-08-10 05:17:18 -03001035 /* sram lead in, rdy */
1036 if (state->revision != 0x8090)
1037 dib8000_write_word(state, 1287, 0x0003);
1038
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001039 if (state->revision == 0x8000)
1040 dprintk("error : dib8000 MA not supported");
1041
1042 dibx000_reset_i2c_master(&state->i2c_master);
1043
Olivier Grenie0c32dbd2011-08-10 05:17:18 -03001044 dib8000_set_power_mode(state, DIB8000_POWER_ALL);
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001045
1046 /* always leave the VBG voltage on - it consumes almost nothing but takes a long time to start */
Patrick Boettcher173a64c2013-04-22 12:45:52 -03001047 dib8000_set_adc_state(state, DIBX000_ADC_OFF);
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001048
1049 /* restart all parts */
1050 dib8000_write_word(state, 770, 0xffff);
1051 dib8000_write_word(state, 771, 0xffff);
1052 dib8000_write_word(state, 772, 0xfffc);
Mauro Carvalho Chehab6d384542014-07-04 14:15:33 -03001053 dib8000_write_word(state, 898, 0x000c); /* restart sad */
Olivier Grenie0c32dbd2011-08-10 05:17:18 -03001054 if (state->revision == 0x8090)
1055 dib8000_write_word(state, 1280, 0x0045);
1056 else
1057 dib8000_write_word(state, 1280, 0x004d);
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001058 dib8000_write_word(state, 1281, 0x000c);
1059
1060 dib8000_write_word(state, 770, 0x0000);
1061 dib8000_write_word(state, 771, 0x0000);
1062 dib8000_write_word(state, 772, 0x0000);
1063 dib8000_write_word(state, 898, 0x0004); // sad
1064 dib8000_write_word(state, 1280, 0x0000);
1065 dib8000_write_word(state, 1281, 0x0000);
1066
1067 /* drives */
Olivier Grenie0c32dbd2011-08-10 05:17:18 -03001068 if (state->revision != 0x8090) {
1069 if (state->cfg.drives)
1070 dib8000_write_word(state, 906, state->cfg.drives);
1071 else {
1072 dprintk("using standard PAD-drive-settings, please adjust settings in config-struct to be optimal.");
1073 /* min drive SDRAM - not optimal - adjust */
1074 dib8000_write_word(state, 906, 0x2d98);
1075 }
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001076 }
1077
1078 dib8000_reset_pll(state);
Olivier Grenie0c32dbd2011-08-10 05:17:18 -03001079 if (state->revision != 0x8090)
1080 dib8000_write_word(state, 898, 0x0004);
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001081
1082 if (dib8000_reset_gpio(state) != 0)
1083 dprintk("GPIO reset was not successful.");
1084
Olivier Grenie0c32dbd2011-08-10 05:17:18 -03001085 if ((state->revision != 0x8090) &&
1086 (dib8000_set_output_mode(fe, OUTMODE_HIGH_Z) != 0))
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001087 dprintk("OUTPUT_MODE could not be resetted.");
1088
1089 state->current_agc = NULL;
1090
1091 // P_iqc_alpha_pha, P_iqc_alpha_amp, P_iqc_dcc_alpha, ...
1092 /* P_iqc_ca2 = 0; P_iqc_impnc_on = 0; P_iqc_mode = 0; */
1093 if (state->cfg.pll->ifreq == 0)
1094 dib8000_write_word(state, 40, 0x0755); /* P_iqc_corr_inh = 0 enable IQcorr block */
1095 else
1096 dib8000_write_word(state, 40, 0x1f55); /* P_iqc_corr_inh = 1 disable IQcorr block */
1097
1098 {
1099 u16 l = 0, r;
1100 const u16 *n;
1101 n = dib8000_defaults;
1102 l = *n++;
1103 while (l) {
1104 r = *n++;
1105 do {
1106 dib8000_write_word(state, r, *n++);
1107 r++;
1108 } while (--l);
1109 l = *n++;
1110 }
1111 }
Patrick Boettcher173a64c2013-04-22 12:45:52 -03001112
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001113 state->isdbt_cfg_loaded = 0;
1114
1115 //div_cfg override for special configs
Patrick Boettcher173a64c2013-04-22 12:45:52 -03001116 if ((state->revision != 8090) && (state->cfg.div_cfg != 0))
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001117 dib8000_write_word(state, 903, state->cfg.div_cfg);
1118
1119 /* unforce divstr regardless whether i2c enumeration was done or not */
1120 dib8000_write_word(state, 1285, dib8000_read_word(state, 1285) & ~(1 << 1));
1121
Olivier Grenie4c70e072011-01-03 15:33:37 -03001122 dib8000_set_bandwidth(fe, 6000);
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001123
1124 dib8000_set_adc_state(state, DIBX000_SLOW_ADC_ON);
Patrick Boettcher173a64c2013-04-22 12:45:52 -03001125 dib8000_sad_calib(state);
1126 if (state->revision != 0x8090)
Olivier Grenie0c32dbd2011-08-10 05:17:18 -03001127 dib8000_set_adc_state(state, DIBX000_SLOW_ADC_OFF);
Patrick Boettcher173a64c2013-04-22 12:45:52 -03001128
1129 /* ber_rs_len = 3 */
1130 dib8000_write_word(state, 285, (dib8000_read_word(state, 285) & ~0x60) | (3 << 5));
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001131
Olivier Grenie0c32dbd2011-08-10 05:17:18 -03001132 dib8000_set_power_mode(state, DIB8000_POWER_INTERFACE_ONLY);
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001133
Mauro Carvalho Chehab6ef06e72013-12-16 19:10:59 -03001134 dib8000_reset_stats(fe);
1135
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001136 return 0;
1137}
1138
1139static void dib8000_restart_agc(struct dib8000_state *state)
1140{
1141 // P_restart_iqc & P_restart_agc
1142 dib8000_write_word(state, 770, 0x0a00);
1143 dib8000_write_word(state, 770, 0x0000);
1144}
1145
1146static int dib8000_update_lna(struct dib8000_state *state)
1147{
1148 u16 dyn_gain;
1149
1150 if (state->cfg.update_lna) {
1151 // read dyn_gain here (because it is demod-dependent and not tuner)
1152 dyn_gain = dib8000_read_word(state, 390);
1153
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001154 if (state->cfg.update_lna(state->fe[0], dyn_gain)) {
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001155 dib8000_restart_agc(state);
1156 return 1;
1157 }
1158 }
1159 return 0;
1160}
1161
1162static int dib8000_set_agc_config(struct dib8000_state *state, u8 band)
1163{
1164 struct dibx000_agc_config *agc = NULL;
1165 int i;
Olivier Grenie0c32dbd2011-08-10 05:17:18 -03001166 u16 reg;
1167
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001168 if (state->current_band == band && state->current_agc != NULL)
1169 return 0;
1170 state->current_band = band;
1171
1172 for (i = 0; i < state->cfg.agc_config_count; i++)
1173 if (state->cfg.agc[i].band_caps & band) {
1174 agc = &state->cfg.agc[i];
1175 break;
1176 }
1177
1178 if (agc == NULL) {
1179 dprintk("no valid AGC configuration found for band 0x%02x", band);
1180 return -EINVAL;
1181 }
1182
1183 state->current_agc = agc;
1184
1185 /* AGC */
1186 dib8000_write_word(state, 76, agc->setup);
1187 dib8000_write_word(state, 77, agc->inv_gain);
1188 dib8000_write_word(state, 78, agc->time_stabiliz);
1189 dib8000_write_word(state, 101, (agc->alpha_level << 12) | agc->thlock);
1190
1191 // Demod AGC loop configuration
1192 dib8000_write_word(state, 102, (agc->alpha_mant << 5) | agc->alpha_exp);
1193 dib8000_write_word(state, 103, (agc->beta_mant << 6) | agc->beta_exp);
1194
1195 dprintk("WBD: ref: %d, sel: %d, active: %d, alpha: %d",
1196 state->wbd_ref != 0 ? state->wbd_ref : agc->wbd_ref, agc->wbd_sel, !agc->perform_agc_softsplit, agc->wbd_sel);
1197
1198 /* AGC continued */
1199 if (state->wbd_ref != 0)
1200 dib8000_write_word(state, 106, state->wbd_ref);
1201 else // use default
1202 dib8000_write_word(state, 106, agc->wbd_ref);
Olivier Grenie0c32dbd2011-08-10 05:17:18 -03001203
1204 if (state->revision == 0x8090) {
1205 reg = dib8000_read_word(state, 922) & (0x3 << 2);
1206 dib8000_write_word(state, 922, reg | (agc->wbd_sel << 2));
1207 }
1208
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001209 dib8000_write_word(state, 107, (agc->wbd_alpha << 9) | (agc->perform_agc_softsplit << 8));
1210 dib8000_write_word(state, 108, agc->agc1_max);
1211 dib8000_write_word(state, 109, agc->agc1_min);
1212 dib8000_write_word(state, 110, agc->agc2_max);
1213 dib8000_write_word(state, 111, agc->agc2_min);
1214 dib8000_write_word(state, 112, (agc->agc1_pt1 << 8) | agc->agc1_pt2);
1215 dib8000_write_word(state, 113, (agc->agc1_slope1 << 8) | agc->agc1_slope2);
1216 dib8000_write_word(state, 114, (agc->agc2_pt1 << 8) | agc->agc2_pt2);
1217 dib8000_write_word(state, 115, (agc->agc2_slope1 << 8) | agc->agc2_slope2);
1218
1219 dib8000_write_word(state, 75, agc->agc1_pt3);
Olivier Grenie0c32dbd2011-08-10 05:17:18 -03001220 if (state->revision != 0x8090)
1221 dib8000_write_word(state, 923,
1222 (dib8000_read_word(state, 923) & 0xffe3) |
1223 (agc->wbd_inv << 4) | (agc->wbd_sel << 2));
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001224
1225 return 0;
1226}
1227
Mauro Carvalho Chehabd44913c2014-05-29 09:20:17 -03001228static void dib8000_pwm_agc_reset(struct dvb_frontend *fe)
Olivier Grenie03245a52009-12-04 13:27:57 -03001229{
1230 struct dib8000_state *state = fe->demodulator_priv;
1231 dib8000_set_adc_state(state, DIBX000_ADC_ON);
1232 dib8000_set_agc_config(state, (unsigned char)(BAND_OF_FREQUENCY(fe->dtv_property_cache.frequency / 1000)));
1233}
Olivier Grenie03245a52009-12-04 13:27:57 -03001234
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001235static int dib8000_agc_soft_split(struct dib8000_state *state)
1236{
1237 u16 agc, split_offset;
1238
1239 if (!state->current_agc || !state->current_agc->perform_agc_softsplit || state->current_agc->split.max == 0)
Mauro Carvalho Chehabd6c62b72014-07-04 14:15:37 -03001240 return 0;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001241
1242 // n_agc_global
1243 agc = dib8000_read_word(state, 390);
1244
1245 if (agc > state->current_agc->split.min_thres)
1246 split_offset = state->current_agc->split.min;
1247 else if (agc < state->current_agc->split.max_thres)
1248 split_offset = state->current_agc->split.max;
1249 else
1250 split_offset = state->current_agc->split.max *
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001251 (agc - state->current_agc->split.min_thres) /
1252 (state->current_agc->split.max_thres - state->current_agc->split.min_thres);
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001253
1254 dprintk("AGC split_offset: %d", split_offset);
1255
1256 // P_agc_force_split and P_agc_split_offset
1257 dib8000_write_word(state, 107, (dib8000_read_word(state, 107) & 0xff00) | split_offset);
1258 return 5000;
1259}
1260
1261static int dib8000_agc_startup(struct dvb_frontend *fe)
1262{
1263 struct dib8000_state *state = fe->demodulator_priv;
1264 enum frontend_tune_state *tune_state = &state->tune_state;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001265 int ret = 0;
Olivier Grenie0c32dbd2011-08-10 05:17:18 -03001266 u16 reg, upd_demod_gain_period = 0x8000;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001267
1268 switch (*tune_state) {
1269 case CT_AGC_START:
1270 // set power-up level: interf+analog+AGC
1271
Olivier Grenie0c32dbd2011-08-10 05:17:18 -03001272 if (state->revision != 0x8090)
1273 dib8000_set_adc_state(state, DIBX000_ADC_ON);
1274 else {
1275 dib8000_set_power_mode(state, DIB8000_POWER_ALL);
1276
1277 reg = dib8000_read_word(state, 1947)&0xff00;
1278 dib8000_write_word(state, 1946,
1279 upd_demod_gain_period & 0xFFFF);
1280 /* bit 14 = enDemodGain */
1281 dib8000_write_word(state, 1947, reg | (1<<14) |
1282 ((upd_demod_gain_period >> 16) & 0xFF));
1283
1284 /* enable adc i & q */
1285 reg = dib8000_read_word(state, 1920);
1286 dib8000_write_word(state, 1920, (reg | 0x3) &
1287 (~(1 << 7)));
1288 }
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001289
1290 if (dib8000_set_agc_config(state, (unsigned char)(BAND_OF_FREQUENCY(fe->dtv_property_cache.frequency / 1000))) != 0) {
1291 *tune_state = CT_AGC_STOP;
1292 state->status = FE_STATUS_TUNE_FAILED;
1293 break;
1294 }
1295
1296 ret = 70;
1297 *tune_state = CT_AGC_STEP_0;
1298 break;
1299
1300 case CT_AGC_STEP_0:
1301 //AGC initialization
1302 if (state->cfg.agc_control)
Olivier Grenie4c70e072011-01-03 15:33:37 -03001303 state->cfg.agc_control(fe, 1);
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001304
1305 dib8000_restart_agc(state);
1306
1307 // wait AGC rough lock time
1308 ret = 50;
1309 *tune_state = CT_AGC_STEP_1;
1310 break;
1311
1312 case CT_AGC_STEP_1:
1313 // wait AGC accurate lock time
1314 ret = 70;
1315
1316 if (dib8000_update_lna(state))
1317 // wait only AGC rough lock time
1318 ret = 50;
1319 else
1320 *tune_state = CT_AGC_STEP_2;
1321 break;
1322
1323 case CT_AGC_STEP_2:
1324 dib8000_agc_soft_split(state);
1325
1326 if (state->cfg.agc_control)
Olivier Grenie4c70e072011-01-03 15:33:37 -03001327 state->cfg.agc_control(fe, 0);
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001328
1329 *tune_state = CT_AGC_STOP;
1330 break;
1331 default:
1332 ret = dib8000_agc_soft_split(state);
1333 break;
1334 }
1335 return ret;
1336
1337}
1338
Olivier Grenie0c32dbd2011-08-10 05:17:18 -03001339static void dib8096p_host_bus_drive(struct dib8000_state *state, u8 drive)
1340{
1341 u16 reg;
1342
1343 drive &= 0x7;
1344
1345 /* drive host bus 2, 3, 4 */
1346 reg = dib8000_read_word(state, 1798) &
1347 ~(0x7 | (0x7 << 6) | (0x7 << 12));
1348 reg |= (drive<<12) | (drive<<6) | drive;
1349 dib8000_write_word(state, 1798, reg);
1350
1351 /* drive host bus 5,6 */
1352 reg = dib8000_read_word(state, 1799) & ~((0x7 << 2) | (0x7 << 8));
1353 reg |= (drive<<8) | (drive<<2);
1354 dib8000_write_word(state, 1799, reg);
1355
1356 /* drive host bus 7, 8, 9 */
1357 reg = dib8000_read_word(state, 1800) &
1358 ~(0x7 | (0x7 << 6) | (0x7 << 12));
1359 reg |= (drive<<12) | (drive<<6) | drive;
1360 dib8000_write_word(state, 1800, reg);
1361
1362 /* drive host bus 10, 11 */
1363 reg = dib8000_read_word(state, 1801) & ~((0x7 << 2) | (0x7 << 8));
1364 reg |= (drive<<8) | (drive<<2);
1365 dib8000_write_word(state, 1801, reg);
1366
1367 /* drive host bus 12, 13, 14 */
1368 reg = dib8000_read_word(state, 1802) &
1369 ~(0x7 | (0x7 << 6) | (0x7 << 12));
1370 reg |= (drive<<12) | (drive<<6) | drive;
1371 dib8000_write_word(state, 1802, reg);
1372}
1373
1374static u32 dib8096p_calcSyncFreq(u32 P_Kin, u32 P_Kout,
1375 u32 insertExtSynchro, u32 syncSize)
1376{
1377 u32 quantif = 3;
1378 u32 nom = (insertExtSynchro * P_Kin+syncSize);
1379 u32 denom = P_Kout;
1380 u32 syncFreq = ((nom << quantif) / denom);
1381
1382 if ((syncFreq & ((1 << quantif) - 1)) != 0)
1383 syncFreq = (syncFreq >> quantif) + 1;
1384 else
1385 syncFreq = (syncFreq >> quantif);
1386
1387 if (syncFreq != 0)
1388 syncFreq = syncFreq - 1;
1389
1390 return syncFreq;
1391}
1392
1393static void dib8096p_cfg_DibTx(struct dib8000_state *state, u32 P_Kin,
1394 u32 P_Kout, u32 insertExtSynchro, u32 synchroMode,
1395 u32 syncWord, u32 syncSize)
1396{
1397 dprintk("Configure DibStream Tx");
1398
1399 dib8000_write_word(state, 1615, 1);
1400 dib8000_write_word(state, 1603, P_Kin);
1401 dib8000_write_word(state, 1605, P_Kout);
1402 dib8000_write_word(state, 1606, insertExtSynchro);
1403 dib8000_write_word(state, 1608, synchroMode);
1404 dib8000_write_word(state, 1609, (syncWord >> 16) & 0xffff);
1405 dib8000_write_word(state, 1610, syncWord & 0xffff);
1406 dib8000_write_word(state, 1612, syncSize);
1407 dib8000_write_word(state, 1615, 0);
1408}
1409
1410static void dib8096p_cfg_DibRx(struct dib8000_state *state, u32 P_Kin,
1411 u32 P_Kout, u32 synchroMode, u32 insertExtSynchro,
1412 u32 syncWord, u32 syncSize, u32 dataOutRate)
1413{
1414 u32 syncFreq;
1415
1416 dprintk("Configure DibStream Rx synchroMode = %d", synchroMode);
1417
1418 if ((P_Kin != 0) && (P_Kout != 0)) {
1419 syncFreq = dib8096p_calcSyncFreq(P_Kin, P_Kout,
1420 insertExtSynchro, syncSize);
1421 dib8000_write_word(state, 1542, syncFreq);
1422 }
1423
1424 dib8000_write_word(state, 1554, 1);
1425 dib8000_write_word(state, 1536, P_Kin);
1426 dib8000_write_word(state, 1537, P_Kout);
1427 dib8000_write_word(state, 1539, synchroMode);
1428 dib8000_write_word(state, 1540, (syncWord >> 16) & 0xffff);
1429 dib8000_write_word(state, 1541, syncWord & 0xffff);
1430 dib8000_write_word(state, 1543, syncSize);
1431 dib8000_write_word(state, 1544, dataOutRate);
1432 dib8000_write_word(state, 1554, 0);
1433}
1434
1435static void dib8096p_enMpegMux(struct dib8000_state *state, int onoff)
1436{
1437 u16 reg_1287;
1438
1439 reg_1287 = dib8000_read_word(state, 1287);
1440
1441 switch (onoff) {
1442 case 1:
1443 reg_1287 &= ~(1 << 8);
1444 break;
1445 case 0:
1446 reg_1287 |= (1 << 8);
1447 break;
1448 }
1449
1450 dib8000_write_word(state, 1287, reg_1287);
1451}
1452
1453static void dib8096p_configMpegMux(struct dib8000_state *state,
1454 u16 pulseWidth, u16 enSerialMode, u16 enSerialClkDiv2)
1455{
1456 u16 reg_1287;
1457
1458 dprintk("Enable Mpeg mux");
1459
1460 dib8096p_enMpegMux(state, 0);
1461
1462 /* If the input mode is MPEG do not divide the serial clock */
1463 if ((enSerialMode == 1) && (state->input_mode_mpeg == 1))
1464 enSerialClkDiv2 = 0;
1465
1466 reg_1287 = ((pulseWidth & 0x1f) << 3) |
1467 ((enSerialMode & 0x1) << 2) | (enSerialClkDiv2 & 0x1);
1468 dib8000_write_word(state, 1287, reg_1287);
1469
1470 dib8096p_enMpegMux(state, 1);
1471}
1472
1473static void dib8096p_setDibTxMux(struct dib8000_state *state, int mode)
1474{
1475 u16 reg_1288 = dib8000_read_word(state, 1288) & ~(0x7 << 7);
1476
1477 switch (mode) {
1478 case MPEG_ON_DIBTX:
1479 dprintk("SET MPEG ON DIBSTREAM TX");
1480 dib8096p_cfg_DibTx(state, 8, 5, 0, 0, 0, 0);
1481 reg_1288 |= (1 << 9); break;
1482 case DIV_ON_DIBTX:
1483 dprintk("SET DIV_OUT ON DIBSTREAM TX");
1484 dib8096p_cfg_DibTx(state, 5, 5, 0, 0, 0, 0);
1485 reg_1288 |= (1 << 8); break;
1486 case ADC_ON_DIBTX:
1487 dprintk("SET ADC_OUT ON DIBSTREAM TX");
1488 dib8096p_cfg_DibTx(state, 20, 5, 10, 0, 0, 0);
1489 reg_1288 |= (1 << 7); break;
1490 default:
1491 break;
1492 }
1493 dib8000_write_word(state, 1288, reg_1288);
1494}
1495
1496static void dib8096p_setHostBusMux(struct dib8000_state *state, int mode)
1497{
1498 u16 reg_1288 = dib8000_read_word(state, 1288) & ~(0x7 << 4);
1499
1500 switch (mode) {
1501 case DEMOUT_ON_HOSTBUS:
1502 dprintk("SET DEM OUT OLD INTERF ON HOST BUS");
1503 dib8096p_enMpegMux(state, 0);
1504 reg_1288 |= (1 << 6);
1505 break;
1506 case DIBTX_ON_HOSTBUS:
1507 dprintk("SET DIBSTREAM TX ON HOST BUS");
1508 dib8096p_enMpegMux(state, 0);
1509 reg_1288 |= (1 << 5);
1510 break;
1511 case MPEG_ON_HOSTBUS:
1512 dprintk("SET MPEG MUX ON HOST BUS");
1513 reg_1288 |= (1 << 4);
1514 break;
1515 default:
1516 break;
1517 }
1518 dib8000_write_word(state, 1288, reg_1288);
1519}
1520
1521static int dib8096p_set_diversity_in(struct dvb_frontend *fe, int onoff)
1522{
1523 struct dib8000_state *state = fe->demodulator_priv;
1524 u16 reg_1287;
1525
1526 switch (onoff) {
1527 case 0: /* only use the internal way - not the diversity input */
1528 dprintk("%s mode OFF : by default Enable Mpeg INPUT",
1529 __func__);
1530 /* outputRate = 8 */
1531 dib8096p_cfg_DibRx(state, 8, 5, 0, 0, 0, 8, 0);
1532
1533 /* Do not divide the serial clock of MPEG MUX in
1534 SERIAL MODE in case input mode MPEG is used */
1535 reg_1287 = dib8000_read_word(state, 1287);
1536 /* enSerialClkDiv2 == 1 ? */
1537 if ((reg_1287 & 0x1) == 1) {
1538 /* force enSerialClkDiv2 = 0 */
1539 reg_1287 &= ~0x1;
1540 dib8000_write_word(state, 1287, reg_1287);
1541 }
1542 state->input_mode_mpeg = 1;
1543 break;
1544 case 1: /* both ways */
1545 case 2: /* only the diversity input */
1546 dprintk("%s ON : Enable diversity INPUT", __func__);
1547 dib8096p_cfg_DibRx(state, 5, 5, 0, 0, 0, 0, 0);
1548 state->input_mode_mpeg = 0;
1549 break;
1550 }
1551
1552 dib8000_set_diversity_in(state->fe[0], onoff);
1553 return 0;
1554}
1555
1556static int dib8096p_set_output_mode(struct dvb_frontend *fe, int mode)
1557{
1558 struct dib8000_state *state = fe->demodulator_priv;
1559 u16 outreg, smo_mode, fifo_threshold;
1560 u8 prefer_mpeg_mux_use = 1;
1561 int ret = 0;
1562
Patrick Boettcher173a64c2013-04-22 12:45:52 -03001563 state->output_mode = mode;
Olivier Grenie0c32dbd2011-08-10 05:17:18 -03001564 dib8096p_host_bus_drive(state, 1);
1565
1566 fifo_threshold = 1792;
1567 smo_mode = (dib8000_read_word(state, 299) & 0x0050) | (1 << 1);
1568 outreg = dib8000_read_word(state, 1286) &
1569 ~((1 << 10) | (0x7 << 6) | (1 << 1));
1570
1571 switch (mode) {
1572 case OUTMODE_HIGH_Z:
1573 outreg = 0;
1574 break;
1575
1576 case OUTMODE_MPEG2_SERIAL:
1577 if (prefer_mpeg_mux_use) {
1578 dprintk("dib8096P setting output mode TS_SERIAL using Mpeg Mux");
1579 dib8096p_configMpegMux(state, 3, 1, 1);
1580 dib8096p_setHostBusMux(state, MPEG_ON_HOSTBUS);
1581 } else {/* Use Smooth block */
1582 dprintk("dib8096P setting output mode TS_SERIAL using Smooth bloc");
1583 dib8096p_setHostBusMux(state,
1584 DEMOUT_ON_HOSTBUS);
1585 outreg |= (2 << 6) | (0 << 1);
1586 }
1587 break;
1588
1589 case OUTMODE_MPEG2_PAR_GATED_CLK:
1590 if (prefer_mpeg_mux_use) {
1591 dprintk("dib8096P setting output mode TS_PARALLEL_GATED using Mpeg Mux");
1592 dib8096p_configMpegMux(state, 2, 0, 0);
1593 dib8096p_setHostBusMux(state, MPEG_ON_HOSTBUS);
1594 } else { /* Use Smooth block */
1595 dprintk("dib8096P setting output mode TS_PARALLEL_GATED using Smooth block");
1596 dib8096p_setHostBusMux(state,
1597 DEMOUT_ON_HOSTBUS);
1598 outreg |= (0 << 6);
1599 }
1600 break;
1601
1602 case OUTMODE_MPEG2_PAR_CONT_CLK: /* Using Smooth block only */
1603 dprintk("dib8096P setting output mode TS_PARALLEL_CONT using Smooth block");
1604 dib8096p_setHostBusMux(state, DEMOUT_ON_HOSTBUS);
1605 outreg |= (1 << 6);
1606 break;
1607
1608 case OUTMODE_MPEG2_FIFO:
1609 /* Using Smooth block because not supported
1610 by new Mpeg Mux bloc */
1611 dprintk("dib8096P setting output mode TS_FIFO using Smooth block");
1612 dib8096p_setHostBusMux(state, DEMOUT_ON_HOSTBUS);
1613 outreg |= (5 << 6);
1614 smo_mode |= (3 << 1);
1615 fifo_threshold = 512;
1616 break;
1617
1618 case OUTMODE_DIVERSITY:
1619 dprintk("dib8096P setting output mode MODE_DIVERSITY");
1620 dib8096p_setDibTxMux(state, DIV_ON_DIBTX);
1621 dib8096p_setHostBusMux(state, DIBTX_ON_HOSTBUS);
1622 break;
1623
1624 case OUTMODE_ANALOG_ADC:
1625 dprintk("dib8096P setting output mode MODE_ANALOG_ADC");
1626 dib8096p_setDibTxMux(state, ADC_ON_DIBTX);
1627 dib8096p_setHostBusMux(state, DIBTX_ON_HOSTBUS);
1628 break;
1629 }
1630
1631 if (mode != OUTMODE_HIGH_Z)
1632 outreg |= (1<<10);
1633
1634 dprintk("output_mpeg2_in_188_bytes = %d",
1635 state->cfg.output_mpeg2_in_188_bytes);
1636 if (state->cfg.output_mpeg2_in_188_bytes)
1637 smo_mode |= (1 << 5);
1638
1639 ret |= dib8000_write_word(state, 299, smo_mode);
1640 /* synchronous fread */
1641 ret |= dib8000_write_word(state, 299 + 1, fifo_threshold);
1642 ret |= dib8000_write_word(state, 1286, outreg);
1643
1644 return ret;
1645}
1646
1647static int map_addr_to_serpar_number(struct i2c_msg *msg)
1648{
1649 if (msg->buf[0] <= 15)
1650 msg->buf[0] -= 1;
1651 else if (msg->buf[0] == 17)
1652 msg->buf[0] = 15;
1653 else if (msg->buf[0] == 16)
1654 msg->buf[0] = 17;
1655 else if (msg->buf[0] == 19)
1656 msg->buf[0] = 16;
1657 else if (msg->buf[0] >= 21 && msg->buf[0] <= 25)
1658 msg->buf[0] -= 3;
1659 else if (msg->buf[0] == 28)
1660 msg->buf[0] = 23;
1661 else if (msg->buf[0] == 99)
1662 msg->buf[0] = 99;
1663 else
1664 return -EINVAL;
1665 return 0;
1666}
1667
1668static int dib8096p_tuner_write_serpar(struct i2c_adapter *i2c_adap,
1669 struct i2c_msg msg[], int num)
1670{
1671 struct dib8000_state *state = i2c_get_adapdata(i2c_adap);
1672 u8 n_overflow = 1;
1673 u16 i = 1000;
1674 u16 serpar_num = msg[0].buf[0];
1675
1676 while (n_overflow == 1 && i) {
1677 n_overflow = (dib8000_read_word(state, 1984) >> 1) & 0x1;
1678 i--;
1679 if (i == 0)
1680 dprintk("Tuner ITF: write busy (overflow)");
1681 }
1682 dib8000_write_word(state, 1985, (1 << 6) | (serpar_num & 0x3f));
1683 dib8000_write_word(state, 1986, (msg[0].buf[1] << 8) | msg[0].buf[2]);
1684
1685 return num;
1686}
1687
1688static int dib8096p_tuner_read_serpar(struct i2c_adapter *i2c_adap,
1689 struct i2c_msg msg[], int num)
1690{
1691 struct dib8000_state *state = i2c_get_adapdata(i2c_adap);
1692 u8 n_overflow = 1, n_empty = 1;
1693 u16 i = 1000;
1694 u16 serpar_num = msg[0].buf[0];
1695 u16 read_word;
1696
1697 while (n_overflow == 1 && i) {
1698 n_overflow = (dib8000_read_word(state, 1984) >> 1) & 0x1;
1699 i--;
1700 if (i == 0)
1701 dprintk("TunerITF: read busy (overflow)");
1702 }
1703 dib8000_write_word(state, 1985, (0<<6) | (serpar_num&0x3f));
1704
1705 i = 1000;
1706 while (n_empty == 1 && i) {
1707 n_empty = dib8000_read_word(state, 1984)&0x1;
1708 i--;
1709 if (i == 0)
1710 dprintk("TunerITF: read busy (empty)");
1711 }
1712
1713 read_word = dib8000_read_word(state, 1987);
1714 msg[1].buf[0] = (read_word >> 8) & 0xff;
1715 msg[1].buf[1] = (read_word) & 0xff;
1716
1717 return num;
1718}
1719
1720static int dib8096p_tuner_rw_serpar(struct i2c_adapter *i2c_adap,
1721 struct i2c_msg msg[], int num)
1722{
1723 if (map_addr_to_serpar_number(&msg[0]) == 0) {
1724 if (num == 1) /* write */
1725 return dib8096p_tuner_write_serpar(i2c_adap, msg, 1);
1726 else /* read */
1727 return dib8096p_tuner_read_serpar(i2c_adap, msg, 2);
1728 }
1729 return num;
1730}
1731
1732static int dib8096p_rw_on_apb(struct i2c_adapter *i2c_adap,
1733 struct i2c_msg msg[], int num, u16 apb_address)
1734{
1735 struct dib8000_state *state = i2c_get_adapdata(i2c_adap);
1736 u16 word;
1737
1738 if (num == 1) { /* write */
1739 dib8000_write_word(state, apb_address,
1740 ((msg[0].buf[1] << 8) | (msg[0].buf[2])));
1741 } else {
1742 word = dib8000_read_word(state, apb_address);
1743 msg[1].buf[0] = (word >> 8) & 0xff;
1744 msg[1].buf[1] = (word) & 0xff;
1745 }
1746 return num;
1747}
1748
1749static int dib8096p_tuner_xfer(struct i2c_adapter *i2c_adap,
1750 struct i2c_msg msg[], int num)
1751{
1752 struct dib8000_state *state = i2c_get_adapdata(i2c_adap);
1753 u16 apb_address = 0, word;
1754 int i = 0;
1755
1756 switch (msg[0].buf[0]) {
1757 case 0x12:
1758 apb_address = 1920;
1759 break;
1760 case 0x14:
1761 apb_address = 1921;
1762 break;
1763 case 0x24:
1764 apb_address = 1922;
1765 break;
1766 case 0x1a:
1767 apb_address = 1923;
1768 break;
1769 case 0x22:
1770 apb_address = 1924;
1771 break;
1772 case 0x33:
1773 apb_address = 1926;
1774 break;
1775 case 0x34:
1776 apb_address = 1927;
1777 break;
1778 case 0x35:
1779 apb_address = 1928;
1780 break;
1781 case 0x36:
1782 apb_address = 1929;
1783 break;
1784 case 0x37:
1785 apb_address = 1930;
1786 break;
1787 case 0x38:
1788 apb_address = 1931;
1789 break;
1790 case 0x39:
1791 apb_address = 1932;
1792 break;
1793 case 0x2a:
1794 apb_address = 1935;
1795 break;
1796 case 0x2b:
1797 apb_address = 1936;
1798 break;
1799 case 0x2c:
1800 apb_address = 1937;
1801 break;
1802 case 0x2d:
1803 apb_address = 1938;
1804 break;
1805 case 0x2e:
1806 apb_address = 1939;
1807 break;
1808 case 0x2f:
1809 apb_address = 1940;
1810 break;
1811 case 0x30:
1812 apb_address = 1941;
1813 break;
1814 case 0x31:
1815 apb_address = 1942;
1816 break;
1817 case 0x32:
1818 apb_address = 1943;
1819 break;
1820 case 0x3e:
1821 apb_address = 1944;
1822 break;
1823 case 0x3f:
1824 apb_address = 1945;
1825 break;
1826 case 0x40:
1827 apb_address = 1948;
1828 break;
1829 case 0x25:
1830 apb_address = 936;
1831 break;
1832 case 0x26:
1833 apb_address = 937;
1834 break;
1835 case 0x27:
1836 apb_address = 938;
1837 break;
1838 case 0x28:
1839 apb_address = 939;
1840 break;
1841 case 0x1d:
1842 /* get sad sel request */
1843 i = ((dib8000_read_word(state, 921) >> 12)&0x3);
1844 word = dib8000_read_word(state, 924+i);
1845 msg[1].buf[0] = (word >> 8) & 0xff;
1846 msg[1].buf[1] = (word) & 0xff;
1847 return num;
1848 case 0x1f:
1849 if (num == 1) { /* write */
1850 word = (u16) ((msg[0].buf[1] << 8) |
1851 msg[0].buf[2]);
1852 /* in the VGAMODE Sel are located on bit 0/1 */
1853 word &= 0x3;
1854 word = (dib8000_read_word(state, 921) &
1855 ~(3<<12)) | (word<<12);
1856 /* Set the proper input */
1857 dib8000_write_word(state, 921, word);
1858 return num;
1859 }
1860 }
1861
1862 if (apb_address != 0) /* R/W acces via APB */
1863 return dib8096p_rw_on_apb(i2c_adap, msg, num, apb_address);
1864 else /* R/W access via SERPAR */
1865 return dib8096p_tuner_rw_serpar(i2c_adap, msg, num);
1866
1867 return 0;
1868}
1869
1870static u32 dib8096p_i2c_func(struct i2c_adapter *adapter)
1871{
1872 return I2C_FUNC_I2C;
1873}
1874
1875static struct i2c_algorithm dib8096p_tuner_xfer_algo = {
1876 .master_xfer = dib8096p_tuner_xfer,
1877 .functionality = dib8096p_i2c_func,
1878};
1879
Mauro Carvalho Chehabd44913c2014-05-29 09:20:17 -03001880static struct i2c_adapter *dib8096p_get_i2c_tuner(struct dvb_frontend *fe)
Olivier Grenie0c32dbd2011-08-10 05:17:18 -03001881{
1882 struct dib8000_state *st = fe->demodulator_priv;
1883 return &st->dib8096p_tuner_adap;
1884}
Olivier Grenie0c32dbd2011-08-10 05:17:18 -03001885
Mauro Carvalho Chehabd44913c2014-05-29 09:20:17 -03001886static int dib8096p_tuner_sleep(struct dvb_frontend *fe, int onoff)
Olivier Grenie0c32dbd2011-08-10 05:17:18 -03001887{
1888 struct dib8000_state *state = fe->demodulator_priv;
1889 u16 en_cur_state;
1890
1891 dprintk("sleep dib8096p: %d", onoff);
1892
1893 en_cur_state = dib8000_read_word(state, 1922);
1894
1895 /* LNAs and MIX are ON and therefore it is a valid configuration */
1896 if (en_cur_state > 0xff)
1897 state->tuner_enable = en_cur_state ;
1898
1899 if (onoff)
1900 en_cur_state &= 0x00ff;
1901 else {
1902 if (state->tuner_enable != 0)
1903 en_cur_state = state->tuner_enable;
1904 }
1905
1906 dib8000_write_word(state, 1922, en_cur_state);
1907
1908 return 0;
1909}
Olivier Grenie0c32dbd2011-08-10 05:17:18 -03001910
Olivier Grenie4c70e072011-01-03 15:33:37 -03001911static const s32 lut_1000ln_mant[] =
Olivier Grenie03245a52009-12-04 13:27:57 -03001912{
Olivier Grenie9c783032009-12-07 07:49:40 -03001913 908, 7003, 7090, 7170, 7244, 7313, 7377, 7438, 7495, 7549, 7600
Olivier Grenie03245a52009-12-04 13:27:57 -03001914};
1915
Mauro Carvalho Chehabd44913c2014-05-29 09:20:17 -03001916static s32 dib8000_get_adc_power(struct dvb_frontend *fe, u8 mode)
Olivier Grenie03245a52009-12-04 13:27:57 -03001917{
Olivier Grenie4c70e072011-01-03 15:33:37 -03001918 struct dib8000_state *state = fe->demodulator_priv;
1919 u32 ix = 0, tmp_val = 0, exp = 0, mant = 0;
1920 s32 val;
Olivier Grenie03245a52009-12-04 13:27:57 -03001921
Olivier Grenie4c70e072011-01-03 15:33:37 -03001922 val = dib8000_read32(state, 384);
Olivier Grenie4c70e072011-01-03 15:33:37 -03001923 if (mode) {
1924 tmp_val = val;
1925 while (tmp_val >>= 1)
1926 exp++;
1927 mant = (val * 1000 / (1<<exp));
1928 ix = (u8)((mant-1000)/100); /* index of the LUT */
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001929 val = (lut_1000ln_mant[ix] + 693*(exp-20) - 6908);
Olivier Grenie4c70e072011-01-03 15:33:37 -03001930 val = (val*256)/1000;
1931 }
1932 return val;
Olivier Grenie03245a52009-12-04 13:27:57 -03001933}
Olivier Grenie03245a52009-12-04 13:27:57 -03001934
Mauro Carvalho Chehabd44913c2014-05-29 09:20:17 -03001935static int dib8090p_get_dc_power(struct dvb_frontend *fe, u8 IQ)
Olivier Grenie0c32dbd2011-08-10 05:17:18 -03001936{
1937 struct dib8000_state *state = fe->demodulator_priv;
1938 int val = 0;
1939
1940 switch (IQ) {
1941 case 1:
1942 val = dib8000_read_word(state, 403);
1943 break;
1944 case 0:
1945 val = dib8000_read_word(state, 404);
1946 break;
1947 }
1948 if (val & 0x200)
1949 val -= 1024;
1950
1951 return val;
1952}
Olivier Grenie0c32dbd2011-08-10 05:17:18 -03001953
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001954static void dib8000_update_timf(struct dib8000_state *state)
1955{
1956 u32 timf = state->timf = dib8000_read32(state, 435);
1957
1958 dib8000_write_word(state, 29, (u16) (timf >> 16));
1959 dib8000_write_word(state, 30, (u16) (timf & 0xffff));
1960 dprintk("Updated timing frequency: %d (default: %d)", state->timf, state->timf_default);
1961}
1962
Mauro Carvalho Chehabd44913c2014-05-29 09:20:17 -03001963static u32 dib8000_ctrl_timf(struct dvb_frontend *fe, uint8_t op, uint32_t timf)
Olivier Grenie0c32dbd2011-08-10 05:17:18 -03001964{
1965 struct dib8000_state *state = fe->demodulator_priv;
1966
1967 switch (op) {
1968 case DEMOD_TIMF_SET:
1969 state->timf = timf;
1970 break;
1971 case DEMOD_TIMF_UPDATE:
1972 dib8000_update_timf(state);
1973 break;
1974 case DEMOD_TIMF_GET:
1975 break;
1976 }
1977 dib8000_set_bandwidth(state->fe[0], 6000);
1978
1979 return state->timf;
1980}
Olivier Grenie0c32dbd2011-08-10 05:17:18 -03001981
Olivier Grenie5a0deee2011-05-03 12:27:33 -03001982static const u16 adc_target_16dB[11] = {
Mauro Carvalho Chehaba768f902014-07-04 14:15:38 -03001983 7250, 7238, 7264, 7309, 7338, 7382, 7427, 7456, 7500, 7544, 7574
Olivier Grenie5a0deee2011-05-03 12:27:33 -03001984};
Mauro Carvalho Chehaba768f902014-07-04 14:15:38 -03001985
Olivier Grenie5a0deee2011-05-03 12:27:33 -03001986static const u8 permu_seg[] = { 6, 5, 7, 4, 8, 3, 9, 2, 10, 1, 11, 0, 12 };
1987
Patrick Boettcher173a64c2013-04-22 12:45:52 -03001988static u16 dib8000_set_layer(struct dib8000_state *state, u8 layer_index, u16 max_constellation)
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001989{
Patrick Boettcher173a64c2013-04-22 12:45:52 -03001990 u8 cr, constellation, time_intlv;
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03001991 struct dtv_frontend_properties *c = &state->fe[0]->dtv_property_cache;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001992
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03001993 switch (c->layer[layer_index].modulation) {
Patrick Boettcher173a64c2013-04-22 12:45:52 -03001994 case DQPSK:
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001995 constellation = 0;
1996 break;
Patrick Boettcher173a64c2013-04-22 12:45:52 -03001997 case QPSK:
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001998 constellation = 1;
1999 break;
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002000 case QAM_16:
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002001 constellation = 2;
2002 break;
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002003 case QAM_64:
2004 default:
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002005 constellation = 3;
2006 break;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002007 }
2008
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03002009 switch (c->layer[layer_index].fec) {
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002010 case FEC_1_2:
2011 cr = 1;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002012 break;
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002013 case FEC_2_3:
2014 cr = 2;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002015 break;
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002016 case FEC_3_4:
2017 cr = 3;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002018 break;
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002019 case FEC_5_6:
2020 cr = 5;
2021 break;
2022 case FEC_7_8:
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002023 default:
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002024 cr = 7;
2025 break;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002026 }
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002027
Mauro Carvalho Chehab34ba2e62014-07-04 14:15:27 -03002028 time_intlv = fls(c->layer[layer_index].interleaving);
2029 if (time_intlv > 3 && !(time_intlv == 4 && c->isdbt_sb_mode == 1))
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002030 time_intlv = 0;
2031
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03002032 dib8000_write_word(state, 2 + layer_index, (constellation << 10) | ((c->layer[layer_index].segment_count & 0xf) << 6) | (cr << 3) | time_intlv);
2033 if (c->layer[layer_index].segment_count > 0) {
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002034 switch (max_constellation) {
2035 case DQPSK:
2036 case QPSK:
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03002037 if (c->layer[layer_index].modulation == QAM_16 || c->layer[layer_index].modulation == QAM_64)
2038 max_constellation = c->layer[layer_index].modulation;
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002039 break;
2040 case QAM_16:
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03002041 if (c->layer[layer_index].modulation == QAM_64)
2042 max_constellation = c->layer[layer_index].modulation;
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002043 break;
2044 }
2045 }
2046
2047 return max_constellation;
2048}
2049
2050static 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 */
2051static 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 */
2052static 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 */
2053static u16 dib8000_adp_fine_tune(struct dib8000_state *state, u16 max_constellation)
2054{
2055 u16 i, ana_gain = 0;
2056 const u16 *adp;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002057
2058 /* channel estimation fine configuration */
2059 switch (max_constellation) {
2060 case QAM_64:
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002061 ana_gain = 0x7;
2062 adp = &adp_Q64[0];
2063 break;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002064 case QAM_16:
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002065 ana_gain = 0x7;
2066 adp = &adp_Q16[0];
2067 break;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002068 default:
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002069 ana_gain = 0;
2070 adp = &adp_Qdefault[0];
2071 break;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002072 }
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002073
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002074 for (i = 0; i < 4; i++)
2075 dib8000_write_word(state, 215 + i, adp[i]);
2076
2077 return ana_gain;
2078}
2079
2080static void dib8000_update_ana_gain(struct dib8000_state *state, u16 ana_gain)
2081{
2082 u16 i;
2083
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002084 dib8000_write_word(state, 116, ana_gain);
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002085
2086 /* update ADC target depending on ana_gain */
2087 if (ana_gain) { /* set -16dB ADC target for ana_gain=-1 */
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002088 for (i = 0; i < 10; i++)
2089 dib8000_write_word(state, 80 + i, adc_target_16dB[i]);
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002090 } else { /* set -22dB ADC target for ana_gain=0 */
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002091 for (i = 0; i < 10; i++)
2092 dib8000_write_word(state, 80 + i, adc_target_16dB[i] - 355);
2093 }
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002094}
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002095
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002096static void dib8000_load_ana_fe_coefs(struct dib8000_state *state, const s16 *ana_fe)
2097{
2098 u16 mode = 0;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002099
2100 if (state->isdbt_cfg_loaded == 0)
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002101 for (mode = 0; mode < 24; mode++)
2102 dib8000_write_word(state, 117 + mode, ana_fe[mode]);
2103}
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002104
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002105static const u16 lut_prbs_2k[14] = {
2106 0, 0x423, 0x009, 0x5C7, 0x7A6, 0x3D8, 0x527, 0x7FF, 0x79B, 0x3D6, 0x3A2, 0x53B, 0x2F4, 0x213
2107};
2108static const u16 lut_prbs_4k[14] = {
2109 0, 0x208, 0x0C3, 0x7B9, 0x423, 0x5C7, 0x3D8, 0x7FF, 0x3D6, 0x53B, 0x213, 0x029, 0x0D0, 0x48E
2110};
2111static const u16 lut_prbs_8k[14] = {
2112 0, 0x740, 0x069, 0x7DD, 0x208, 0x7B9, 0x5C7, 0x7FF, 0x53B, 0x029, 0x48E, 0x4C4, 0x367, 0x684
2113};
2114
2115static u16 dib8000_get_init_prbs(struct dib8000_state *state, u16 subchannel)
2116{
2117 int sub_channel_prbs_group = 0;
2118
2119 sub_channel_prbs_group = (subchannel / 3) + 1;
2120 dprintk("sub_channel_prbs_group = %d , subchannel =%d prbs = 0x%04x", sub_channel_prbs_group, subchannel, lut_prbs_8k[sub_channel_prbs_group]);
2121
2122 switch (state->fe[0]->dtv_property_cache.transmission_mode) {
2123 case TRANSMISSION_MODE_2K:
2124 return lut_prbs_2k[sub_channel_prbs_group];
2125 case TRANSMISSION_MODE_4K:
2126 return lut_prbs_4k[sub_channel_prbs_group];
2127 default:
2128 case TRANSMISSION_MODE_8K:
2129 return lut_prbs_8k[sub_channel_prbs_group];
2130 }
2131}
2132
2133static void dib8000_set_13seg_channel(struct dib8000_state *state)
2134{
2135 u16 i;
2136 u16 coff_pow = 0x2800;
2137
2138 state->seg_mask = 0x1fff; /* All 13 segments enabled */
2139
2140 /* ---- COFF ---- Carloff, the most robust --- */
2141 if (state->isdbt_cfg_loaded == 0) { /* if not Sound Broadcasting mode : put default values for 13 segments */
2142 dib8000_write_word(state, 180, (16 << 6) | 9);
2143 dib8000_write_word(state, 187, (4 << 12) | (8 << 5) | 0x2);
2144 coff_pow = 0x2800;
2145 for (i = 0; i < 6; i++)
2146 dib8000_write_word(state, 181+i, coff_pow);
2147
2148 /* P_ctrl_corm_thres4pre_freq_inh=1, P_ctrl_pre_freq_mode_sat=1 */
2149 /* 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 */
2150 dib8000_write_word(state, 338, (1 << 12) | (1 << 10) | (0 << 9) | (3 << 5) | 1);
2151
2152 /* P_ctrl_pre_freq_win_len=8, P_ctrl_pre_freq_thres_lockin=6 */
2153 dib8000_write_word(state, 340, (8 << 6) | (6 << 0));
2154 /* P_ctrl_pre_freq_thres_lockout=4, P_small_use_tmcc/ac/cp=1 */
2155 dib8000_write_word(state, 341, (4 << 3) | (1 << 2) | (1 << 1) | (1 << 0));
2156
2157 dib8000_write_word(state, 228, 0); /* default value */
2158 dib8000_write_word(state, 265, 31); /* default value */
2159 dib8000_write_word(state, 205, 0x200f); /* init value */
2160 }
2161
2162 /*
2163 * make the cpil_coff_lock more robust but slower p_coff_winlen
2164 * 6bits; p_coff_thres_lock 6bits (for coff lock if needed)
2165 */
2166
2167 if (state->cfg.pll->ifreq == 0)
2168 dib8000_write_word(state, 266, ~state->seg_mask | state->seg_diff_mask | 0x40); /* P_equal_noise_seg_inh */
2169
2170 dib8000_load_ana_fe_coefs(state, ana_fe_coeff_13seg);
2171}
2172
2173static void dib8000_set_subchannel_prbs(struct dib8000_state *state, u16 init_prbs)
2174{
2175 u16 reg_1;
2176
2177 reg_1 = dib8000_read_word(state, 1);
2178 dib8000_write_word(state, 1, (init_prbs << 2) | (reg_1 & 0x3)); /* ADDR 1 */
2179}
2180
2181static void dib8000_small_fine_tune(struct dib8000_state *state)
2182{
2183 u16 i;
2184 const s16 *ncoeff;
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03002185 struct dtv_frontend_properties *c = &state->fe[0]->dtv_property_cache;
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002186
2187 dib8000_write_word(state, 352, state->seg_diff_mask);
2188 dib8000_write_word(state, 353, state->seg_mask);
2189
2190 /* 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 -03002191 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 -03002192
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03002193 if (c->isdbt_sb_mode) {
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002194 /* ---- SMALL ---- */
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03002195 switch (c->transmission_mode) {
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002196 case TRANSMISSION_MODE_2K:
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03002197 if (c->isdbt_partial_reception == 0) { /* 1-seg */
2198 if (c->layer[0].modulation == DQPSK) /* DQPSK */
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002199 ncoeff = coeff_2k_sb_1seg_dqpsk;
2200 else /* QPSK or QAM */
2201 ncoeff = coeff_2k_sb_1seg;
2202 } else { /* 3-segments */
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03002203 if (c->layer[0].modulation == DQPSK) { /* DQPSK on central segment */
2204 if (c->layer[1].modulation == DQPSK) /* DQPSK on external segments */
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002205 ncoeff = coeff_2k_sb_3seg_0dqpsk_1dqpsk;
2206 else /* QPSK or QAM on external segments */
2207 ncoeff = coeff_2k_sb_3seg_0dqpsk;
2208 } else { /* QPSK or QAM on central segment */
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03002209 if (c->layer[1].modulation == DQPSK) /* DQPSK on external segments */
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002210 ncoeff = coeff_2k_sb_3seg_1dqpsk;
2211 else /* QPSK or QAM on external segments */
2212 ncoeff = coeff_2k_sb_3seg;
2213 }
2214 }
2215 break;
2216 case TRANSMISSION_MODE_4K:
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03002217 if (c->isdbt_partial_reception == 0) { /* 1-seg */
2218 if (c->layer[0].modulation == DQPSK) /* DQPSK */
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002219 ncoeff = coeff_4k_sb_1seg_dqpsk;
2220 else /* QPSK or QAM */
2221 ncoeff = coeff_4k_sb_1seg;
2222 } else { /* 3-segments */
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03002223 if (c->layer[0].modulation == DQPSK) { /* DQPSK on central segment */
2224 if (c->layer[1].modulation == DQPSK) /* DQPSK on external segments */
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002225 ncoeff = coeff_4k_sb_3seg_0dqpsk_1dqpsk;
2226 else /* QPSK or QAM on external segments */
2227 ncoeff = coeff_4k_sb_3seg_0dqpsk;
2228 } else { /* QPSK or QAM on central segment */
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03002229 if (c->layer[1].modulation == DQPSK) /* DQPSK on external segments */
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002230 ncoeff = coeff_4k_sb_3seg_1dqpsk;
2231 else /* QPSK or QAM on external segments */
2232 ncoeff = coeff_4k_sb_3seg;
2233 }
2234 }
2235 break;
2236 case TRANSMISSION_MODE_AUTO:
2237 case TRANSMISSION_MODE_8K:
2238 default:
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03002239 if (c->isdbt_partial_reception == 0) { /* 1-seg */
2240 if (c->layer[0].modulation == DQPSK) /* DQPSK */
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002241 ncoeff = coeff_8k_sb_1seg_dqpsk;
2242 else /* QPSK or QAM */
2243 ncoeff = coeff_8k_sb_1seg;
2244 } else { /* 3-segments */
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03002245 if (c->layer[0].modulation == DQPSK) { /* DQPSK on central segment */
2246 if (c->layer[1].modulation == DQPSK) /* DQPSK on external segments */
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002247 ncoeff = coeff_8k_sb_3seg_0dqpsk_1dqpsk;
2248 else /* QPSK or QAM on external segments */
2249 ncoeff = coeff_8k_sb_3seg_0dqpsk;
2250 } else { /* QPSK or QAM on central segment */
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03002251 if (c->layer[1].modulation == DQPSK) /* DQPSK on external segments */
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002252 ncoeff = coeff_8k_sb_3seg_1dqpsk;
2253 else /* QPSK or QAM on external segments */
2254 ncoeff = coeff_8k_sb_3seg;
2255 }
2256 }
2257 break;
2258 }
2259
2260 for (i = 0; i < 8; i++)
2261 dib8000_write_word(state, 343 + i, ncoeff[i]);
2262 }
2263}
2264
2265static const u16 coff_thres_1seg[3] = {300, 150, 80};
2266static const u16 coff_thres_3seg[3] = {350, 300, 250};
2267static void dib8000_set_sb_channel(struct dib8000_state *state)
2268{
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03002269 struct dtv_frontend_properties *c = &state->fe[0]->dtv_property_cache;
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002270 const u16 *coff;
2271 u16 i;
2272
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03002273 if (c->transmission_mode == TRANSMISSION_MODE_2K || c->transmission_mode == TRANSMISSION_MODE_4K) {
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002274 dib8000_write_word(state, 219, dib8000_read_word(state, 219) | 0x1); /* adp_pass =1 */
2275 dib8000_write_word(state, 190, dib8000_read_word(state, 190) | (0x1 << 14)); /* pha3_force_pha_shift = 1 */
2276 } else {
2277 dib8000_write_word(state, 219, dib8000_read_word(state, 219) & 0xfffe); /* adp_pass =0 */
2278 dib8000_write_word(state, 190, dib8000_read_word(state, 190) & 0xbfff); /* pha3_force_pha_shift = 0 */
2279 }
2280
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03002281 if (c->isdbt_partial_reception == 1) /* 3-segments */
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002282 state->seg_mask = 0x00E0;
2283 else /* 1-segment */
2284 state->seg_mask = 0x0040;
2285
2286 dib8000_write_word(state, 268, (dib8000_read_word(state, 268) & 0xF9FF) | 0x0200);
2287
2288 /* ---- COFF ---- Carloff, the most robust --- */
2289 /* 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 -03002290 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 -03002291
2292 dib8000_write_word(state, 340, (16 << 6) | (8 << 0)); /* P_ctrl_pre_freq_win_len=16, P_ctrl_pre_freq_thres_lockin=8 */
2293 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 */
2294
2295 /* Sound Broadcasting mode 1 seg */
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03002296 if (c->isdbt_partial_reception == 0) {
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002297 /* 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) */
2298 if (state->mode == 3)
2299 dib8000_write_word(state, 180, 0x1fcf | ((state->mode - 1) << 14));
2300 else
2301 dib8000_write_word(state, 180, 0x0fcf | ((state->mode - 1) << 14));
2302
2303 /* 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 */
2304 dib8000_write_word(state, 338, (1 << 12) | (1 << 10) | (0 << 9) | (5 << 5) | 4);
2305 coff = &coff_thres_1seg[0];
2306 } else { /* Sound Broadcasting mode 3 seg */
2307 dib8000_write_word(state, 180, 0x1fcf | (1 << 14));
2308 /* 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 */
2309 dib8000_write_word(state, 338, (1 << 12) | (1 << 10) | (0 << 9) | (4 << 5) | 4);
2310 coff = &coff_thres_3seg[0];
2311 }
2312
2313 dib8000_write_word(state, 228, 1); /* P_2d_mode_byp=1 */
2314 dib8000_write_word(state, 205, dib8000_read_word(state, 205) & 0xfff0); /* P_cspu_win_cut = 0 */
2315
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03002316 if (c->isdbt_partial_reception == 0 && c->transmission_mode == TRANSMISSION_MODE_2K)
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002317 dib8000_write_word(state, 265, 15); /* P_equal_noise_sel = 15 */
2318
2319 /* Write COFF thres */
2320 for (i = 0 ; i < 3; i++) {
2321 dib8000_write_word(state, 181+i, coff[i]);
2322 dib8000_write_word(state, 184+i, coff[i]);
2323 }
2324
2325 /*
2326 * make the cpil_coff_lock more robust but slower p_coff_winlen
2327 * 6bits; p_coff_thres_lock 6bits (for coff lock if needed)
2328 */
2329
2330 dib8000_write_word(state, 266, ~state->seg_mask | state->seg_diff_mask); /* P_equal_noise_seg_inh */
2331
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03002332 if (c->isdbt_partial_reception == 0)
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002333 dib8000_write_word(state, 178, 64); /* P_fft_powrange = 64 */
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002334 else
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002335 dib8000_write_word(state, 178, 32); /* P_fft_powrange = 32 */
2336}
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002337
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002338static void dib8000_set_isdbt_common_channel(struct dib8000_state *state, u8 seq, u8 autosearching)
2339{
2340 u16 p_cfr_left_edge = 0, p_cfr_right_edge = 0;
2341 u16 tmcc_pow = 0, ana_gain = 0, tmp = 0, i = 0, nbseg_diff = 0 ;
2342 u16 max_constellation = DQPSK;
2343 int init_prbs;
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03002344 struct dtv_frontend_properties *c = &state->fe[0]->dtv_property_cache;
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002345
Mauro Carvalho Chehabdde8e112014-07-04 14:15:32 -03002346 if (autosearching)
2347 c->isdbt_partial_reception = 1;
2348
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002349 /* P_mode */
2350 dib8000_write_word(state, 10, (seq << 4));
2351
2352 /* init mode */
2353 state->mode = fft_to_mode(state);
2354
2355 /* set guard */
2356 tmp = dib8000_read_word(state, 1);
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03002357 dib8000_write_word(state, 1, (tmp&0xfffc) | (c->guard_interval & 0x3));
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002358
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03002359 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 -03002360
2361 /* signal optimization parameter */
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03002362 if (c->isdbt_partial_reception) {
2363 state->seg_diff_mask = (c->layer[0].modulation == DQPSK) << permu_seg[0];
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002364 for (i = 1; i < 3; i++)
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03002365 nbseg_diff += (c->layer[i].modulation == DQPSK) * c->layer[i].segment_count;
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002366 for (i = 0; i < nbseg_diff; i++)
2367 state->seg_diff_mask |= 1 << permu_seg[i+1];
2368 } else {
2369 for (i = 0; i < 3; i++)
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03002370 nbseg_diff += (c->layer[i].modulation == DQPSK) * c->layer[i].segment_count;
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002371 for (i = 0; i < nbseg_diff; i++)
2372 state->seg_diff_mask |= 1 << permu_seg[i];
2373 }
2374
2375 if (state->seg_diff_mask)
2376 dib8000_write_word(state, 268, (dib8000_read_word(state, 268) & 0xF9FF) | 0x0200);
2377 else
2378 dib8000_write_word(state, 268, (2 << 9) | 39); /*init value */
2379
2380 for (i = 0; i < 3; i++)
2381 max_constellation = dib8000_set_layer(state, i, max_constellation);
2382 if (autosearching == 0) {
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03002383 state->layer_b_nb_seg = c->layer[1].segment_count;
2384 state->layer_c_nb_seg = c->layer[2].segment_count;
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002385 }
2386
2387 /* WRITE: Mode & Diff mask */
2388 dib8000_write_word(state, 0, (state->mode << 13) | state->seg_diff_mask);
2389
2390 state->differential_constellation = (state->seg_diff_mask != 0);
2391
2392 /* channel estimation fine configuration */
2393 ana_gain = dib8000_adp_fine_tune(state, max_constellation);
2394
2395 /* update ana_gain depending on max constellation */
2396 dib8000_update_ana_gain(state, ana_gain);
2397
2398 /* ---- ANA_FE ---- */
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03002399 if (c->isdbt_partial_reception) /* 3-segments */
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002400 dib8000_load_ana_fe_coefs(state, ana_fe_coeff_3seg);
2401 else
2402 dib8000_load_ana_fe_coefs(state, ana_fe_coeff_1seg); /* 1-segment */
2403
2404 /* TSB or ISDBT ? apply it now */
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03002405 if (c->isdbt_sb_mode) {
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002406 dib8000_set_sb_channel(state);
Mauro Carvalho Chehab746f7ae2013-04-25 11:15:54 -03002407 if (c->isdbt_sb_subchannel < 14)
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03002408 init_prbs = dib8000_get_init_prbs(state, c->isdbt_sb_subchannel);
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002409 else
2410 init_prbs = 0;
2411 } else {
2412 dib8000_set_13seg_channel(state);
2413 init_prbs = 0xfff;
2414 }
2415
2416 /* SMALL */
2417 dib8000_small_fine_tune(state);
2418
2419 dib8000_set_subchannel_prbs(state, init_prbs);
2420
2421 /* ---- CHAN_BLK ---- */
2422 for (i = 0; i < 13; i++) {
2423 if ((((~state->seg_diff_mask) >> i) & 1) == 1) {
2424 p_cfr_left_edge += (1 << i) * ((i == 0) || ((((state->seg_mask & (~state->seg_diff_mask)) >> (i - 1)) & 1) == 0));
2425 p_cfr_right_edge += (1 << i) * ((i == 12) || ((((state->seg_mask & (~state->seg_diff_mask)) >> (i + 1)) & 1) == 0));
2426 }
2427 }
2428 dib8000_write_word(state, 222, p_cfr_left_edge); /* p_cfr_left_edge */
2429 dib8000_write_word(state, 223, p_cfr_right_edge); /* p_cfr_right_edge */
2430 /* "P_cspu_left_edge" & "P_cspu_right_edge" not used => do not care */
2431
2432 dib8000_write_word(state, 189, ~state->seg_mask | state->seg_diff_mask); /* P_lmod4_seg_inh */
2433 dib8000_write_word(state, 192, ~state->seg_mask | state->seg_diff_mask); /* P_pha3_seg_inh */
2434 dib8000_write_word(state, 225, ~state->seg_mask | state->seg_diff_mask); /* P_tac_seg_inh */
2435
2436 if (!autosearching)
2437 dib8000_write_word(state, 288, (~state->seg_mask | state->seg_diff_mask) & 0x1fff); /* P_tmcc_seg_eq_inh */
2438 else
2439 dib8000_write_word(state, 288, 0x1fff); /*disable equalisation of the tmcc when autosearch to be able to find the DQPSK channels. */
2440
2441 dib8000_write_word(state, 211, state->seg_mask & (~state->seg_diff_mask)); /* P_des_seg_enabled */
2442 dib8000_write_word(state, 287, ~state->seg_mask | 0x1000); /* P_tmcc_seg_inh */
2443
2444 dib8000_write_word(state, 178, 32); /* P_fft_powrange = 32 */
2445
2446 /* ---- TMCC ---- */
2447 for (i = 0; i < 3; i++)
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03002448 tmcc_pow += (((c->layer[i].modulation == DQPSK) * 4 + 1) * c->layer[i].segment_count) ;
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002449
2450 /* Quantif of "P_tmcc_dec_thres_?k" is (0, 5+mode, 9); */
2451 /* Threshold is set at 1/4 of max power. */
2452 tmcc_pow *= (1 << (9-2));
2453 dib8000_write_word(state, 290, tmcc_pow); /* P_tmcc_dec_thres_2k */
2454 dib8000_write_word(state, 291, tmcc_pow); /* P_tmcc_dec_thres_4k */
2455 dib8000_write_word(state, 292, tmcc_pow); /* P_tmcc_dec_thres_8k */
2456 /*dib8000_write_word(state, 287, (1 << 13) | 0x1000 ); */
2457
2458 /* ---- PHA3 ---- */
2459 if (state->isdbt_cfg_loaded == 0)
2460 dib8000_write_word(state, 250, 3285); /* p_2d_hspeed_thr0 */
2461
2462 state->isdbt_cfg_loaded = 0;
2463}
2464
Mauro Carvalho Chehab6f7ee062013-04-25 10:36:56 -03002465static u32 dib8000_wait_lock(struct dib8000_state *state, u32 internal,
2466 u32 wait0_ms, u32 wait1_ms, u32 wait2_ms)
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002467{
Mauro Carvalho Chehab13122f92013-04-25 15:22:20 -03002468 u32 value = 0; /* P_search_end0 wait time */
2469 u16 reg = 11; /* P_search_end0 start addr */
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002470
2471 for (reg = 11; reg < 16; reg += 2) {
2472 if (reg == 11) {
2473 if (state->revision == 0x8090)
Mauro Carvalho Chehab13122f92013-04-25 15:22:20 -03002474 value = internal * wait1_ms;
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002475 else
Mauro Carvalho Chehab13122f92013-04-25 15:22:20 -03002476 value = internal * wait0_ms;
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002477 } else if (reg == 13)
Mauro Carvalho Chehab13122f92013-04-25 15:22:20 -03002478 value = internal * wait1_ms;
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002479 else if (reg == 15)
Mauro Carvalho Chehab13122f92013-04-25 15:22:20 -03002480 value = internal * wait2_ms;
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002481 dib8000_write_word(state, reg, (u16)((value >> 16) & 0xffff));
2482 dib8000_write_word(state, (reg + 1), (u16)(value & 0xffff));
2483 }
2484 return value;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002485}
2486
2487static int dib8000_autosearch_start(struct dvb_frontend *fe)
2488{
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002489 struct dib8000_state *state = fe->demodulator_priv;
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03002490 struct dtv_frontend_properties *c = &state->fe[0]->dtv_property_cache;
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002491 u8 slist = 0;
2492 u32 value, internal = state->cfg.pll->internal;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002493
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002494 if (state->revision == 0x8090)
2495 internal = dib8000_read32(state, 23) / 1000;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002496
Olivier Grenied67350f2013-12-12 09:26:22 -03002497 if ((state->revision >= 0x8002) &&
2498 (state->autosearch_state == AS_SEARCHING_FFT)) {
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002499 dib8000_write_word(state, 37, 0x0065); /* P_ctrl_pha_off_max default values */
2500 dib8000_write_word(state, 116, 0x0000); /* P_ana_gain to 0 */
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002501
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002502 dib8000_write_word(state, 0, (dib8000_read_word(state, 0) & 0x1fff) | (0 << 13) | (1 << 15)); /* P_mode = 0, P_restart_search=1 */
2503 dib8000_write_word(state, 1, (dib8000_read_word(state, 1) & 0xfffc) | 0); /* P_guard = 0 */
2504 dib8000_write_word(state, 6, 0); /* P_lock0_mask = 0 */
2505 dib8000_write_word(state, 7, 0); /* P_lock1_mask = 0 */
2506 dib8000_write_word(state, 8, 0); /* P_lock2_mask = 0 */
2507 dib8000_write_word(state, 10, (dib8000_read_word(state, 10) & 0x200) | (16 << 4) | (0 << 0)); /* P_search_list=16, P_search_maxtrial=0 */
2508
2509 if (state->revision == 0x8090)
2510 value = dib8000_wait_lock(state, internal, 10, 10, 10); /* time in ms configure P_search_end0 P_search_end1 P_search_end2 */
2511 else
2512 value = dib8000_wait_lock(state, internal, 20, 20, 20); /* time in ms configure P_search_end0 P_search_end1 P_search_end2 */
2513
2514 dib8000_write_word(state, 17, 0);
2515 dib8000_write_word(state, 18, 200); /* P_search_rstst = 200 */
2516 dib8000_write_word(state, 19, 0);
2517 dib8000_write_word(state, 20, 400); /* P_search_rstend = 400 */
2518 dib8000_write_word(state, 21, (value >> 16) & 0xffff); /* P_search_checkst */
2519 dib8000_write_word(state, 22, value & 0xffff);
2520
2521 if (state->revision == 0x8090)
2522 dib8000_write_word(state, 32, (dib8000_read_word(state, 32) & 0xf0ff) | (0 << 8)); /* P_corm_alpha = 0 */
2523 else
2524 dib8000_write_word(state, 32, (dib8000_read_word(state, 32) & 0xf0ff) | (9 << 8)); /* P_corm_alpha = 3 */
2525 dib8000_write_word(state, 355, 2); /* P_search_param_max = 2 */
2526
2527 /* P_search_param_select = (1 | 1<<4 | 1 << 8) */
2528 dib8000_write_word(state, 356, 0);
2529 dib8000_write_word(state, 357, 0x111);
2530
2531 dib8000_write_word(state, 770, (dib8000_read_word(state, 770) & 0xdfff) | (1 << 13)); /* P_restart_ccg = 1 */
2532 dib8000_write_word(state, 770, (dib8000_read_word(state, 770) & 0xdfff) | (0 << 13)); /* P_restart_ccg = 0 */
2533 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 -03002534 } else if ((state->revision >= 0x8002) &&
2535 (state->autosearch_state == AS_SEARCHING_GUARD)) {
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03002536 c->transmission_mode = TRANSMISSION_MODE_8K;
2537 c->guard_interval = GUARD_INTERVAL_1_8;
2538 c->inversion = 0;
2539 c->layer[0].modulation = QAM_64;
2540 c->layer[0].fec = FEC_2_3;
2541 c->layer[0].interleaving = 0;
2542 c->layer[0].segment_count = 13;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002543
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002544 slist = 16;
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03002545 c->transmission_mode = state->found_nfft;
Patrick Boettcher78f3bc62009-08-17 12:53:51 -03002546
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002547 dib8000_set_isdbt_common_channel(state, slist, 1);
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002548
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002549 /* set lock_mask values */
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002550 dib8000_write_word(state, 6, 0x4);
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002551 if (state->revision == 0x8090)
2552 dib8000_write_word(state, 7, ((1 << 12) | (1 << 11) | (1 << 10)));/* tmcc_dec_lock, tmcc_sync_lock, tmcc_data_lock, tmcc_bch_uncor */
2553 else
2554 dib8000_write_word(state, 7, 0x8);
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002555 dib8000_write_word(state, 8, 0x1000);
2556
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002557 /* set lock_mask wait time values */
2558 if (state->revision == 0x8090)
2559 dib8000_wait_lock(state, internal, 50, 100, 1000); /* time in ms configure P_search_end0 P_search_end1 P_search_end2 */
2560 else
2561 dib8000_wait_lock(state, internal, 50, 200, 1000); /* time in ms configure P_search_end0 P_search_end1 P_search_end2 */
2562
2563 dib8000_write_word(state, 355, 3); /* P_search_param_max = 3 */
2564
2565 /* P_search_param_select = 0xf; look for the 4 different guard intervals */
2566 dib8000_write_word(state, 356, 0);
2567 dib8000_write_word(state, 357, 0xf);
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002568
2569 value = dib8000_read_word(state, 0);
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002570 dib8000_write_word(state, 0, (u16)((1 << 15) | value));
2571 dib8000_read_word(state, 1284); /* reset the INT. n_irq_pending */
2572 dib8000_write_word(state, 0, (u16)value);
2573 } else {
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03002574 c->inversion = 0;
2575 c->layer[0].modulation = QAM_64;
2576 c->layer[0].fec = FEC_2_3;
2577 c->layer[0].interleaving = 0;
2578 c->layer[0].segment_count = 13;
2579 if (!c->isdbt_sb_mode)
2580 c->layer[0].segment_count = 13;
Patrick Boettcher78f3bc62009-08-17 12:53:51 -03002581
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002582 /* choose the right list, in sb, always do everything */
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03002583 if (c->isdbt_sb_mode) {
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002584 slist = 7;
2585 dib8000_write_word(state, 0, (dib8000_read_word(state, 0) & 0x9fff) | (1 << 13));
2586 } else {
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03002587 if (c->guard_interval == GUARD_INTERVAL_AUTO) {
2588 if (c->transmission_mode == TRANSMISSION_MODE_AUTO) {
2589 c->transmission_mode = TRANSMISSION_MODE_8K;
2590 c->guard_interval = GUARD_INTERVAL_1_8;
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002591 slist = 7;
2592 dib8000_write_word(state, 0, (dib8000_read_word(state, 0) & 0x9fff) | (1 << 13)); /* P_mode = 1 to have autosearch start ok with mode2 */
2593 } else {
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03002594 c->guard_interval = GUARD_INTERVAL_1_8;
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002595 slist = 3;
2596 }
2597 } else {
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03002598 if (c->transmission_mode == TRANSMISSION_MODE_AUTO) {
2599 c->transmission_mode = TRANSMISSION_MODE_8K;
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002600 slist = 2;
2601 dib8000_write_word(state, 0, (dib8000_read_word(state, 0) & 0x9fff) | (1 << 13)); /* P_mode = 1 */
2602 } else
2603 slist = 0;
2604 }
2605 }
2606 dprintk("Using list for autosearch : %d", slist);
2607
2608 dib8000_set_isdbt_common_channel(state, slist, 1);
2609
2610 /* set lock_mask values */
2611 dib8000_write_word(state, 6, 0x4);
2612 if (state->revision == 0x8090)
2613 dib8000_write_word(state, 7, (1 << 12) | (1 << 11) | (1 << 10));
2614 else
2615 dib8000_write_word(state, 7, 0x8);
2616 dib8000_write_word(state, 8, 0x1000);
2617
2618 /* set lock_mask wait time values */
2619 if (state->revision == 0x8090)
2620 dib8000_wait_lock(state, internal, 50, 200, 1000); /* time in ms configure P_search_end0 P_search_end1 P_search_end2 */
2621 else
2622 dib8000_wait_lock(state, internal, 50, 100, 1000); /* time in ms configure P_search_end0 P_search_end1 P_search_end2 */
2623
2624 value = dib8000_read_word(state, 0);
2625 dib8000_write_word(state, 0, (u16)((1 << 15) | value));
2626 dib8000_read_word(state, 1284); /* reset the INT. n_irq_pending */
2627 dib8000_write_word(state, 0, (u16)value);
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002628 }
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002629 return 0;
2630}
2631
2632static int dib8000_autosearch_irq(struct dvb_frontend *fe)
2633{
2634 struct dib8000_state *state = fe->demodulator_priv;
2635 u16 irq_pending = dib8000_read_word(state, 1284);
2636
Olivier Grenied67350f2013-12-12 09:26:22 -03002637 if ((state->revision >= 0x8002) &&
2638 (state->autosearch_state == AS_SEARCHING_FFT)) {
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002639 if (irq_pending & 0x1) {
2640 dprintk("dib8000_autosearch_irq: max correlation result available");
2641 return 3;
2642 }
2643 } else {
2644 if (irq_pending & 0x1) { /* failed */
2645 dprintk("dib8000_autosearch_irq failed");
2646 return 1;
2647 }
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002648
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002649 if (irq_pending & 0x2) { /* succeeded */
2650 dprintk("dib8000_autosearch_irq succeeded");
2651 return 2;
2652 }
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002653 }
2654
2655 return 0; // still pending
2656}
2657
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002658static void dib8000_viterbi_state(struct dib8000_state *state, u8 onoff)
2659{
2660 u16 tmp;
2661
2662 tmp = dib8000_read_word(state, 771);
2663 if (onoff) /* start P_restart_chd : channel_decoder */
2664 dib8000_write_word(state, 771, tmp & 0xfffd);
2665 else /* stop P_restart_chd : channel_decoder */
2666 dib8000_write_word(state, 771, tmp | (1<<1));
2667}
2668
2669static void dib8000_set_dds(struct dib8000_state *state, s32 offset_khz)
2670{
2671 s16 unit_khz_dds_val;
2672 u32 abs_offset_khz = ABS(offset_khz);
2673 u32 dds = state->cfg.pll->ifreq & 0x1ffffff;
2674 u8 invert = !!(state->cfg.pll->ifreq & (1 << 25));
2675 u8 ratio;
2676
2677 if (state->revision == 0x8090) {
2678 ratio = 4;
2679 unit_khz_dds_val = (1<<26) / (dib8000_read32(state, 23) / 1000);
2680 if (offset_khz < 0)
2681 dds = (1 << 26) - (abs_offset_khz * unit_khz_dds_val);
2682 else
2683 dds = (abs_offset_khz * unit_khz_dds_val);
2684
2685 if (invert)
2686 dds = (1<<26) - dds;
2687 } else {
2688 ratio = 2;
2689 unit_khz_dds_val = (u16) (67108864 / state->cfg.pll->internal);
2690
2691 if (offset_khz < 0)
2692 unit_khz_dds_val *= -1;
2693
2694 /* IF tuner */
2695 if (invert)
2696 dds -= abs_offset_khz * unit_khz_dds_val;
2697 else
2698 dds += abs_offset_khz * unit_khz_dds_val;
2699 }
2700
2701 dprintk("setting a DDS frequency offset of %c%dkHz", invert ? '-' : ' ', dds / unit_khz_dds_val);
2702
2703 if (abs_offset_khz <= (state->cfg.pll->internal / ratio)) {
2704 /* Max dds offset is the half of the demod freq */
2705 dib8000_write_word(state, 26, invert);
2706 dib8000_write_word(state, 27, (u16)(dds >> 16) & 0x1ff);
2707 dib8000_write_word(state, 28, (u16)(dds & 0xffff));
2708 }
2709}
2710
2711static void dib8000_set_frequency_offset(struct dib8000_state *state)
2712{
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03002713 struct dtv_frontend_properties *c = &state->fe[0]->dtv_property_cache;
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002714 int i;
2715 u32 current_rf;
2716 int total_dds_offset_khz;
2717
2718 if (state->fe[0]->ops.tuner_ops.get_frequency)
2719 state->fe[0]->ops.tuner_ops.get_frequency(state->fe[0], &current_rf);
2720 else
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03002721 current_rf = c->frequency;
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002722 current_rf /= 1000;
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03002723 total_dds_offset_khz = (int)current_rf - (int)c->frequency / 1000;
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002724
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03002725 if (c->isdbt_sb_mode) {
2726 state->subchannel = c->isdbt_sb_subchannel;
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002727
2728 i = dib8000_read_word(state, 26) & 1; /* P_dds_invspec */
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03002729 dib8000_write_word(state, 26, c->inversion ^ i);
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002730
2731 if (state->cfg.pll->ifreq == 0) { /* low if tuner */
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03002732 if ((c->inversion ^ i) == 0)
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002733 dib8000_write_word(state, 26, dib8000_read_word(state, 26) | 1);
2734 } else {
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03002735 if ((c->inversion ^ i) == 0)
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002736 total_dds_offset_khz *= -1;
2737 }
2738 }
2739
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03002740 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 -03002741
2742 /* apply dds offset now */
2743 dib8000_set_dds(state, total_dds_offset_khz);
2744}
2745
2746static u16 LUT_isdbt_symbol_duration[4] = { 26, 101, 63 };
Mauro Carvalho Chehab6f7ee062013-04-25 10:36:56 -03002747
2748static u32 dib8000_get_symbol_duration(struct dib8000_state *state)
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002749{
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03002750 struct dtv_frontend_properties *c = &state->fe[0]->dtv_property_cache;
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002751 u16 i;
2752
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03002753 switch (c->transmission_mode) {
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002754 case TRANSMISSION_MODE_2K:
2755 i = 0;
2756 break;
2757 case TRANSMISSION_MODE_4K:
2758 i = 2;
2759 break;
2760 default:
2761 case TRANSMISSION_MODE_AUTO:
2762 case TRANSMISSION_MODE_8K:
2763 i = 1;
2764 break;
2765 }
2766
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03002767 return (LUT_isdbt_symbol_duration[i] / (c->bandwidth_hz / 1000)) + 1;
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002768}
2769
2770static void dib8000_set_isdbt_loop_params(struct dib8000_state *state, enum param_loop_step loop_step)
2771{
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03002772 struct dtv_frontend_properties *c = &state->fe[0]->dtv_property_cache;
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002773 u16 reg_32 = 0, reg_37 = 0;
2774
2775 switch (loop_step) {
2776 case LOOP_TUNE_1:
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03002777 if (c->isdbt_sb_mode) {
2778 if (c->isdbt_partial_reception == 0) {
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002779 reg_32 = ((11 - state->mode) << 12) | (6 << 8) | 0x40; /* P_timf_alpha = (11-P_mode), P_corm_alpha=6, P_corm_thres=0x40 */
2780 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) */
2781 } else { /* Sound Broadcasting mode 3 seg */
2782 reg_32 = ((10 - state->mode) << 12) | (6 << 8) | 0x60; /* P_timf_alpha = (10-P_mode), P_corm_alpha=6, P_corm_thres=0x60 */
2783 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) */
2784 }
2785 } else { /* 13-seg start conf offset loop parameters */
2786 reg_32 = ((9 - state->mode) << 12) | (6 << 8) | 0x80; /* P_timf_alpha = (9-P_mode, P_corm_alpha=6, P_corm_thres=0x80 */
2787 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 */
2788 }
2789 break;
2790 case LOOP_TUNE_2:
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03002791 if (c->isdbt_sb_mode) {
2792 if (c->isdbt_partial_reception == 0) { /* Sound Broadcasting mode 1 seg */
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002793 reg_32 = ((13-state->mode) << 12) | (6 << 8) | 0x40; /* P_timf_alpha = (13-P_mode) , P_corm_alpha=6, P_corm_thres=0x40*/
2794 reg_37 = (12-state->mode) | ((5 + state->mode) << 5);
2795 } else { /* Sound Broadcasting mode 3 seg */
2796 reg_32 = ((12-state->mode) << 12) | (6 << 8) | 0x60; /* P_timf_alpha = (12-P_mode) , P_corm_alpha=6, P_corm_thres=0x60 */
2797 reg_37 = (11-state->mode) | ((5 + state->mode) << 5);
2798 }
2799 } else { /* 13 seg */
2800 reg_32 = ((11-state->mode) << 12) | (6 << 8) | 0x80; /* P_timf_alpha = 8 , P_corm_alpha=6, P_corm_thres=0x80 */
2801 reg_37 = ((5+state->mode) << 5) | (10 - state->mode);
2802 }
2803 break;
2804 }
2805 dib8000_write_word(state, 32, reg_32);
2806 dib8000_write_word(state, 37, reg_37);
2807}
2808
2809static void dib8000_demod_restart(struct dib8000_state *state)
2810{
2811 dib8000_write_word(state, 770, 0x4000);
2812 dib8000_write_word(state, 770, 0x0000);
2813 return;
2814}
2815
2816static void dib8000_set_sync_wait(struct dib8000_state *state)
2817{
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03002818 struct dtv_frontend_properties *c = &state->fe[0]->dtv_property_cache;
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002819 u16 sync_wait = 64;
2820
2821 /* P_dvsy_sync_wait - reuse mode */
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03002822 switch (c->transmission_mode) {
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002823 case TRANSMISSION_MODE_8K:
2824 sync_wait = 256;
2825 break;
2826 case TRANSMISSION_MODE_4K:
2827 sync_wait = 128;
2828 break;
2829 default:
2830 case TRANSMISSION_MODE_2K:
2831 sync_wait = 64;
2832 break;
2833 }
2834
2835 if (state->cfg.diversity_delay == 0)
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03002836 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 -03002837 else
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03002838 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 -03002839
2840 dib8000_write_word(state, 273, (dib8000_read_word(state, 273) & 0x000f) | (sync_wait << 4));
2841}
2842
Mauro Carvalho Chehabd6c62b72014-07-04 14:15:37 -03002843static unsigned long dib8000_get_timeout(struct dib8000_state *state, u32 delay, enum timeout_mode mode)
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002844{
2845 if (mode == SYMBOL_DEPENDENT_ON)
Mauro Carvalho Chehabd6c62b72014-07-04 14:15:37 -03002846 delay *= state->symbol_duration;
2847
2848 return jiffies + usecs_to_jiffies(delay * 100);
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002849}
2850
2851static s32 dib8000_get_status(struct dvb_frontend *fe)
2852{
2853 struct dib8000_state *state = fe->demodulator_priv;
2854 return state->status;
2855}
2856
Mauro Carvalho Chehabd44913c2014-05-29 09:20:17 -03002857static enum frontend_tune_state dib8000_get_tune_state(struct dvb_frontend *fe)
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002858{
2859 struct dib8000_state *state = fe->demodulator_priv;
2860 return state->tune_state;
2861}
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002862
Mauro Carvalho Chehabd44913c2014-05-29 09:20:17 -03002863static int dib8000_set_tune_state(struct dvb_frontend *fe, enum frontend_tune_state tune_state)
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002864{
2865 struct dib8000_state *state = fe->demodulator_priv;
2866
2867 state->tune_state = tune_state;
2868 return 0;
2869}
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002870
2871static int dib8000_tune_restart_from_demod(struct dvb_frontend *fe)
2872{
2873 struct dib8000_state *state = fe->demodulator_priv;
2874
2875 state->status = FE_STATUS_TUNE_PENDING;
2876 state->tune_state = CT_DEMOD_START;
2877 return 0;
2878}
2879
2880static u16 dib8000_read_lock(struct dvb_frontend *fe)
2881{
2882 struct dib8000_state *state = fe->demodulator_priv;
2883
2884 if (state->revision == 0x8090)
2885 return dib8000_read_word(state, 570);
2886 return dib8000_read_word(state, 568);
2887}
2888
2889static int dib8090p_init_sdram(struct dib8000_state *state)
2890{
2891 u16 reg = 0;
2892 dprintk("init sdram");
2893
2894 reg = dib8000_read_word(state, 274) & 0xfff0;
2895 dib8000_write_word(state, 274, reg | 0x7); /* P_dintlv_delay_ram = 7 because of MobileSdram */
2896
2897 dib8000_write_word(state, 1803, (7 << 2));
2898
2899 reg = dib8000_read_word(state, 1280);
2900 dib8000_write_word(state, 1280, reg | (1 << 2)); /* force restart P_restart_sdram */
2901 dib8000_write_word(state, 1280, reg); /* release restart P_restart_sdram */
2902
2903 return 0;
2904}
2905
Mauro Carvalho Chehabad976182013-12-15 09:57:40 -03002906/**
2907 * is_manual_mode - Check if TMCC should be used for parameters settings
2908 * @c: struct dvb_frontend_properties
2909 *
2910 * By default, TMCC table should be used for parameter settings on most
2911 * usercases. However, sometimes it is desirable to lock the demod to
2912 * use the manual parameters.
2913 *
2914 * On manual mode, the current dib8000_tune state machine is very restrict:
2915 * It requires that both per-layer and per-transponder parameters to be
2916 * properly specified, otherwise the device won't lock.
2917 *
2918 * Check if all those conditions are properly satisfied before allowing
2919 * the device to use the manual frequency lock mode.
2920 */
2921static int is_manual_mode(struct dtv_frontend_properties *c)
2922{
2923 int i, n_segs = 0;
2924
2925 /* Use auto mode on DVB-T compat mode */
2926 if (c->delivery_system != SYS_ISDBT)
2927 return 0;
2928
2929 /*
2930 * Transmission mode is only detected on auto mode, currently
2931 */
2932 if (c->transmission_mode == TRANSMISSION_MODE_AUTO) {
2933 dprintk("transmission mode auto");
2934 return 0;
2935 }
2936
2937 /*
2938 * Guard interval is only detected on auto mode, currently
2939 */
2940 if (c->guard_interval == GUARD_INTERVAL_AUTO) {
2941 dprintk("guard interval auto");
2942 return 0;
2943 }
2944
2945 /*
2946 * If no layer is enabled, assume auto mode, as at least one
2947 * layer should be enabled
2948 */
2949 if (!c->isdbt_layer_enabled) {
2950 dprintk("no layer modulation specified");
2951 return 0;
2952 }
2953
2954 /*
2955 * Check if the per-layer parameters aren't auto and
2956 * disable a layer if segment count is 0 or invalid.
2957 */
2958 for (i = 0; i < 3; i++) {
2959 if (!(c->isdbt_layer_enabled & 1 << i))
2960 continue;
2961
2962 if ((c->layer[i].segment_count > 13) ||
2963 (c->layer[i].segment_count == 0)) {
2964 c->isdbt_layer_enabled &= ~(1 << i);
2965 continue;
2966 }
2967
2968 n_segs += c->layer[i].segment_count;
2969
2970 if ((c->layer[i].modulation == QAM_AUTO) ||
2971 (c->layer[i].fec == FEC_AUTO)) {
2972 dprintk("layer %c has either modulation or FEC auto",
2973 'A' + i);
2974 return 0;
2975 }
2976 }
2977
2978 /*
2979 * Userspace specified a wrong number of segments.
2980 * fallback to auto mode.
2981 */
2982 if (n_segs == 0 || n_segs > 13) {
2983 dprintk("number of segments is invalid");
2984 return 0;
2985 }
2986
2987 /* Everything looks ok for manual mode */
2988 return 1;
2989}
2990
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002991static int dib8000_tune(struct dvb_frontend *fe)
2992{
2993 struct dib8000_state *state = fe->demodulator_priv;
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03002994 struct dtv_frontend_properties *c = &state->fe[0]->dtv_property_cache;
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002995 enum frontend_tune_state *tune_state = &state->tune_state;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002996
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002997 u16 locks, deeper_interleaver = 0, i;
2998 int ret = 1; /* 1 symbol duration (in 100us unit) delay most of the time */
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002999
Mauro Carvalho Chehabd6c62b72014-07-04 14:15:37 -03003000 unsigned long *timeout = &state->timeout;
3001 unsigned long now = jiffies;
Patrick Boettcher173a64c2013-04-22 12:45:52 -03003002#ifdef DIB8000_AGC_FREEZE
3003 u16 agc1, agc2;
3004#endif
Dan Carpentere04f4b22012-07-20 07:11:57 -03003005
Patrick Boettcher173a64c2013-04-22 12:45:52 -03003006 u32 corm[4] = {0, 0, 0, 0};
3007 u8 find_index, max_value;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003008
Patrick Boettcher173a64c2013-04-22 12:45:52 -03003009#if 0
3010 if (*tune_state < CT_DEMOD_STOP)
Mauro Carvalho Chehabd6c62b72014-07-04 14:15:37 -03003011 dprintk("IN: context status = %d, TUNE_STATE %d autosearch step = %u jiffies = %lu",
3012 state->channel_parameters_set, *tune_state, state->autosearch_state, now);
Patrick Boettcher173a64c2013-04-22 12:45:52 -03003013#endif
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003014
Patrick Boettcher173a64c2013-04-22 12:45:52 -03003015 switch (*tune_state) {
3016 case CT_DEMOD_START: /* 30 */
Mauro Carvalho Chehab7fa676c2014-07-04 14:15:29 -03003017 dib8000_reset_stats(fe);
Mauro Carvalho Chehab6ef06e72013-12-16 19:10:59 -03003018
Mauro Carvalho Chehab7fa676c2014-07-04 14:15:29 -03003019 if (state->revision == 0x8090)
3020 dib8090p_init_sdram(state);
3021 state->status = FE_STATUS_TUNE_PENDING;
3022 state->channel_parameters_set = is_manual_mode(c);
Mauro Carvalho Chehabad976182013-12-15 09:57:40 -03003023
Mauro Carvalho Chehab7fa676c2014-07-04 14:15:29 -03003024 dprintk("Tuning channel on %s search mode",
3025 state->channel_parameters_set ? "manual" : "auto");
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003026
Mauro Carvalho Chehab7fa676c2014-07-04 14:15:29 -03003027 dib8000_viterbi_state(state, 0); /* force chan dec in restart */
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003028
Mauro Carvalho Chehab7fa676c2014-07-04 14:15:29 -03003029 /* Layer monitor */
3030 dib8000_write_word(state, 285, dib8000_read_word(state, 285) & 0x60);
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003031
Mauro Carvalho Chehab7fa676c2014-07-04 14:15:29 -03003032 dib8000_set_frequency_offset(state);
3033 dib8000_set_bandwidth(fe, c->bandwidth_hz / 1000);
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003034
Mauro Carvalho Chehab7fa676c2014-07-04 14:15:29 -03003035 if (state->channel_parameters_set == 0) { /* The channel struct is unknown, search it ! */
Patrick Boettcher173a64c2013-04-22 12:45:52 -03003036#ifdef DIB8000_AGC_FREEZE
Mauro Carvalho Chehab7fa676c2014-07-04 14:15:29 -03003037 if (state->revision != 0x8090) {
3038 state->agc1_max = dib8000_read_word(state, 108);
3039 state->agc1_min = dib8000_read_word(state, 109);
3040 state->agc2_max = dib8000_read_word(state, 110);
3041 state->agc2_min = dib8000_read_word(state, 111);
3042 agc1 = dib8000_read_word(state, 388);
3043 agc2 = dib8000_read_word(state, 389);
3044 dib8000_write_word(state, 108, agc1);
3045 dib8000_write_word(state, 109, agc1);
3046 dib8000_write_word(state, 110, agc2);
3047 dib8000_write_word(state, 111, agc2);
Patrick Boettcher173a64c2013-04-22 12:45:52 -03003048 }
Mauro Carvalho Chehab7fa676c2014-07-04 14:15:29 -03003049#endif
3050 state->autosearch_state = AS_SEARCHING_FFT;
3051 state->found_nfft = TRANSMISSION_MODE_AUTO;
3052 state->found_guard = GUARD_INTERVAL_AUTO;
3053 *tune_state = CT_DEMOD_SEARCH_NEXT;
3054 } else { /* we already know the channel struct so TUNE only ! */
3055 state->autosearch_state = AS_DONE;
3056 *tune_state = CT_DEMOD_STEP_3;
3057 }
3058 state->symbol_duration = dib8000_get_symbol_duration(state);
3059 break;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003060
Patrick Boettcher173a64c2013-04-22 12:45:52 -03003061 case CT_DEMOD_SEARCH_NEXT: /* 51 */
Mauro Carvalho Chehab7fa676c2014-07-04 14:15:29 -03003062 dib8000_autosearch_start(fe);
3063 if (state->revision == 0x8090)
3064 ret = 50;
3065 else
3066 ret = 15;
3067 *tune_state = CT_DEMOD_STEP_1;
3068 break;
3069
3070 case CT_DEMOD_STEP_1: /* 31 */
3071 switch (dib8000_autosearch_irq(fe)) {
3072 case 1: /* fail */
3073 state->status = FE_STATUS_TUNE_FAILED;
3074 state->autosearch_state = AS_DONE;
3075 *tune_state = CT_DEMOD_STOP; /* else we are done here */
3076 break;
3077 case 2: /* Succes */
3078 state->status = FE_STATUS_FFT_SUCCESS; /* signal to the upper layer, that there was a channel found and the parameters can be read */
3079 *tune_state = CT_DEMOD_STEP_3;
3080 if (state->autosearch_state == AS_SEARCHING_GUARD)
3081 *tune_state = CT_DEMOD_STEP_2;
3082 else
3083 state->autosearch_state = AS_DONE;
3084 break;
3085 case 3: /* Autosearch FFT max correlation endded */
3086 *tune_state = CT_DEMOD_STEP_2;
3087 break;
3088 }
3089 break;
3090
3091 case CT_DEMOD_STEP_2:
3092 switch (state->autosearch_state) {
3093 case AS_SEARCHING_FFT:
3094 /* searching for the correct FFT */
3095 if (state->revision == 0x8090) {
3096 corm[2] = (dib8000_read_word(state, 596) << 16) | (dib8000_read_word(state, 597));
3097 corm[1] = (dib8000_read_word(state, 598) << 16) | (dib8000_read_word(state, 599));
3098 corm[0] = (dib8000_read_word(state, 600) << 16) | (dib8000_read_word(state, 601));
3099 } else {
3100 corm[2] = (dib8000_read_word(state, 594) << 16) | (dib8000_read_word(state, 595));
3101 corm[1] = (dib8000_read_word(state, 596) << 16) | (dib8000_read_word(state, 597));
3102 corm[0] = (dib8000_read_word(state, 598) << 16) | (dib8000_read_word(state, 599));
3103 }
3104 /* dprintk("corm fft: %u %u %u", corm[0], corm[1], corm[2]); */
3105
3106 max_value = 0;
3107 for (find_index = 1 ; find_index < 3 ; find_index++) {
3108 if (corm[max_value] < corm[find_index])
3109 max_value = find_index ;
3110 }
3111
3112 switch (max_value) {
3113 case 0:
3114 state->found_nfft = TRANSMISSION_MODE_2K;
3115 break;
3116 case 1:
3117 state->found_nfft = TRANSMISSION_MODE_4K;
3118 break;
3119 case 2:
3120 default:
3121 state->found_nfft = TRANSMISSION_MODE_8K;
3122 break;
3123 }
3124 /* dprintk("Autosearch FFT has found Mode %d", max_value + 1); */
3125
3126 *tune_state = CT_DEMOD_SEARCH_NEXT;
3127 state->autosearch_state = AS_SEARCHING_GUARD;
Patrick Boettcher173a64c2013-04-22 12:45:52 -03003128 if (state->revision == 0x8090)
3129 ret = 50;
3130 else
Mauro Carvalho Chehab7fa676c2014-07-04 14:15:29 -03003131 ret = 10;
Patrick Boettcher173a64c2013-04-22 12:45:52 -03003132 break;
Mauro Carvalho Chehab7fa676c2014-07-04 14:15:29 -03003133 case AS_SEARCHING_GUARD:
3134 /* searching for the correct guard interval */
3135 if (state->revision == 0x8090)
3136 state->found_guard = dib8000_read_word(state, 572) & 0x3;
3137 else
3138 state->found_guard = dib8000_read_word(state, 570) & 0x3;
3139 /* dprintk("guard interval found=%i", state->found_guard); */
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003140
Mauro Carvalho Chehab7fa676c2014-07-04 14:15:29 -03003141 *tune_state = CT_DEMOD_STEP_3;
Patrick Boettcher173a64c2013-04-22 12:45:52 -03003142 break;
Mauro Carvalho Chehab7fa676c2014-07-04 14:15:29 -03003143 default:
3144 /* the demod should never be in this state */
3145 state->status = FE_STATUS_TUNE_FAILED;
3146 state->autosearch_state = AS_DONE;
3147 *tune_state = CT_DEMOD_STOP; /* else we are done here */
Patrick Boettcher173a64c2013-04-22 12:45:52 -03003148 break;
Mauro Carvalho Chehab7fa676c2014-07-04 14:15:29 -03003149 }
3150 break;
Patrick Boettcher173a64c2013-04-22 12:45:52 -03003151
3152 case CT_DEMOD_STEP_3: /* 33 */
Mauro Carvalho Chehab7fa676c2014-07-04 14:15:29 -03003153 dib8000_set_isdbt_loop_params(state, LOOP_TUNE_1);
3154 dib8000_set_isdbt_common_channel(state, 0, 0);/* setting the known channel parameters here */
3155 *tune_state = CT_DEMOD_STEP_4;
3156 break;
Patrick Boettcher173a64c2013-04-22 12:45:52 -03003157
3158 case CT_DEMOD_STEP_4: /* (34) */
Mauro Carvalho Chehab7fa676c2014-07-04 14:15:29 -03003159 dib8000_demod_restart(state);
Patrick Boettcher173a64c2013-04-22 12:45:52 -03003160
Mauro Carvalho Chehab7fa676c2014-07-04 14:15:29 -03003161 dib8000_set_sync_wait(state);
3162 dib8000_set_diversity_in(state->fe[0], state->diversity_onoff);
Patrick Boettcher173a64c2013-04-22 12:45:52 -03003163
Mauro Carvalho Chehab7fa676c2014-07-04 14:15:29 -03003164 locks = (dib8000_read_word(state, 180) >> 6) & 0x3f; /* P_coff_winlen ? */
3165 /* coff should lock over P_coff_winlen ofdm symbols : give 3 times this length to lock */
3166 *timeout = dib8000_get_timeout(state, 2 * locks, SYMBOL_DEPENDENT_ON);
3167 *tune_state = CT_DEMOD_STEP_5;
3168 break;
Patrick Boettcher173a64c2013-04-22 12:45:52 -03003169
3170 case CT_DEMOD_STEP_5: /* (35) */
Mauro Carvalho Chehab7fa676c2014-07-04 14:15:29 -03003171 locks = dib8000_read_lock(fe);
3172 if (locks & (0x3 << 11)) { /* coff-lock and off_cpil_lock achieved */
3173 dib8000_update_timf(state); /* we achieved a coff_cpil_lock - it's time to update the timf */
3174 if (!state->differential_constellation) {
3175 /* 2 times lmod4_win_len + 10 symbols (pipe delay after coff + nb to compute a 1st correlation) */
3176 *timeout = dib8000_get_timeout(state, (20 * ((dib8000_read_word(state, 188)>>5)&0x1f)), SYMBOL_DEPENDENT_ON);
3177 *tune_state = CT_DEMOD_STEP_7;
3178 } else {
3179 *tune_state = CT_DEMOD_STEP_8;
Patrick Boettcher173a64c2013-04-22 12:45:52 -03003180 }
Mauro Carvalho Chehabd6c62b72014-07-04 14:15:37 -03003181 } else if (time_after(now, *timeout)) {
Mauro Carvalho Chehab7fa676c2014-07-04 14:15:29 -03003182 *tune_state = CT_DEMOD_STEP_6; /* goto check for diversity input connection */
3183 }
3184 break;
Patrick Boettcher173a64c2013-04-22 12:45:52 -03003185
3186 case CT_DEMOD_STEP_6: /* (36) if there is an input (diversity) */
Mauro Carvalho Chehab7fa676c2014-07-04 14:15:29 -03003187 if ((state->fe[1] != NULL) && (state->output_mode != OUTMODE_DIVERSITY)) {
3188 /* 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 */
3189 if (dib8000_get_status(state->fe[1]) <= FE_STATUS_STD_SUCCESS) /* Something is locked on the input fe */
3190 *tune_state = CT_DEMOD_STEP_8; /* go for mpeg */
3191 else if (dib8000_get_status(state->fe[1]) >= FE_STATUS_TUNE_TIME_TOO_SHORT) { /* fe in input failled also, break the current one */
3192 *tune_state = CT_DEMOD_STOP; /* else we are done here ; step 8 will close the loops and exit */
Patrick Boettcher173a64c2013-04-22 12:45:52 -03003193 dib8000_viterbi_state(state, 1); /* start viterbi chandec */
3194 dib8000_set_isdbt_loop_params(state, LOOP_TUNE_2);
Patrick Boettcher173a64c2013-04-22 12:45:52 -03003195 state->status = FE_STATUS_TUNE_FAILED;
3196 }
Mauro Carvalho Chehab7fa676c2014-07-04 14:15:29 -03003197 } else {
Patrick Boettcher173a64c2013-04-22 12:45:52 -03003198 dib8000_viterbi_state(state, 1); /* start viterbi chandec */
3199 dib8000_set_isdbt_loop_params(state, LOOP_TUNE_2);
Mauro Carvalho Chehab7fa676c2014-07-04 14:15:29 -03003200 *tune_state = CT_DEMOD_STOP; /* else we are done here ; step 8 will close the loops and exit */
3201 state->status = FE_STATUS_TUNE_FAILED;
3202 }
3203 break;
Patrick Boettcher173a64c2013-04-22 12:45:52 -03003204
Mauro Carvalho Chehab7fa676c2014-07-04 14:15:29 -03003205 case CT_DEMOD_STEP_7: /* 37 */
3206 locks = dib8000_read_lock(fe);
3207 if (locks & (1<<10)) { /* lmod4_lock */
3208 ret = 14; /* wait for 14 symbols */
3209 *tune_state = CT_DEMOD_STEP_8;
Mauro Carvalho Chehabd6c62b72014-07-04 14:15:37 -03003210 } else if (time_after(now, *timeout))
Mauro Carvalho Chehab7fa676c2014-07-04 14:15:29 -03003211 *tune_state = CT_DEMOD_STEP_6; /* goto check for diversity input connection */
3212 break;
3213
3214 case CT_DEMOD_STEP_8: /* 38 */
3215 dib8000_viterbi_state(state, 1); /* start viterbi chandec */
3216 dib8000_set_isdbt_loop_params(state, LOOP_TUNE_2);
3217
3218 /* mpeg will never lock on this condition because init_prbs is not set : search for it !*/
3219 if (c->isdbt_sb_mode
3220 && c->isdbt_sb_subchannel < 14
3221 && !state->differential_constellation) {
3222 state->subchannel = 0;
3223 *tune_state = CT_DEMOD_STEP_11;
3224 } else {
3225 *tune_state = CT_DEMOD_STEP_9;
3226 state->status = FE_STATUS_LOCKED;
3227 }
3228 break;
Patrick Boettcher173a64c2013-04-22 12:45:52 -03003229
3230 case CT_DEMOD_STEP_9: /* 39 */
Mauro Carvalho Chehab7fa676c2014-07-04 14:15:29 -03003231 if ((state->revision == 0x8090) || ((dib8000_read_word(state, 1291) >> 9) & 0x1)) { /* fe capable of deinterleaving : esram */
3232 /* defines timeout for mpeg lock depending on interleaver length of longest layer */
3233 for (i = 0; i < 3; i++) {
3234 if (c->layer[i].interleaving >= deeper_interleaver) {
3235 dprintk("layer%i: time interleaver = %d ", i, c->layer[i].interleaving);
3236 if (c->layer[i].segment_count > 0) { /* valid layer */
3237 deeper_interleaver = c->layer[0].interleaving;
3238 state->longest_intlv_layer = i;
Patrick Boettcher173a64c2013-04-22 12:45:52 -03003239 }
3240 }
Mauro Carvalho Chehab7fa676c2014-07-04 14:15:29 -03003241 }
Patrick Boettcher173a64c2013-04-22 12:45:52 -03003242
Mauro Carvalho Chehab7fa676c2014-07-04 14:15:29 -03003243 if (deeper_interleaver == 0)
3244 locks = 2; /* locks is the tmp local variable name */
3245 else if (deeper_interleaver == 3)
3246 locks = 8;
3247 else
3248 locks = 2 * deeper_interleaver;
Patrick Boettcher173a64c2013-04-22 12:45:52 -03003249
Mauro Carvalho Chehab7fa676c2014-07-04 14:15:29 -03003250 if (state->diversity_onoff != 0) /* because of diversity sync */
3251 locks *= 2;
Patrick Boettcher173a64c2013-04-22 12:45:52 -03003252
Mauro Carvalho Chehabd6c62b72014-07-04 14:15:37 -03003253 *timeout = now + msecs_to_jiffies(200 * locks); /* give the mpeg lock 800ms if sram is present */
3254 dprintk("Deeper interleaver mode = %d on layer %d : timeout mult factor = %d => will use timeout = %ld",
3255 deeper_interleaver, state->longest_intlv_layer, locks, *timeout);
Patrick Boettcher173a64c2013-04-22 12:45:52 -03003256
Mauro Carvalho Chehab7fa676c2014-07-04 14:15:29 -03003257 *tune_state = CT_DEMOD_STEP_10;
3258 } else
3259 *tune_state = CT_DEMOD_STOP;
3260 break;
Patrick Boettcher173a64c2013-04-22 12:45:52 -03003261
3262 case CT_DEMOD_STEP_10: /* 40 */
Mauro Carvalho Chehab7fa676c2014-07-04 14:15:29 -03003263 locks = dib8000_read_lock(fe);
3264 if (locks&(1<<(7-state->longest_intlv_layer))) { /* mpeg lock : check the longest one */
Mauro Carvalho Chehab3c0d3942014-07-04 14:15:40 -03003265 dprintk("ISDB-T layer locks: Layer A %s, Layer B %s, Layer C %s",
3266 c->layer[0].segment_count ? (locks >> 7) & 0x1 ? "locked" : "NOT LOCKED" : "not enabled",
3267 c->layer[1].segment_count ? (locks >> 6) & 0x1 ? "locked" : "NOT LOCKED" : "not enabled",
3268 c->layer[2].segment_count ? (locks >> 5) & 0x1 ? "locked" : "NOT LOCKED" : "not enabled");
Mauro Carvalho Chehab7fa676c2014-07-04 14:15:29 -03003269 if (c->isdbt_sb_mode
3270 && c->isdbt_sb_subchannel < 14
3271 && !state->differential_constellation)
3272 /* signal to the upper layer, that there was a channel found and the parameters can be read */
3273 state->status = FE_STATUS_DEMOD_SUCCESS;
3274 else
3275 state->status = FE_STATUS_DATA_LOCKED;
3276 *tune_state = CT_DEMOD_STOP;
Mauro Carvalho Chehabd6c62b72014-07-04 14:15:37 -03003277 } else if (time_after(now, *timeout)) {
Mauro Carvalho Chehab7fa676c2014-07-04 14:15:29 -03003278 if (c->isdbt_sb_mode
3279 && c->isdbt_sb_subchannel < 14
3280 && !state->differential_constellation) { /* continue to try init prbs autosearch */
3281 state->subchannel += 3;
3282 *tune_state = CT_DEMOD_STEP_11;
3283 } else { /* we are done mpeg of the longest interleaver xas not locking but let's try if an other layer has locked in the same time */
Mauro Carvalho Chehab3c0d3942014-07-04 14:15:40 -03003284 if (locks & (0x7 << 5)) {
3285 dprintk("Not all ISDB-T layers locked in %d ms: Layer A %s, Layer B %s, Layer C %s",
3286 jiffies_to_msecs(now - *timeout),
3287 c->layer[0].segment_count ? (locks >> 7) & 0x1 ? "locked" : "NOT LOCKED" : "not enabled",
3288 c->layer[1].segment_count ? (locks >> 6) & 0x1 ? "locked" : "NOT LOCKED" : "not enabled",
3289 c->layer[2].segment_count ? (locks >> 5) & 0x1 ? "locked" : "NOT LOCKED" : "not enabled");
3290
Patrick Boettcher173a64c2013-04-22 12:45:52 -03003291 state->status = FE_STATUS_DATA_LOCKED;
Mauro Carvalho Chehab7fa676c2014-07-04 14:15:29 -03003292 } else
3293 state->status = FE_STATUS_TUNE_FAILED;
Patrick Boettcher173a64c2013-04-22 12:45:52 -03003294 *tune_state = CT_DEMOD_STOP;
Patrick Boettcher173a64c2013-04-22 12:45:52 -03003295 }
Mauro Carvalho Chehab7fa676c2014-07-04 14:15:29 -03003296 }
3297 break;
Patrick Boettcher173a64c2013-04-22 12:45:52 -03003298
3299 case CT_DEMOD_STEP_11: /* 41 : init prbs autosearch */
Mauro Carvalho Chehab7fa676c2014-07-04 14:15:29 -03003300 if (state->subchannel <= 41) {
3301 dib8000_set_subchannel_prbs(state, dib8000_get_init_prbs(state, state->subchannel));
3302 *tune_state = CT_DEMOD_STEP_9;
3303 } else {
3304 *tune_state = CT_DEMOD_STOP;
3305 state->status = FE_STATUS_TUNE_FAILED;
3306 }
3307 break;
Patrick Boettcher173a64c2013-04-22 12:45:52 -03003308
3309 default:
Mauro Carvalho Chehab7fa676c2014-07-04 14:15:29 -03003310 break;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003311 }
3312
Patrick Boettcher173a64c2013-04-22 12:45:52 -03003313 /* tuning is finished - cleanup the demod */
3314 switch (*tune_state) {
3315 case CT_DEMOD_STOP: /* (42) */
3316#ifdef DIB8000_AGC_FREEZE
Mauro Carvalho Chehab7fa676c2014-07-04 14:15:29 -03003317 if ((state->revision != 0x8090) && (state->agc1_max != 0)) {
3318 dib8000_write_word(state, 108, state->agc1_max);
3319 dib8000_write_word(state, 109, state->agc1_min);
3320 dib8000_write_word(state, 110, state->agc2_max);
3321 dib8000_write_word(state, 111, state->agc2_min);
3322 state->agc1_max = 0;
3323 state->agc1_min = 0;
3324 state->agc2_max = 0;
3325 state->agc2_min = 0;
3326 }
Patrick Boettcher173a64c2013-04-22 12:45:52 -03003327#endif
Mauro Carvalho Chehabd6c62b72014-07-04 14:15:37 -03003328 ret = 0;
Mauro Carvalho Chehab7fa676c2014-07-04 14:15:29 -03003329 break;
Patrick Boettcher173a64c2013-04-22 12:45:52 -03003330 default:
Mauro Carvalho Chehab7fa676c2014-07-04 14:15:29 -03003331 break;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003332 }
3333
Patrick Boettcher173a64c2013-04-22 12:45:52 -03003334 if ((ret > 0) && (*tune_state > CT_DEMOD_STEP_3))
3335 return ret * state->symbol_duration;
3336 if ((ret > 0) && (ret < state->symbol_duration))
3337 return state->symbol_duration; /* at least one symbol */
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003338 return ret;
3339}
3340
3341static int dib8000_wakeup(struct dvb_frontend *fe)
3342{
3343 struct dib8000_state *state = fe->demodulator_priv;
Olivier Grenie4c70e072011-01-03 15:33:37 -03003344 u8 index_frontend;
3345 int ret;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003346
Olivier Grenie0c32dbd2011-08-10 05:17:18 -03003347 dib8000_set_power_mode(state, DIB8000_POWER_ALL);
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003348 dib8000_set_adc_state(state, DIBX000_ADC_ON);
3349 if (dib8000_set_adc_state(state, DIBX000_SLOW_ADC_ON) != 0)
3350 dprintk("could not start Slow ADC");
3351
Patrick Boettcher173a64c2013-04-22 12:45:52 -03003352 if (state->revision == 0x8090)
Olivier Grenie0c32dbd2011-08-10 05:17:18 -03003353 dib8000_sad_calib(state);
3354
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03003355 for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
Olivier Grenie4c70e072011-01-03 15:33:37 -03003356 ret = state->fe[index_frontend]->ops.init(state->fe[index_frontend]);
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03003357 if (ret < 0)
Olivier Grenie4c70e072011-01-03 15:33:37 -03003358 return ret;
3359 }
3360
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003361 return 0;
3362}
3363
3364static int dib8000_sleep(struct dvb_frontend *fe)
3365{
Olivier Grenie4c70e072011-01-03 15:33:37 -03003366 struct dib8000_state *state = fe->demodulator_priv;
3367 u8 index_frontend;
3368 int ret;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003369
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03003370 for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
Olivier Grenie4c70e072011-01-03 15:33:37 -03003371 ret = state->fe[index_frontend]->ops.sleep(state->fe[index_frontend]);
3372 if (ret < 0)
3373 return ret;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003374 }
Olivier Grenie4c70e072011-01-03 15:33:37 -03003375
Olivier Grenie0c32dbd2011-08-10 05:17:18 -03003376 if (state->revision != 0x8090)
3377 dib8000_set_output_mode(fe, OUTMODE_HIGH_Z);
3378 dib8000_set_power_mode(state, DIB8000_POWER_INTERFACE_ONLY);
Olivier Grenie4c70e072011-01-03 15:33:37 -03003379 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 -03003380}
3381
Mauro Carvalho Chehab70315b32013-12-15 07:41:20 -02003382static int dib8000_read_status(struct dvb_frontend *fe, fe_status_t * stat);
3383
Mauro Carvalho Chehab7c61d802011-12-30 11:30:21 -03003384static int dib8000_get_frontend(struct dvb_frontend *fe)
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003385{
3386 struct dib8000_state *state = fe->demodulator_priv;
3387 u16 i, val = 0;
Mauro Carvalho Chehab70315b32013-12-15 07:41:20 -02003388 fe_status_t stat = 0;
Olivier Grenie4c70e072011-01-03 15:33:37 -03003389 u8 index_frontend, sub_index_frontend;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003390
3391 fe->dtv_property_cache.bandwidth_hz = 6000000;
3392
Mauro Carvalho Chehab70315b32013-12-15 07:41:20 -02003393 /*
3394 * If called to early, get_frontend makes dib8000_tune to either
3395 * not lock or not sync. This causes dvbv5-scan/dvbv5-zap to fail.
3396 * So, let's just return if frontend 0 has not locked.
3397 */
3398 dib8000_read_status(fe, &stat);
3399 if (!(stat & FE_HAS_SYNC))
3400 return 0;
3401
Mauro Carvalho Chehabecc31d52014-07-04 14:15:39 -03003402 dprintk("dib8000_get_frontend: TMCC lock");
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03003403 for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
Olivier Grenie4c70e072011-01-03 15:33:37 -03003404 state->fe[index_frontend]->ops.read_status(state->fe[index_frontend], &stat);
3405 if (stat&FE_HAS_SYNC) {
3406 dprintk("TMCC lock on the slave%i", index_frontend);
3407 /* synchronize the cache with the other frontends */
Mauro Carvalho Chehab7c61d802011-12-30 11:30:21 -03003408 state->fe[index_frontend]->ops.get_frontend(state->fe[index_frontend]);
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03003409 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 -03003410 if (sub_index_frontend != index_frontend) {
3411 state->fe[sub_index_frontend]->dtv_property_cache.isdbt_sb_mode = state->fe[index_frontend]->dtv_property_cache.isdbt_sb_mode;
3412 state->fe[sub_index_frontend]->dtv_property_cache.inversion = state->fe[index_frontend]->dtv_property_cache.inversion;
3413 state->fe[sub_index_frontend]->dtv_property_cache.transmission_mode = state->fe[index_frontend]->dtv_property_cache.transmission_mode;
3414 state->fe[sub_index_frontend]->dtv_property_cache.guard_interval = state->fe[index_frontend]->dtv_property_cache.guard_interval;
3415 state->fe[sub_index_frontend]->dtv_property_cache.isdbt_partial_reception = state->fe[index_frontend]->dtv_property_cache.isdbt_partial_reception;
3416 for (i = 0; i < 3; i++) {
3417 state->fe[sub_index_frontend]->dtv_property_cache.layer[i].segment_count = state->fe[index_frontend]->dtv_property_cache.layer[i].segment_count;
3418 state->fe[sub_index_frontend]->dtv_property_cache.layer[i].interleaving = state->fe[index_frontend]->dtv_property_cache.layer[i].interleaving;
3419 state->fe[sub_index_frontend]->dtv_property_cache.layer[i].fec = state->fe[index_frontend]->dtv_property_cache.layer[i].fec;
3420 state->fe[sub_index_frontend]->dtv_property_cache.layer[i].modulation = state->fe[index_frontend]->dtv_property_cache.layer[i].modulation;
3421 }
3422 }
3423 }
3424 return 0;
3425 }
3426 }
3427
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003428 fe->dtv_property_cache.isdbt_sb_mode = dib8000_read_word(state, 508) & 0x1;
3429
Olivier Grenie0c32dbd2011-08-10 05:17:18 -03003430 if (state->revision == 0x8090)
3431 val = dib8000_read_word(state, 572);
3432 else
3433 val = dib8000_read_word(state, 570);
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003434 fe->dtv_property_cache.inversion = (val & 0x40) >> 6;
3435 switch ((val & 0x30) >> 4) {
3436 case 1:
3437 fe->dtv_property_cache.transmission_mode = TRANSMISSION_MODE_2K;
Mauro Carvalho Chehabecc31d52014-07-04 14:15:39 -03003438 dprintk("dib8000_get_frontend: transmission mode 2K");
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003439 break;
Mauro Carvalho Chehab7fec1c82014-07-04 14:15:30 -03003440 case 2:
3441 fe->dtv_property_cache.transmission_mode = TRANSMISSION_MODE_4K;
Mauro Carvalho Chehabecc31d52014-07-04 14:15:39 -03003442 dprintk("dib8000_get_frontend: transmission mode 4K");
Mauro Carvalho Chehab7fec1c82014-07-04 14:15:30 -03003443 break;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003444 case 3:
3445 default:
3446 fe->dtv_property_cache.transmission_mode = TRANSMISSION_MODE_8K;
Mauro Carvalho Chehabecc31d52014-07-04 14:15:39 -03003447 dprintk("dib8000_get_frontend: transmission mode 8K");
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003448 break;
3449 }
3450
3451 switch (val & 0x3) {
3452 case 0:
3453 fe->dtv_property_cache.guard_interval = GUARD_INTERVAL_1_32;
Mauro Carvalho Chehabecc31d52014-07-04 14:15:39 -03003454 dprintk("dib8000_get_frontend: Guard Interval = 1/32 ");
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003455 break;
3456 case 1:
3457 fe->dtv_property_cache.guard_interval = GUARD_INTERVAL_1_16;
Mauro Carvalho Chehabecc31d52014-07-04 14:15:39 -03003458 dprintk("dib8000_get_frontend: Guard Interval = 1/16 ");
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003459 break;
3460 case 2:
Mauro Carvalho Chehabecc31d52014-07-04 14:15:39 -03003461 dprintk("dib8000_get_frontend: Guard Interval = 1/8 ");
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003462 fe->dtv_property_cache.guard_interval = GUARD_INTERVAL_1_8;
3463 break;
3464 case 3:
Mauro Carvalho Chehabecc31d52014-07-04 14:15:39 -03003465 dprintk("dib8000_get_frontend: Guard Interval = 1/4 ");
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003466 fe->dtv_property_cache.guard_interval = GUARD_INTERVAL_1_4;
3467 break;
3468 }
3469
3470 val = dib8000_read_word(state, 505);
3471 fe->dtv_property_cache.isdbt_partial_reception = val & 1;
Mauro Carvalho Chehabecc31d52014-07-04 14:15:39 -03003472 dprintk("dib8000_get_frontend: partial_reception = %d ", fe->dtv_property_cache.isdbt_partial_reception);
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003473
3474 for (i = 0; i < 3; i++) {
Mauro Carvalho Chehabecc31d52014-07-04 14:15:39 -03003475 int show;
3476
3477 val = dib8000_read_word(state, 493 + i) & 0x0f;
3478 fe->dtv_property_cache.layer[i].segment_count = val;
3479
3480 if (val == 0 || val > 13)
3481 show = 0;
3482 else
3483 show = 1;
3484
3485 if (show)
3486 dprintk("dib8000_get_frontend: Layer %d segments = %d ",
3487 i, fe->dtv_property_cache.layer[i].segment_count);
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003488
Mauro Carvalho Chehab51fea112013-12-16 04:16:59 -03003489 val = dib8000_read_word(state, 499 + i) & 0x3;
3490 /* Interleaving can be 0, 1, 2 or 4 */
3491 if (val == 3)
3492 val = 4;
3493 fe->dtv_property_cache.layer[i].interleaving = val;
Mauro Carvalho Chehabecc31d52014-07-04 14:15:39 -03003494 if (show)
3495 dprintk("dib8000_get_frontend: Layer %d time_intlv = %d ",
3496 i, fe->dtv_property_cache.layer[i].interleaving);
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003497
3498 val = dib8000_read_word(state, 481 + i);
3499 switch (val & 0x7) {
3500 case 1:
3501 fe->dtv_property_cache.layer[i].fec = FEC_1_2;
Mauro Carvalho Chehabecc31d52014-07-04 14:15:39 -03003502 if (show)
3503 dprintk("dib8000_get_frontend: Layer %d Code Rate = 1/2 ", i);
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003504 break;
3505 case 2:
3506 fe->dtv_property_cache.layer[i].fec = FEC_2_3;
Mauro Carvalho Chehabecc31d52014-07-04 14:15:39 -03003507 if (show)
3508 dprintk("dib8000_get_frontend: Layer %d Code Rate = 2/3 ", i);
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003509 break;
3510 case 3:
3511 fe->dtv_property_cache.layer[i].fec = FEC_3_4;
Mauro Carvalho Chehabecc31d52014-07-04 14:15:39 -03003512 if (show)
3513 dprintk("dib8000_get_frontend: Layer %d Code Rate = 3/4 ", i);
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003514 break;
3515 case 5:
3516 fe->dtv_property_cache.layer[i].fec = FEC_5_6;
Mauro Carvalho Chehabecc31d52014-07-04 14:15:39 -03003517 if (show)
3518 dprintk("dib8000_get_frontend: Layer %d Code Rate = 5/6 ", i);
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003519 break;
3520 default:
3521 fe->dtv_property_cache.layer[i].fec = FEC_7_8;
Mauro Carvalho Chehabecc31d52014-07-04 14:15:39 -03003522 if (show)
3523 dprintk("dib8000_get_frontend: Layer %d Code Rate = 7/8 ", i);
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003524 break;
3525 }
3526
3527 val = dib8000_read_word(state, 487 + i);
3528 switch (val & 0x3) {
3529 case 0:
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003530 fe->dtv_property_cache.layer[i].modulation = DQPSK;
Mauro Carvalho Chehabecc31d52014-07-04 14:15:39 -03003531 if (show)
3532 dprintk("dib8000_get_frontend: Layer %d DQPSK ", i);
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003533 break;
3534 case 1:
3535 fe->dtv_property_cache.layer[i].modulation = QPSK;
Mauro Carvalho Chehabecc31d52014-07-04 14:15:39 -03003536 if (show)
3537 dprintk("dib8000_get_frontend: Layer %d QPSK ", i);
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003538 break;
3539 case 2:
3540 fe->dtv_property_cache.layer[i].modulation = QAM_16;
Mauro Carvalho Chehabecc31d52014-07-04 14:15:39 -03003541 if (show)
3542 dprintk("dib8000_get_frontend: Layer %d QAM16 ", i);
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003543 break;
3544 case 3:
3545 default:
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003546 fe->dtv_property_cache.layer[i].modulation = QAM_64;
Mauro Carvalho Chehabecc31d52014-07-04 14:15:39 -03003547 if (show)
3548 dprintk("dib8000_get_frontend: Layer %d QAM64 ", i);
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003549 break;
3550 }
3551 }
Olivier Grenie4c70e072011-01-03 15:33:37 -03003552
3553 /* synchronize the cache with the other frontends */
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03003554 for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
Olivier Grenie4c70e072011-01-03 15:33:37 -03003555 state->fe[index_frontend]->dtv_property_cache.isdbt_sb_mode = fe->dtv_property_cache.isdbt_sb_mode;
3556 state->fe[index_frontend]->dtv_property_cache.inversion = fe->dtv_property_cache.inversion;
3557 state->fe[index_frontend]->dtv_property_cache.transmission_mode = fe->dtv_property_cache.transmission_mode;
3558 state->fe[index_frontend]->dtv_property_cache.guard_interval = fe->dtv_property_cache.guard_interval;
3559 state->fe[index_frontend]->dtv_property_cache.isdbt_partial_reception = fe->dtv_property_cache.isdbt_partial_reception;
3560 for (i = 0; i < 3; i++) {
3561 state->fe[index_frontend]->dtv_property_cache.layer[i].segment_count = fe->dtv_property_cache.layer[i].segment_count;
3562 state->fe[index_frontend]->dtv_property_cache.layer[i].interleaving = fe->dtv_property_cache.layer[i].interleaving;
3563 state->fe[index_frontend]->dtv_property_cache.layer[i].fec = fe->dtv_property_cache.layer[i].fec;
3564 state->fe[index_frontend]->dtv_property_cache.layer[i].modulation = fe->dtv_property_cache.layer[i].modulation;
3565 }
3566 }
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003567 return 0;
3568}
3569
Mauro Carvalho Chehab490ecd62011-12-22 20:38:27 -03003570static int dib8000_set_frontend(struct dvb_frontend *fe)
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003571{
3572 struct dib8000_state *state = fe->demodulator_priv;
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03003573 struct dtv_frontend_properties *c = &state->fe[0]->dtv_property_cache;
Mauro Carvalho Chehabd6c62b72014-07-04 14:15:37 -03003574 int l, i, active, time, time_slave = 0;
Patrick Boettcher173a64c2013-04-22 12:45:52 -03003575 u8 exit_condition, index_frontend;
Mauro Carvalho Chehabd6c62b72014-07-04 14:15:37 -03003576 unsigned long delay, callback_time;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003577
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03003578 if (c->frequency == 0) {
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003579 dprintk("dib8000: must at least specify frequency ");
3580 return 0;
3581 }
3582
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03003583 if (c->bandwidth_hz == 0) {
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003584 dprintk("dib8000: no bandwidth specified, set to default ");
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03003585 c->bandwidth_hz = 6000000;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003586 }
3587
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03003588 for (index_frontend = 0; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
Olivier Grenie4c70e072011-01-03 15:33:37 -03003589 /* synchronization of the cache */
3590 state->fe[index_frontend]->dtv_property_cache.delivery_system = SYS_ISDBT;
3591 memcpy(&state->fe[index_frontend]->dtv_property_cache, &fe->dtv_property_cache, sizeof(struct dtv_frontend_properties));
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003592
Patrick Boettcher173a64c2013-04-22 12:45:52 -03003593 /* set output mode and diversity input */
3594 if (state->revision != 0x8090) {
3595 dib8000_set_diversity_in(state->fe[index_frontend], 1);
3596 if (index_frontend != 0)
3597 dib8000_set_output_mode(state->fe[index_frontend],
3598 OUTMODE_DIVERSITY);
3599 else
3600 dib8000_set_output_mode(state->fe[0], OUTMODE_HIGH_Z);
3601 } else {
3602 dib8096p_set_diversity_in(state->fe[index_frontend], 1);
3603 if (index_frontend != 0)
3604 dib8096p_set_output_mode(state->fe[index_frontend],
3605 OUTMODE_DIVERSITY);
3606 else
3607 dib8096p_set_output_mode(state->fe[0], OUTMODE_HIGH_Z);
3608 }
3609
3610 /* tune the tuner */
Olivier Grenie4c70e072011-01-03 15:33:37 -03003611 if (state->fe[index_frontend]->ops.tuner_ops.set_params)
Mauro Carvalho Chehab14d24d12011-12-24 12:24:33 -03003612 state->fe[index_frontend]->ops.tuner_ops.set_params(state->fe[index_frontend]);
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003613
Olivier Grenie4c70e072011-01-03 15:33:37 -03003614 dib8000_set_tune_state(state->fe[index_frontend], CT_AGC_START);
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003615 }
3616
Patrick Boettcher173a64c2013-04-22 12:45:52 -03003617 /* turn off the diversity of the last chip */
3618 if (state->revision != 0x8090)
3619 dib8000_set_diversity_in(state->fe[index_frontend - 1], 0);
3620 else
3621 dib8096p_set_diversity_in(state->fe[index_frontend - 1], 0);
3622
Olivier Grenie4c70e072011-01-03 15:33:37 -03003623 /* start up the AGC */
3624 do {
3625 time = dib8000_agc_startup(state->fe[0]);
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03003626 for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
Olivier Grenie4c70e072011-01-03 15:33:37 -03003627 time_slave = dib8000_agc_startup(state->fe[index_frontend]);
Mauro Carvalho Chehabd6c62b72014-07-04 14:15:37 -03003628 if (time == 0)
Olivier Grenie4c70e072011-01-03 15:33:37 -03003629 time = time_slave;
Mauro Carvalho Chehabd6c62b72014-07-04 14:15:37 -03003630 else if ((time_slave != 0) && (time_slave > time))
Olivier Grenie4c70e072011-01-03 15:33:37 -03003631 time = time_slave;
3632 }
Mauro Carvalho Chehabd6c62b72014-07-04 14:15:37 -03003633 if (time == 0)
Olivier Grenie4c70e072011-01-03 15:33:37 -03003634 break;
Mauro Carvalho Chehab4607bb72014-07-04 14:15:35 -03003635
3636 /*
3637 * Despite dib8000_agc_startup returns time at a 0.1 ms range,
3638 * the actual sleep time depends on CONFIG_HZ. The worse case
3639 * is when CONFIG_HZ=100. In such case, the minimum granularity
3640 * is 10ms. On some real field tests, the tuner sometimes don't
3641 * lock when this timer is lower than 10ms. So, enforce a 10ms
3642 * granularity.
3643 */
3644 time = 10 * (time + 99)/100;
3645 usleep_range(time * 1000, (time + 1) * 1000);
Olivier Grenie4c70e072011-01-03 15:33:37 -03003646 exit_condition = 1;
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03003647 for (index_frontend = 0; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
Olivier Grenie4c70e072011-01-03 15:33:37 -03003648 if (dib8000_get_tune_state(state->fe[index_frontend]) != CT_AGC_STOP) {
3649 exit_condition = 0;
3650 break;
3651 }
3652 }
3653 } while (exit_condition == 0);
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003654
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03003655 for (index_frontend = 0; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++)
Olivier Grenie4c70e072011-01-03 15:33:37 -03003656 dib8000_set_tune_state(state->fe[index_frontend], CT_DEMOD_START);
3657
Patrick Boettcher173a64c2013-04-22 12:45:52 -03003658 active = 1;
3659 do {
Mauro Carvalho Chehabd6c62b72014-07-04 14:15:37 -03003660 callback_time = 0;
Mauro Carvalho Chehab2c2c4412011-01-16 13:02:52 -02003661 for (index_frontend = 0; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
Patrick Boettcher173a64c2013-04-22 12:45:52 -03003662 delay = dib8000_tune(state->fe[index_frontend]);
Mauro Carvalho Chehabd6c62b72014-07-04 14:15:37 -03003663 if (delay != 0) {
3664 delay = jiffies + usecs_to_jiffies(100 * delay);
3665 if (!callback_time || delay < callback_time)
3666 callback_time = delay;
3667 }
Olivier Grenie4c70e072011-01-03 15:33:37 -03003668
Patrick Boettcher173a64c2013-04-22 12:45:52 -03003669 /* we are in autosearch */
3670 if (state->channel_parameters_set == 0) { /* searching */
3671 if ((dib8000_get_status(state->fe[index_frontend]) == FE_STATUS_DEMOD_SUCCESS) || (dib8000_get_status(state->fe[index_frontend]) == FE_STATUS_FFT_SUCCESS)) {
3672 dprintk("autosearch succeeded on fe%i", index_frontend);
3673 dib8000_get_frontend(state->fe[index_frontend]); /* we read the channel parameters from the frontend which was successful */
3674 state->channel_parameters_set = 1;
3675
3676 for (l = 0; (l < MAX_NUMBER_OF_FRONTENDS) && (state->fe[l] != NULL); l++) {
3677 if (l != index_frontend) { /* and for all frontend except the successful one */
Mauro Carvalho Chehabecc31d52014-07-04 14:15:39 -03003678 dprintk("Restarting frontend %d\n", l);
Patrick Boettcher173a64c2013-04-22 12:45:52 -03003679 dib8000_tune_restart_from_demod(state->fe[l]);
3680
3681 state->fe[l]->dtv_property_cache.isdbt_sb_mode = state->fe[index_frontend]->dtv_property_cache.isdbt_sb_mode;
3682 state->fe[l]->dtv_property_cache.inversion = state->fe[index_frontend]->dtv_property_cache.inversion;
3683 state->fe[l]->dtv_property_cache.transmission_mode = state->fe[index_frontend]->dtv_property_cache.transmission_mode;
3684 state->fe[l]->dtv_property_cache.guard_interval = state->fe[index_frontend]->dtv_property_cache.guard_interval;
3685 state->fe[l]->dtv_property_cache.isdbt_partial_reception = state->fe[index_frontend]->dtv_property_cache.isdbt_partial_reception;
3686 for (i = 0; i < 3; i++) {
3687 state->fe[l]->dtv_property_cache.layer[i].segment_count = state->fe[index_frontend]->dtv_property_cache.layer[i].segment_count;
3688 state->fe[l]->dtv_property_cache.layer[i].interleaving = state->fe[index_frontend]->dtv_property_cache.layer[i].interleaving;
3689 state->fe[l]->dtv_property_cache.layer[i].fec = state->fe[index_frontend]->dtv_property_cache.layer[i].fec;
3690 state->fe[l]->dtv_property_cache.layer[i].modulation = state->fe[index_frontend]->dtv_property_cache.layer[i].modulation;
3691 }
3692
3693 }
Mauro Carvalho Chehab2c2c4412011-01-16 13:02:52 -02003694 }
3695 }
3696 }
Patrick Boettcher173a64c2013-04-22 12:45:52 -03003697 }
3698 /* tuning is done when the master frontend is done (failed or success) */
3699 if (dib8000_get_status(state->fe[0]) == FE_STATUS_TUNE_FAILED ||
3700 dib8000_get_status(state->fe[0]) == FE_STATUS_LOCKED ||
3701 dib8000_get_status(state->fe[0]) == FE_STATUS_DATA_LOCKED) {
3702 active = 0;
3703 /* we need to wait for all frontends to be finished */
3704 for (index_frontend = 0; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
3705 if (dib8000_get_tune_state(state->fe[index_frontend]) != CT_DEMOD_STOP)
3706 active = 1;
3707 }
3708 if (active == 0)
3709 dprintk("tuning done with status %d", dib8000_get_status(state->fe[0]));
Mauro Carvalho Chehab2c2c4412011-01-16 13:02:52 -02003710 }
Olivier Grenie4c70e072011-01-03 15:33:37 -03003711
Mauro Carvalho Chehabd6c62b72014-07-04 14:15:37 -03003712 if ((active == 1) && (callback_time == 0)) {
Patrick Boettcher173a64c2013-04-22 12:45:52 -03003713 dprintk("strange callback time something went wrong");
3714 active = 0;
3715 }
Olivier Grenie4c70e072011-01-03 15:33:37 -03003716
Mauro Carvalho Chehabd6c62b72014-07-04 14:15:37 -03003717 while ((active == 1) && (time_before(jiffies, callback_time)))
Patrick Boettcher173a64c2013-04-22 12:45:52 -03003718 msleep(100);
3719 } while (active);
Olivier Grenie4c70e072011-01-03 15:33:37 -03003720
Patrick Boettcher173a64c2013-04-22 12:45:52 -03003721 /* set output mode */
3722 if (state->revision != 0x8090)
Olivier Grenie0c32dbd2011-08-10 05:17:18 -03003723 dib8000_set_output_mode(state->fe[0], state->cfg.output_mode);
Patrick Boettcher173a64c2013-04-22 12:45:52 -03003724 else {
Olivier Grenie0c32dbd2011-08-10 05:17:18 -03003725 dib8096p_set_output_mode(state->fe[0], state->cfg.output_mode);
3726 if (state->cfg.enMpegOutput == 0) {
3727 dib8096p_setDibTxMux(state, MPEG_ON_DIBTX);
3728 dib8096p_setHostBusMux(state, DIBTX_ON_HOSTBUS);
3729 }
Olivier Grenie0c32dbd2011-08-10 05:17:18 -03003730 }
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003731
Geert Uytterhoeven4d8d5d92013-06-02 13:52:17 -03003732 return 0;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003733}
3734
Mauro Carvalho Chehab6ef06e72013-12-16 19:10:59 -03003735static int dib8000_get_stats(struct dvb_frontend *fe, fe_status_t stat);
3736
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003737static int dib8000_read_status(struct dvb_frontend *fe, fe_status_t * stat)
3738{
3739 struct dib8000_state *state = fe->demodulator_priv;
Olivier Grenie0c32dbd2011-08-10 05:17:18 -03003740 u16 lock_slave = 0, lock;
Olivier Grenie4c70e072011-01-03 15:33:37 -03003741 u8 index_frontend;
3742
Patrick Boettcher173a64c2013-04-22 12:45:52 -03003743 lock = dib8000_read_lock(fe);
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03003744 for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++)
Olivier Grenie4c70e072011-01-03 15:33:37 -03003745 lock_slave |= dib8000_read_lock(state->fe[index_frontend]);
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003746
3747 *stat = 0;
3748
Olivier Grenie4c70e072011-01-03 15:33:37 -03003749 if (((lock >> 13) & 1) || ((lock_slave >> 13) & 1))
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003750 *stat |= FE_HAS_SIGNAL;
3751
Olivier Grenie4c70e072011-01-03 15:33:37 -03003752 if (((lock >> 8) & 1) || ((lock_slave >> 8) & 1)) /* Equal */
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003753 *stat |= FE_HAS_CARRIER;
3754
Olivier Grenie4c70e072011-01-03 15:33:37 -03003755 if ((((lock >> 1) & 0xf) == 0xf) || (((lock_slave >> 1) & 0xf) == 0xf)) /* TMCC_SYNC */
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003756 *stat |= FE_HAS_SYNC;
3757
Olivier Grenie4c70e072011-01-03 15:33:37 -03003758 if ((((lock >> 12) & 1) || ((lock_slave >> 12) & 1)) && ((lock >> 5) & 7)) /* FEC MPEG */
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003759 *stat |= FE_HAS_LOCK;
3760
Olivier Grenie4c70e072011-01-03 15:33:37 -03003761 if (((lock >> 12) & 1) || ((lock_slave >> 12) & 1)) {
Olivier Grenie89dfc552009-11-30 06:38:49 -03003762 lock = dib8000_read_word(state, 554); /* Viterbi Layer A */
3763 if (lock & 0x01)
3764 *stat |= FE_HAS_VITERBI;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003765
Olivier Grenie89dfc552009-11-30 06:38:49 -03003766 lock = dib8000_read_word(state, 555); /* Viterbi Layer B */
3767 if (lock & 0x01)
3768 *stat |= FE_HAS_VITERBI;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003769
Olivier Grenie89dfc552009-11-30 06:38:49 -03003770 lock = dib8000_read_word(state, 556); /* Viterbi Layer C */
3771 if (lock & 0x01)
3772 *stat |= FE_HAS_VITERBI;
3773 }
Mauro Carvalho Chehab6ef06e72013-12-16 19:10:59 -03003774 dib8000_get_stats(fe, *stat);
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003775
3776 return 0;
3777}
3778
3779static int dib8000_read_ber(struct dvb_frontend *fe, u32 * ber)
3780{
3781 struct dib8000_state *state = fe->demodulator_priv;
Olivier Grenie0c32dbd2011-08-10 05:17:18 -03003782
3783 /* 13 segments */
3784 if (state->revision == 0x8090)
3785 *ber = (dib8000_read_word(state, 562) << 16) |
3786 dib8000_read_word(state, 563);
3787 else
3788 *ber = (dib8000_read_word(state, 560) << 16) |
3789 dib8000_read_word(state, 561);
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003790 return 0;
3791}
3792
3793static int dib8000_read_unc_blocks(struct dvb_frontend *fe, u32 * unc)
3794{
3795 struct dib8000_state *state = fe->demodulator_priv;
Olivier Grenie0c32dbd2011-08-10 05:17:18 -03003796
3797 /* packet error on 13 seg */
3798 if (state->revision == 0x8090)
3799 *unc = dib8000_read_word(state, 567);
3800 else
3801 *unc = dib8000_read_word(state, 565);
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003802 return 0;
3803}
3804
3805static int dib8000_read_signal_strength(struct dvb_frontend *fe, u16 * strength)
3806{
3807 struct dib8000_state *state = fe->demodulator_priv;
Olivier Grenie4c70e072011-01-03 15:33:37 -03003808 u8 index_frontend;
3809 u16 val;
3810
3811 *strength = 0;
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03003812 for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
Olivier Grenie4c70e072011-01-03 15:33:37 -03003813 state->fe[index_frontend]->ops.read_signal_strength(state->fe[index_frontend], &val);
3814 if (val > 65535 - *strength)
3815 *strength = 65535;
3816 else
3817 *strength += val;
3818 }
3819
3820 val = 65535 - dib8000_read_word(state, 390);
3821 if (val > 65535 - *strength)
3822 *strength = 65535;
3823 else
3824 *strength += val;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003825 return 0;
3826}
3827
Olivier Grenie4c70e072011-01-03 15:33:37 -03003828static u32 dib8000_get_snr(struct dvb_frontend *fe)
3829{
3830 struct dib8000_state *state = fe->demodulator_priv;
3831 u32 n, s, exp;
3832 u16 val;
3833
Olivier Grenie0c32dbd2011-08-10 05:17:18 -03003834 if (state->revision != 0x8090)
3835 val = dib8000_read_word(state, 542);
3836 else
3837 val = dib8000_read_word(state, 544);
Olivier Grenie4c70e072011-01-03 15:33:37 -03003838 n = (val >> 6) & 0xff;
3839 exp = (val & 0x3f);
3840 if ((exp & 0x20) != 0)
3841 exp -= 0x40;
3842 n <<= exp+16;
3843
Olivier Grenie0c32dbd2011-08-10 05:17:18 -03003844 if (state->revision != 0x8090)
3845 val = dib8000_read_word(state, 543);
3846 else
3847 val = dib8000_read_word(state, 545);
Olivier Grenie4c70e072011-01-03 15:33:37 -03003848 s = (val >> 6) & 0xff;
3849 exp = (val & 0x3f);
3850 if ((exp & 0x20) != 0)
3851 exp -= 0x40;
3852 s <<= exp+16;
3853
3854 if (n > 0) {
3855 u32 t = (s/n) << 16;
3856 return t + ((s << 16) - n*t) / n;
3857 }
3858 return 0xffffffff;
3859}
3860
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003861static int dib8000_read_snr(struct dvb_frontend *fe, u16 * snr)
3862{
3863 struct dib8000_state *state = fe->demodulator_priv;
Olivier Grenie4c70e072011-01-03 15:33:37 -03003864 u8 index_frontend;
3865 u32 snr_master;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003866
Olivier Grenie4c70e072011-01-03 15:33:37 -03003867 snr_master = dib8000_get_snr(fe);
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03003868 for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++)
Olivier Grenie4c70e072011-01-03 15:33:37 -03003869 snr_master += dib8000_get_snr(state->fe[index_frontend]);
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003870
Olivier Grenie1f6bfcc2011-07-04 12:33:54 -03003871 if ((snr_master >> 16) != 0) {
Olivier Grenie4c70e072011-01-03 15:33:37 -03003872 snr_master = 10*intlog10(snr_master>>16);
3873 *snr = snr_master / ((1 << 24) / 10);
3874 }
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003875 else
Olivier Grenie4c70e072011-01-03 15:33:37 -03003876 *snr = 0;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003877
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003878 return 0;
3879}
3880
Mauro Carvalho Chehab6ef06e72013-12-16 19:10:59 -03003881struct per_layer_regs {
3882 u16 lock, ber, per;
3883};
3884
3885static const struct per_layer_regs per_layer_regs[] = {
3886 { 554, 560, 562 },
3887 { 555, 576, 578 },
3888 { 556, 581, 583 },
3889};
3890
Mauro Carvalho Chehab42ff76b2013-12-16 21:45:19 -03003891struct linear_segments {
3892 unsigned x;
3893 signed y;
3894};
3895
3896/*
3897 * Table to estimate signal strength in dBm.
3898 * This table was empirically determinated by measuring the signal
3899 * strength generated by a DTA-2111 RF generator directly connected into
3900 * a dib8076 device (a PixelView PV-D231U stick), using a good quality
3901 * 3 meters RC6 cable and good RC6 connectors.
3902 * The real value can actually be different on other devices, depending
3903 * on several factors, like if LNA is enabled or not, if diversity is
3904 * enabled, type of connectors, etc.
3905 * Yet, it is better to use this measure in dB than a random non-linear
3906 * percentage value, especially for antenna adjustments.
3907 * On my tests, the precision of the measure using this table is about
3908 * 0.5 dB, with sounds reasonable enough.
3909 */
3910static struct linear_segments strength_to_db_table[] = {
3911 { 55953, 108500 }, /* -22.5 dBm */
3912 { 55394, 108000 },
3913 { 53834, 107000 },
3914 { 52863, 106000 },
3915 { 52239, 105000 },
3916 { 52012, 104000 },
3917 { 51803, 103000 },
3918 { 51566, 102000 },
3919 { 51356, 101000 },
3920 { 51112, 100000 },
3921 { 50869, 99000 },
3922 { 50600, 98000 },
3923 { 50363, 97000 },
3924 { 50117, 96000 }, /* -35 dBm */
3925 { 49889, 95000 },
3926 { 49680, 94000 },
3927 { 49493, 93000 },
3928 { 49302, 92000 },
3929 { 48929, 91000 },
3930 { 48416, 90000 },
3931 { 48035, 89000 },
3932 { 47593, 88000 },
3933 { 47282, 87000 },
3934 { 46953, 86000 },
3935 { 46698, 85000 },
3936 { 45617, 84000 },
3937 { 44773, 83000 },
3938 { 43845, 82000 },
3939 { 43020, 81000 },
3940 { 42010, 80000 }, /* -51 dBm */
3941 { 0, 0 },
3942};
3943
3944static u32 interpolate_value(u32 value, struct linear_segments *segments,
3945 unsigned len)
3946{
3947 u64 tmp64;
3948 u32 dx;
3949 s32 dy;
3950 int i, ret;
3951
3952 if (value >= segments[0].x)
3953 return segments[0].y;
3954 if (value < segments[len-1].x)
3955 return segments[len-1].y;
3956
3957 for (i = 1; i < len - 1; i++) {
3958 /* If value is identical, no need to interpolate */
3959 if (value == segments[i].x)
3960 return segments[i].y;
3961 if (value > segments[i].x)
3962 break;
3963 }
3964
3965 /* Linear interpolation between the two (x,y) points */
3966 dy = segments[i - 1].y - segments[i].y;
3967 dx = segments[i - 1].x - segments[i].x;
3968
3969 tmp64 = value - segments[i].x;
3970 tmp64 *= dy;
3971 do_div(tmp64, dx);
3972 ret = segments[i].y + tmp64;
3973
3974 return ret;
3975}
3976
Mauro Carvalho Chehab704f01b2013-12-17 10:08:20 -03003977static u32 dib8000_get_time_us(struct dvb_frontend *fe, int layer)
3978{
3979 struct dib8000_state *state = fe->demodulator_priv;
3980 struct dtv_frontend_properties *c = &state->fe[0]->dtv_property_cache;
3981 int ini_layer, end_layer, i;
Mauro Carvalho Chehab4bf48152013-12-20 08:11:31 -02003982 u64 time_us, tmp64;
Mauro Carvalho Chehab704f01b2013-12-17 10:08:20 -03003983 u32 tmp, denom;
Mauro Carvalho Chehabe4a3bc12014-01-13 15:14:33 -02003984 int guard, rate_num, rate_denum = 1, bits_per_symbol, nsegs;
3985 int interleaving = 0, fft_div;
Mauro Carvalho Chehab704f01b2013-12-17 10:08:20 -03003986
3987 if (layer >= 0) {
3988 ini_layer = layer;
3989 end_layer = layer + 1;
3990 } else {
3991 ini_layer = 0;
3992 end_layer = 3;
3993 }
3994
3995 switch (c->guard_interval) {
3996 case GUARD_INTERVAL_1_4:
3997 guard = 4;
3998 break;
3999 case GUARD_INTERVAL_1_8:
4000 guard = 8;
4001 break;
4002 case GUARD_INTERVAL_1_16:
4003 guard = 16;
4004 break;
4005 default:
4006 case GUARD_INTERVAL_1_32:
4007 guard = 32;
4008 break;
4009 }
4010
4011 switch (c->transmission_mode) {
4012 case TRANSMISSION_MODE_2K:
4013 fft_div = 4;
4014 break;
4015 case TRANSMISSION_MODE_4K:
4016 fft_div = 2;
4017 break;
4018 default:
4019 case TRANSMISSION_MODE_8K:
4020 fft_div = 1;
4021 break;
4022 }
4023
4024 denom = 0;
4025 for (i = ini_layer; i < end_layer; i++) {
4026 nsegs = c->layer[i].segment_count;
4027 if (nsegs == 0 || nsegs > 13)
4028 continue;
4029
4030 switch (c->layer[i].modulation) {
4031 case DQPSK:
4032 case QPSK:
4033 bits_per_symbol = 2;
4034 break;
4035 case QAM_16:
4036 bits_per_symbol = 4;
4037 break;
4038 default:
4039 case QAM_64:
4040 bits_per_symbol = 6;
4041 break;
4042 }
4043
4044 switch (c->layer[i].fec) {
4045 case FEC_1_2:
4046 rate_num = 1;
4047 rate_denum = 2;
4048 break;
4049 case FEC_2_3:
4050 rate_num = 2;
4051 rate_denum = 3;
4052 break;
4053 case FEC_3_4:
4054 rate_num = 3;
4055 rate_denum = 4;
4056 break;
4057 case FEC_5_6:
4058 rate_num = 5;
4059 rate_denum = 6;
4060 break;
4061 default:
4062 case FEC_7_8:
4063 rate_num = 7;
4064 rate_denum = 8;
4065 break;
4066 }
4067
4068 interleaving = c->layer[i].interleaving;
4069
4070 denom += bits_per_symbol * rate_num * fft_div * nsegs * 384;
4071 }
4072
4073 /* If all goes wrong, wait for 1s for the next stats */
4074 if (!denom)
4075 return 0;
4076
4077 /* Estimate the period for the total bit rate */
4078 time_us = rate_denum * (1008 * 1562500L);
Mauro Carvalho Chehab4bf48152013-12-20 08:11:31 -02004079 tmp64 = time_us;
4080 do_div(tmp64, guard);
4081 time_us = time_us + tmp64;
Mauro Carvalho Chehab704f01b2013-12-17 10:08:20 -03004082 time_us += denom / 2;
4083 do_div(time_us, denom);
4084
4085 tmp = 1008 * 96 * interleaving;
4086 time_us += tmp + tmp / guard;
4087
4088 return time_us;
4089}
4090
Mauro Carvalho Chehab6ef06e72013-12-16 19:10:59 -03004091static int dib8000_get_stats(struct dvb_frontend *fe, fe_status_t stat)
4092{
4093 struct dib8000_state *state = fe->demodulator_priv;
4094 struct dtv_frontend_properties *c = &state->fe[0]->dtv_property_cache;
Mauro Carvalho Chehab704f01b2013-12-17 10:08:20 -03004095 int i;
Mauro Carvalho Chehab0400c532013-12-17 11:34:22 -03004096 int show_per_stats = 0;
4097 u32 time_us = 0, snr, val;
4098 u64 blocks;
Mauro Carvalho Chehab42ff76b2013-12-16 21:45:19 -03004099 s32 db;
Mauro Carvalho Chehab6ef06e72013-12-16 19:10:59 -03004100 u16 strength;
4101
4102 /* Get Signal strength */
4103 dib8000_read_signal_strength(fe, &strength);
Mauro Carvalho Chehab42ff76b2013-12-16 21:45:19 -03004104 val = strength;
4105 db = interpolate_value(val,
4106 strength_to_db_table,
4107 ARRAY_SIZE(strength_to_db_table)) - 131000;
4108 c->strength.stat[0].svalue = db;
Mauro Carvalho Chehab6ef06e72013-12-16 19:10:59 -03004109
Mauro Carvalho Chehab704f01b2013-12-17 10:08:20 -03004110 /* UCB/BER/CNR measures require lock */
Mauro Carvalho Chehab6ef06e72013-12-16 19:10:59 -03004111 if (!(stat & FE_HAS_LOCK)) {
Mauro Carvalho Chehab704f01b2013-12-17 10:08:20 -03004112 c->cnr.len = 1;
Mauro Carvalho Chehab0400c532013-12-17 11:34:22 -03004113 c->block_count.len = 1;
Mauro Carvalho Chehab6ef06e72013-12-16 19:10:59 -03004114 c->block_error.len = 1;
4115 c->post_bit_error.len = 1;
4116 c->post_bit_count.len = 1;
Mauro Carvalho Chehab704f01b2013-12-17 10:08:20 -03004117 c->cnr.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
Mauro Carvalho Chehab6ef06e72013-12-16 19:10:59 -03004118 c->post_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
4119 c->post_bit_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
4120 c->block_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
Mauro Carvalho Chehab0400c532013-12-17 11:34:22 -03004121 c->block_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
Mauro Carvalho Chehab6ef06e72013-12-16 19:10:59 -03004122 return 0;
4123 }
4124
Mauro Carvalho Chehab704f01b2013-12-17 10:08:20 -03004125 /* Check if time for stats was elapsed */
Mauro Carvalho Chehab0400c532013-12-17 11:34:22 -03004126 if (time_after(jiffies, state->per_jiffies_stats)) {
4127 state->per_jiffies_stats = jiffies + msecs_to_jiffies(1000);
Mauro Carvalho Chehab6ef06e72013-12-16 19:10:59 -03004128
Mauro Carvalho Chehab704f01b2013-12-17 10:08:20 -03004129 /* Get SNR */
4130 snr = dib8000_get_snr(fe);
4131 for (i = 1; i < MAX_NUMBER_OF_FRONTENDS; i++) {
4132 if (state->fe[i])
4133 snr += dib8000_get_snr(state->fe[i]);
4134 }
4135 snr = snr >> 16;
Mauro Carvalho Chehab6ef06e72013-12-16 19:10:59 -03004136
Mauro Carvalho Chehab704f01b2013-12-17 10:08:20 -03004137 if (snr) {
4138 snr = 10 * intlog10(snr);
4139 snr = (1000L * snr) >> 24;
4140 } else {
4141 snr = 0;
4142 }
4143 c->cnr.stat[0].svalue = snr;
4144 c->cnr.stat[0].scale = FE_SCALE_DECIBEL;
Mauro Carvalho Chehab6ef06e72013-12-16 19:10:59 -03004145
Mauro Carvalho Chehab0400c532013-12-17 11:34:22 -03004146 /* Get UCB measures */
4147 dib8000_read_unc_blocks(fe, &val);
4148 if (val < state->init_ucb)
Mauro Carvalho Chehab5dc85262014-01-13 15:05:44 -02004149 state->init_ucb += 0x100000000LL;
Mauro Carvalho Chehab0400c532013-12-17 11:34:22 -03004150
4151 c->block_error.stat[0].scale = FE_SCALE_COUNTER;
4152 c->block_error.stat[0].uvalue = val + state->init_ucb;
4153
4154 /* Estimate the number of packets based on bitrate */
4155 if (!time_us)
4156 time_us = dib8000_get_time_us(fe, -1);
4157
4158 if (time_us) {
Mauro Carvalho Chehab5dc85262014-01-13 15:05:44 -02004159 blocks = 1250000ULL * 1000000ULL;
Mauro Carvalho Chehab0400c532013-12-17 11:34:22 -03004160 do_div(blocks, time_us * 8 * 204);
4161 c->block_count.stat[0].scale = FE_SCALE_COUNTER;
4162 c->block_count.stat[0].uvalue += blocks;
4163 }
4164
4165 show_per_stats = 1;
4166 }
4167
4168 /* Get post-BER measures */
4169 if (time_after(jiffies, state->ber_jiffies_stats)) {
4170 time_us = dib8000_get_time_us(fe, -1);
4171 state->ber_jiffies_stats = jiffies + msecs_to_jiffies((time_us + 500) / 1000);
4172
4173 dprintk("Next all layers stats available in %u us.", time_us);
Mauro Carvalho Chehab704f01b2013-12-17 10:08:20 -03004174
4175 dib8000_read_ber(fe, &val);
4176 c->post_bit_error.stat[0].scale = FE_SCALE_COUNTER;
4177 c->post_bit_error.stat[0].uvalue += val;
4178
4179 c->post_bit_count.stat[0].scale = FE_SCALE_COUNTER;
4180 c->post_bit_count.stat[0].uvalue += 100000000;
Mauro Carvalho Chehab704f01b2013-12-17 10:08:20 -03004181 }
Mauro Carvalho Chehab6ef06e72013-12-16 19:10:59 -03004182
4183 if (state->revision < 0x8002)
4184 return 0;
4185
4186 c->block_error.len = 4;
4187 c->post_bit_error.len = 4;
4188 c->post_bit_count.len = 4;
4189
4190 for (i = 0; i < 3; i++) {
Mauro Carvalho Chehab0400c532013-12-17 11:34:22 -03004191 unsigned nsegs = c->layer[i].segment_count;
4192
4193 if (nsegs == 0 || nsegs > 13)
Mauro Carvalho Chehab704f01b2013-12-17 10:08:20 -03004194 continue;
Mauro Carvalho Chehab6ef06e72013-12-16 19:10:59 -03004195
Mauro Carvalho Chehab0400c532013-12-17 11:34:22 -03004196 time_us = 0;
Mauro Carvalho Chehab6ef06e72013-12-16 19:10:59 -03004197
Mauro Carvalho Chehab0400c532013-12-17 11:34:22 -03004198 if (time_after(jiffies, state->ber_jiffies_stats_layer[i])) {
4199 time_us = dib8000_get_time_us(fe, i);
Mauro Carvalho Chehab6ef06e72013-12-16 19:10:59 -03004200
Mauro Carvalho Chehab0400c532013-12-17 11:34:22 -03004201 state->ber_jiffies_stats_layer[i] = jiffies + msecs_to_jiffies((time_us + 500) / 1000);
4202 dprintk("Next layer %c stats will be available in %u us\n",
4203 'A' + i, time_us);
Mauro Carvalho Chehab704f01b2013-12-17 10:08:20 -03004204
Mauro Carvalho Chehab0400c532013-12-17 11:34:22 -03004205 val = dib8000_read_word(state, per_layer_regs[i].ber);
4206 c->post_bit_error.stat[1 + i].scale = FE_SCALE_COUNTER;
4207 c->post_bit_error.stat[1 + i].uvalue += val;
Mauro Carvalho Chehab704f01b2013-12-17 10:08:20 -03004208
Mauro Carvalho Chehab0400c532013-12-17 11:34:22 -03004209 c->post_bit_count.stat[1 + i].scale = FE_SCALE_COUNTER;
4210 c->post_bit_count.stat[1 + i].uvalue += 100000000;
4211 }
4212
4213 if (show_per_stats) {
4214 val = dib8000_read_word(state, per_layer_regs[i].per);
4215
4216 c->block_error.stat[1 + i].scale = FE_SCALE_COUNTER;
4217 c->block_error.stat[1 + i].uvalue += val;
4218
4219 if (!time_us)
4220 time_us = dib8000_get_time_us(fe, i);
4221 if (time_us) {
Mauro Carvalho Chehab5dc85262014-01-13 15:05:44 -02004222 blocks = 1250000ULL * 1000000ULL;
Mauro Carvalho Chehab0400c532013-12-17 11:34:22 -03004223 do_div(blocks, time_us * 8 * 204);
4224 c->block_count.stat[0].scale = FE_SCALE_COUNTER;
4225 c->block_count.stat[0].uvalue += blocks;
4226 }
4227 }
Mauro Carvalho Chehab6ef06e72013-12-16 19:10:59 -03004228 }
4229 return 0;
4230}
4231
Mauro Carvalho Chehabd44913c2014-05-29 09:20:17 -03004232static int dib8000_set_slave_frontend(struct dvb_frontend *fe, struct dvb_frontend *fe_slave)
Olivier Grenie4c70e072011-01-03 15:33:37 -03004233{
4234 struct dib8000_state *state = fe->demodulator_priv;
4235 u8 index_frontend = 1;
4236
4237 while ((index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL))
4238 index_frontend++;
4239 if (index_frontend < MAX_NUMBER_OF_FRONTENDS) {
4240 dprintk("set slave fe %p to index %i", fe_slave, index_frontend);
4241 state->fe[index_frontend] = fe_slave;
4242 return 0;
4243 }
4244
4245 dprintk("too many slave frontend");
4246 return -ENOMEM;
4247}
Olivier Grenie4c70e072011-01-03 15:33:37 -03004248
Mauro Carvalho Chehabd44913c2014-05-29 09:20:17 -03004249static int dib8000_remove_slave_frontend(struct dvb_frontend *fe)
Olivier Grenie4c70e072011-01-03 15:33:37 -03004250{
4251 struct dib8000_state *state = fe->demodulator_priv;
4252 u8 index_frontend = 1;
4253
4254 while ((index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL))
4255 index_frontend++;
4256 if (index_frontend != 1) {
4257 dprintk("remove slave fe %p (index %i)", state->fe[index_frontend-1], index_frontend-1);
4258 state->fe[index_frontend] = NULL;
4259 return 0;
4260 }
4261
4262 dprintk("no frontend to be removed");
4263 return -ENODEV;
4264}
Olivier Grenie4c70e072011-01-03 15:33:37 -03004265
Mauro Carvalho Chehabd44913c2014-05-29 09:20:17 -03004266static struct dvb_frontend *dib8000_get_slave_frontend(struct dvb_frontend *fe, int slave_index)
Olivier Grenie4c70e072011-01-03 15:33:37 -03004267{
4268 struct dib8000_state *state = fe->demodulator_priv;
4269
4270 if (slave_index >= MAX_NUMBER_OF_FRONTENDS)
4271 return NULL;
4272 return state->fe[slave_index];
4273}
Olivier Grenie4c70e072011-01-03 15:33:37 -03004274
Mauro Carvalho Chehabd44913c2014-05-29 09:20:17 -03004275static int dib8000_i2c_enumeration(struct i2c_adapter *host, int no_of_demods,
Olivier Grenie0c32dbd2011-08-10 05:17:18 -03004276 u8 default_addr, u8 first_addr, u8 is_dib8096p)
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03004277{
Olivier Grenie5a0deee2011-05-03 12:27:33 -03004278 int k = 0, ret = 0;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03004279 u8 new_addr = 0;
4280 struct i2c_device client = {.adap = host };
4281
Olivier Grenie5a0deee2011-05-03 12:27:33 -03004282 client.i2c_write_buffer = kzalloc(4 * sizeof(u8), GFP_KERNEL);
4283 if (!client.i2c_write_buffer) {
4284 dprintk("%s: not enough memory", __func__);
4285 return -ENOMEM;
4286 }
4287 client.i2c_read_buffer = kzalloc(4 * sizeof(u8), GFP_KERNEL);
4288 if (!client.i2c_read_buffer) {
4289 dprintk("%s: not enough memory", __func__);
4290 ret = -ENOMEM;
Patrick Boettcher79fcce32011-08-03 12:08:21 -03004291 goto error_memory_read;
Olivier Grenie5a0deee2011-05-03 12:27:33 -03004292 }
Patrick Boettcher79fcce32011-08-03 12:08:21 -03004293 client.i2c_buffer_lock = kzalloc(sizeof(struct mutex), GFP_KERNEL);
4294 if (!client.i2c_buffer_lock) {
4295 dprintk("%s: not enough memory", __func__);
4296 ret = -ENOMEM;
4297 goto error_memory_lock;
4298 }
4299 mutex_init(client.i2c_buffer_lock);
Olivier Grenie5a0deee2011-05-03 12:27:33 -03004300
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03004301 for (k = no_of_demods - 1; k >= 0; k--) {
4302 /* designated i2c address */
4303 new_addr = first_addr + (k << 1);
4304
4305 client.addr = new_addr;
Olivier Grenie0c32dbd2011-08-10 05:17:18 -03004306 if (!is_dib8096p)
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03004307 dib8000_i2c_write16(&client, 1287, 0x0003); /* sram lead in, rdy */
Olivier Grenie0c32dbd2011-08-10 05:17:18 -03004308 if (dib8000_identify(&client) == 0) {
4309 /* sram lead in, rdy */
4310 if (!is_dib8096p)
4311 dib8000_i2c_write16(&client, 1287, 0x0003);
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03004312 client.addr = default_addr;
4313 if (dib8000_identify(&client) == 0) {
4314 dprintk("#%d: not identified", k);
Olivier Grenie5a0deee2011-05-03 12:27:33 -03004315 ret = -EINVAL;
4316 goto error;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03004317 }
4318 }
4319
4320 /* start diversity to pull_down div_str - just for i2c-enumeration */
4321 dib8000_i2c_write16(&client, 1286, (1 << 10) | (4 << 6));
4322
4323 /* set new i2c address and force divstart */
4324 dib8000_i2c_write16(&client, 1285, (new_addr << 2) | 0x2);
4325 client.addr = new_addr;
4326 dib8000_identify(&client);
4327
4328 dprintk("IC %d initialized (to i2c_address 0x%x)", k, new_addr);
4329 }
4330
4331 for (k = 0; k < no_of_demods; k++) {
4332 new_addr = first_addr | (k << 1);
4333 client.addr = new_addr;
4334
4335 // unforce divstr
4336 dib8000_i2c_write16(&client, 1285, new_addr << 2);
4337
4338 /* deactivate div - it was just for i2c-enumeration */
4339 dib8000_i2c_write16(&client, 1286, 0);
4340 }
4341
Olivier Grenie5a0deee2011-05-03 12:27:33 -03004342error:
Patrick Boettcher79fcce32011-08-03 12:08:21 -03004343 kfree(client.i2c_buffer_lock);
4344error_memory_lock:
Olivier Grenie5a0deee2011-05-03 12:27:33 -03004345 kfree(client.i2c_read_buffer);
Patrick Boettcher79fcce32011-08-03 12:08:21 -03004346error_memory_read:
Olivier Grenie5a0deee2011-05-03 12:27:33 -03004347 kfree(client.i2c_write_buffer);
4348
4349 return ret;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03004350}
4351
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03004352static int dib8000_fe_get_tune_settings(struct dvb_frontend *fe, struct dvb_frontend_tune_settings *tune)
4353{
4354 tune->min_delay_ms = 1000;
4355 tune->step_size = 0;
4356 tune->max_drift = 0;
4357 return 0;
4358}
4359
4360static void dib8000_release(struct dvb_frontend *fe)
4361{
4362 struct dib8000_state *st = fe->demodulator_priv;
Olivier Grenie4c70e072011-01-03 15:33:37 -03004363 u8 index_frontend;
4364
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03004365 for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (st->fe[index_frontend] != NULL); index_frontend++)
Olivier Grenie4c70e072011-01-03 15:33:37 -03004366 dvb_frontend_detach(st->fe[index_frontend]);
4367
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03004368 dibx000_exit_i2c_master(&st->i2c_master);
Olivier Grenie0c32dbd2011-08-10 05:17:18 -03004369 i2c_del_adapter(&st->dib8096p_tuner_adap);
Olivier Grenie4c70e072011-01-03 15:33:37 -03004370 kfree(st->fe[0]);
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03004371 kfree(st);
4372}
4373
Mauro Carvalho Chehabd44913c2014-05-29 09:20:17 -03004374static 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 -03004375{
4376 struct dib8000_state *st = fe->demodulator_priv;
4377 return dibx000_get_i2c_adapter(&st->i2c_master, intf, gating);
4378}
4379
Mauro Carvalho Chehabd44913c2014-05-29 09:20:17 -03004380static int dib8000_pid_filter_ctrl(struct dvb_frontend *fe, u8 onoff)
Olivier Grenief8731f42009-09-18 04:08:43 -03004381{
4382 struct dib8000_state *st = fe->demodulator_priv;
Olivier Grenie4c70e072011-01-03 15:33:37 -03004383 u16 val = dib8000_read_word(st, 299) & 0xffef;
4384 val |= (onoff & 0x1) << 4;
Olivier Grenief8731f42009-09-18 04:08:43 -03004385
Olivier Grenie4c70e072011-01-03 15:33:37 -03004386 dprintk("pid filter enabled %d", onoff);
4387 return dib8000_write_word(st, 299, val);
Olivier Grenief8731f42009-09-18 04:08:43 -03004388}
Olivier Grenief8731f42009-09-18 04:08:43 -03004389
Mauro Carvalho Chehabd44913c2014-05-29 09:20:17 -03004390static int dib8000_pid_filter(struct dvb_frontend *fe, u8 id, u16 pid, u8 onoff)
Olivier Grenief8731f42009-09-18 04:08:43 -03004391{
4392 struct dib8000_state *st = fe->demodulator_priv;
Olivier Grenie4c70e072011-01-03 15:33:37 -03004393 dprintk("Index %x, PID %d, OnOff %d", id, pid, onoff);
4394 return dib8000_write_word(st, 305 + id, onoff ? (1 << 13) | pid : 0);
Olivier Grenief8731f42009-09-18 04:08:43 -03004395}
Olivier Grenief8731f42009-09-18 04:08:43 -03004396
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03004397static const struct dvb_frontend_ops dib8000_ops = {
Mauro Carvalho Chehab490ecd62011-12-22 20:38:27 -03004398 .delsys = { SYS_ISDBT },
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03004399 .info = {
4400 .name = "DiBcom 8000 ISDB-T",
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03004401 .frequency_min = 44250000,
4402 .frequency_max = 867250000,
4403 .frequency_stepsize = 62500,
4404 .caps = FE_CAN_INVERSION_AUTO |
4405 FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
4406 FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
4407 FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO |
4408 FE_CAN_TRANSMISSION_MODE_AUTO | FE_CAN_GUARD_INTERVAL_AUTO | FE_CAN_RECOVER | FE_CAN_HIERARCHY_AUTO,
4409 },
4410
4411 .release = dib8000_release,
4412
4413 .init = dib8000_wakeup,
4414 .sleep = dib8000_sleep,
4415
Mauro Carvalho Chehab490ecd62011-12-22 20:38:27 -03004416 .set_frontend = dib8000_set_frontend,
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03004417 .get_tune_settings = dib8000_fe_get_tune_settings,
Mauro Carvalho Chehab490ecd62011-12-22 20:38:27 -03004418 .get_frontend = dib8000_get_frontend,
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03004419
4420 .read_status = dib8000_read_status,
4421 .read_ber = dib8000_read_ber,
4422 .read_signal_strength = dib8000_read_signal_strength,
4423 .read_snr = dib8000_read_snr,
4424 .read_ucblocks = dib8000_read_unc_blocks,
4425};
4426
Mauro Carvalho Chehabd44913c2014-05-29 09:20:17 -03004427static struct dvb_frontend *dib8000_init(struct i2c_adapter *i2c_adap, u8 i2c_addr, struct dib8000_config *cfg)
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03004428{
4429 struct dvb_frontend *fe;
4430 struct dib8000_state *state;
4431
Mauro Carvalho Chehabb9bc7d52014-05-29 09:20:16 -03004432 dprintk("dib8000_init");
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03004433
4434 state = kzalloc(sizeof(struct dib8000_state), GFP_KERNEL);
4435 if (state == NULL)
4436 return NULL;
Olivier Grenie4c70e072011-01-03 15:33:37 -03004437 fe = kzalloc(sizeof(struct dvb_frontend), GFP_KERNEL);
4438 if (fe == NULL)
Dan Carpentered54c0e2011-01-19 11:27:58 -03004439 goto error;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03004440
4441 memcpy(&state->cfg, cfg, sizeof(struct dib8000_config));
4442 state->i2c.adap = i2c_adap;
4443 state->i2c.addr = i2c_addr;
Olivier Grenie5a0deee2011-05-03 12:27:33 -03004444 state->i2c.i2c_write_buffer = state->i2c_write_buffer;
4445 state->i2c.i2c_read_buffer = state->i2c_read_buffer;
Patrick Boettcher79fcce32011-08-03 12:08:21 -03004446 mutex_init(&state->i2c_buffer_lock);
4447 state->i2c.i2c_buffer_lock = &state->i2c_buffer_lock;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03004448 state->gpio_val = cfg->gpio_val;
4449 state->gpio_dir = cfg->gpio_dir;
4450
4451 /* Ensure the output mode remains at the previous default if it's
4452 * not specifically set by the caller.
4453 */
4454 if ((state->cfg.output_mode != OUTMODE_MPEG2_SERIAL) && (state->cfg.output_mode != OUTMODE_MPEG2_PAR_GATED_CLK))
4455 state->cfg.output_mode = OUTMODE_MPEG2_FIFO;
4456
Olivier Grenie4c70e072011-01-03 15:33:37 -03004457 state->fe[0] = fe;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03004458 fe->demodulator_priv = state;
Olivier Grenie4c70e072011-01-03 15:33:37 -03004459 memcpy(&state->fe[0]->ops, &dib8000_ops, sizeof(struct dvb_frontend_ops));
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03004460
4461 state->timf_default = cfg->pll->timf;
4462
4463 if (dib8000_identify(&state->i2c) == 0)
4464 goto error;
4465
4466 dibx000_init_i2c_master(&state->i2c_master, DIB8000, state->i2c.adap, state->i2c.addr);
4467
Olivier Grenie0c32dbd2011-08-10 05:17:18 -03004468 /* init 8096p tuner adapter */
4469 strncpy(state->dib8096p_tuner_adap.name, "DiB8096P tuner interface",
4470 sizeof(state->dib8096p_tuner_adap.name));
4471 state->dib8096p_tuner_adap.algo = &dib8096p_tuner_xfer_algo;
4472 state->dib8096p_tuner_adap.algo_data = NULL;
4473 state->dib8096p_tuner_adap.dev.parent = state->i2c.adap->dev.parent;
4474 i2c_set_adapdata(&state->dib8096p_tuner_adap, state);
4475 i2c_add_adapter(&state->dib8096p_tuner_adap);
4476
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03004477 dib8000_reset(fe);
4478
4479 dib8000_write_word(state, 285, (dib8000_read_word(state, 285) & ~0x60) | (3 << 5)); /* ber_rs_len = 3 */
Patrick Boettcher173a64c2013-04-22 12:45:52 -03004480 state->current_demod_bw = 6000;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03004481
4482 return fe;
4483
Patrick Boettcher173a64c2013-04-22 12:45:52 -03004484error:
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03004485 kfree(state);
4486 return NULL;
4487}
4488
Mauro Carvalho Chehabd44913c2014-05-29 09:20:17 -03004489void *dib8000_attach(struct dib8000_ops *ops)
4490{
4491 if (!ops)
4492 return NULL;
4493
4494 ops->pwm_agc_reset = dib8000_pwm_agc_reset;
4495 ops->get_dc_power = dib8090p_get_dc_power;
4496 ops->set_gpio = dib8000_set_gpio;
4497 ops->get_slave_frontend = dib8000_get_slave_frontend;
4498 ops->set_tune_state = dib8000_set_tune_state;
4499 ops->pid_filter_ctrl = dib8000_pid_filter_ctrl;
4500 ops->remove_slave_frontend = dib8000_remove_slave_frontend;
4501 ops->get_adc_power = dib8000_get_adc_power;
4502 ops->update_pll = dib8000_update_pll;
4503 ops->tuner_sleep = dib8096p_tuner_sleep;
4504 ops->get_tune_state = dib8000_get_tune_state;
4505 ops->get_i2c_tuner = dib8096p_get_i2c_tuner;
4506 ops->set_slave_frontend = dib8000_set_slave_frontend;
4507 ops->pid_filter = dib8000_pid_filter;
4508 ops->ctrl_timf = dib8000_ctrl_timf;
4509 ops->init = dib8000_init;
4510 ops->get_i2c_master = dib8000_get_i2c_master;
4511 ops->i2c_enumeration = dib8000_i2c_enumeration;
4512 ops->set_wbd_ref = dib8000_set_wbd_ref;
4513
4514 return ops;
4515}
4516EXPORT_SYMBOL(dib8000_attach);
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03004517
4518MODULE_AUTHOR("Olivier Grenie <Olivier.Grenie@dibcom.fr, " "Patrick Boettcher <pboettcher@dibcom.fr>");
4519MODULE_DESCRIPTION("Driver for the DiBcom 8000 ISDB-T demodulator");
4520MODULE_LICENSE("GPL");