blob: 90536147bf0458c444a59e176b79ddff09471f4f [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>
14
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -030015#include "dvb_math.h"
16
17#include "dvb_frontend.h"
18
19#include "dib8000.h"
20
21#define LAYER_ALL -1
22#define LAYER_A 1
23#define LAYER_B 2
24#define LAYER_C 3
25
Olivier Grenie4c70e072011-01-03 15:33:37 -030026#define MAX_NUMBER_OF_FRONTENDS 6
Patrick Boettcher173a64c2013-04-22 12:45:52 -030027/* #define DIB8000_AGC_FREEZE */
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -030028
Patrick Boettcher78f3bc62009-08-17 12:53:51 -030029static int debug;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -030030module_param(debug, int, 0644);
31MODULE_PARM_DESC(debug, "turn on debugging (default: 0)");
32
33#define dprintk(args...) do { if (debug) { printk(KERN_DEBUG "DiB8000: "); printk(args); printk("\n"); } } while (0)
34
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -030035struct i2c_device {
36 struct i2c_adapter *adap;
37 u8 addr;
Olivier Grenie5a0deee2011-05-03 12:27:33 -030038 u8 *i2c_write_buffer;
39 u8 *i2c_read_buffer;
Patrick Boettcher79fcce32011-08-03 12:08:21 -030040 struct mutex *i2c_buffer_lock;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -030041};
42
Patrick Boettcher173a64c2013-04-22 12:45:52 -030043enum param_loop_step {
44 LOOP_TUNE_1,
45 LOOP_TUNE_2
46};
47
48enum dib8000_autosearch_step {
49 AS_START = 0,
50 AS_SEARCHING_FFT,
51 AS_SEARCHING_GUARD,
52 AS_DONE = 100,
53};
54
55enum timeout_mode {
56 SYMBOL_DEPENDENT_OFF = 0,
57 SYMBOL_DEPENDENT_ON,
58};
59
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -030060struct dib8000_state {
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -030061 struct dib8000_config cfg;
62
63 struct i2c_device i2c;
64
65 struct dibx000_i2c_master i2c_master;
66
67 u16 wbd_ref;
68
69 u8 current_band;
70 u32 current_bandwidth;
71 struct dibx000_agc_config *current_agc;
72 u32 timf;
73 u32 timf_default;
74
75 u8 div_force_off:1;
76 u8 div_state:1;
77 u16 div_sync_wait;
78
79 u8 agc_state;
80 u8 differential_constellation;
81 u8 diversity_onoff;
82
83 s16 ber_monitored_layer;
84 u16 gpio_dir;
85 u16 gpio_val;
86
87 u16 revision;
88 u8 isdbt_cfg_loaded;
89 enum frontend_tune_state tune_state;
Patrick Boettcher173a64c2013-04-22 12:45:52 -030090 s32 status;
Olivier Grenie4c70e072011-01-03 15:33:37 -030091
92 struct dvb_frontend *fe[MAX_NUMBER_OF_FRONTENDS];
Olivier Grenie5a0deee2011-05-03 12:27:33 -030093
94 /* for the I2C transfer */
95 struct i2c_msg msg[2];
96 u8 i2c_write_buffer[4];
97 u8 i2c_read_buffer[2];
Patrick Boettcher79fcce32011-08-03 12:08:21 -030098 struct mutex i2c_buffer_lock;
Olivier Grenie0c32dbd2011-08-10 05:17:18 -030099 u8 input_mode_mpeg;
100
101 u16 tuner_enable;
102 struct i2c_adapter dib8096p_tuner_adap;
Patrick Boettcher173a64c2013-04-22 12:45:52 -0300103 u16 current_demod_bw;
104
105 u16 seg_mask;
106 u16 seg_diff_mask;
107 u16 mode;
108 u8 layer_b_nb_seg;
109 u8 layer_c_nb_seg;
110
111 u8 channel_parameters_set;
112 u16 autosearch_state;
113 u16 found_nfft;
114 u16 found_guard;
115 u8 subchannel;
116 u8 symbol_duration;
117 u32 timeout;
118 u8 longest_intlv_layer;
119 u16 output_mode;
120
121#ifdef DIB8000_AGC_FREEZE
122 u16 agc1_max;
123 u16 agc1_min;
124 u16 agc2_max;
125 u16 agc2_min;
126#endif
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300127};
128
129enum dib8000_power_mode {
Olivier Grenie0c32dbd2011-08-10 05:17:18 -0300130 DIB8000_POWER_ALL = 0,
131 DIB8000_POWER_INTERFACE_ONLY,
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300132};
133
134static u16 dib8000_i2c_read16(struct i2c_device *i2c, u16 reg)
135{
Patrick Boettcher79fcce32011-08-03 12:08:21 -0300136 u16 ret;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300137 struct i2c_msg msg[2] = {
Patrick Boettcher79fcce32011-08-03 12:08:21 -0300138 {.addr = i2c->addr >> 1, .flags = 0, .len = 2},
139 {.addr = i2c->addr >> 1, .flags = I2C_M_RD, .len = 2},
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300140 };
141
Patrick Boettcher79fcce32011-08-03 12:08:21 -0300142 if (mutex_lock_interruptible(i2c->i2c_buffer_lock) < 0) {
143 dprintk("could not acquire lock");
144 return 0;
145 }
146
147 msg[0].buf = i2c->i2c_write_buffer;
Olivier Grenie5a0deee2011-05-03 12:27:33 -0300148 msg[0].buf[0] = reg >> 8;
149 msg[0].buf[1] = reg & 0xff;
Patrick Boettcher79fcce32011-08-03 12:08:21 -0300150 msg[1].buf = i2c->i2c_read_buffer;
Olivier Grenie5a0deee2011-05-03 12:27:33 -0300151
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300152 if (i2c_transfer(i2c->adap, msg, 2) != 2)
153 dprintk("i2c read error on %d", reg);
154
Patrick Boettcher79fcce32011-08-03 12:08:21 -0300155 ret = (msg[1].buf[0] << 8) | msg[1].buf[1];
156 mutex_unlock(i2c->i2c_buffer_lock);
157 return ret;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300158}
159
160static u16 dib8000_read_word(struct dib8000_state *state, u16 reg)
161{
Patrick Boettcher79fcce32011-08-03 12:08:21 -0300162 u16 ret;
163
164 if (mutex_lock_interruptible(&state->i2c_buffer_lock) < 0) {
165 dprintk("could not acquire lock");
166 return 0;
167 }
168
Olivier Grenie5a0deee2011-05-03 12:27:33 -0300169 state->i2c_write_buffer[0] = reg >> 8;
170 state->i2c_write_buffer[1] = reg & 0xff;
171
172 memset(state->msg, 0, 2 * sizeof(struct i2c_msg));
173 state->msg[0].addr = state->i2c.addr >> 1;
174 state->msg[0].flags = 0;
175 state->msg[0].buf = state->i2c_write_buffer;
176 state->msg[0].len = 2;
177 state->msg[1].addr = state->i2c.addr >> 1;
178 state->msg[1].flags = I2C_M_RD;
179 state->msg[1].buf = state->i2c_read_buffer;
180 state->msg[1].len = 2;
181
182 if (i2c_transfer(state->i2c.adap, state->msg, 2) != 2)
183 dprintk("i2c read error on %d", reg);
184
Patrick Boettcher79fcce32011-08-03 12:08:21 -0300185 ret = (state->i2c_read_buffer[0] << 8) | state->i2c_read_buffer[1];
186 mutex_unlock(&state->i2c_buffer_lock);
187
188 return ret;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300189}
190
191static u32 dib8000_read32(struct dib8000_state *state, u16 reg)
192{
193 u16 rw[2];
194
195 rw[0] = dib8000_read_word(state, reg + 0);
196 rw[1] = dib8000_read_word(state, reg + 1);
197
198 return ((rw[0] << 16) | (rw[1]));
199}
200
201static int dib8000_i2c_write16(struct i2c_device *i2c, u16 reg, u16 val)
202{
Patrick Boettcher79fcce32011-08-03 12:08:21 -0300203 struct i2c_msg msg = {.addr = i2c->addr >> 1, .flags = 0, .len = 4};
Olivier Grenie5a0deee2011-05-03 12:27:33 -0300204 int ret = 0;
205
Patrick Boettcher79fcce32011-08-03 12:08:21 -0300206 if (mutex_lock_interruptible(i2c->i2c_buffer_lock) < 0) {
207 dprintk("could not acquire lock");
208 return -EINVAL;
209 }
210
211 msg.buf = i2c->i2c_write_buffer;
Olivier Grenie5a0deee2011-05-03 12:27:33 -0300212 msg.buf[0] = (reg >> 8) & 0xff;
213 msg.buf[1] = reg & 0xff;
214 msg.buf[2] = (val >> 8) & 0xff;
215 msg.buf[3] = val & 0xff;
216
217 ret = i2c_transfer(i2c->adap, &msg, 1) != 1 ? -EREMOTEIO : 0;
Patrick Boettcher79fcce32011-08-03 12:08:21 -0300218 mutex_unlock(i2c->i2c_buffer_lock);
Olivier Grenie5a0deee2011-05-03 12:27:33 -0300219
220 return ret;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300221}
222
223static int dib8000_write_word(struct dib8000_state *state, u16 reg, u16 val)
224{
Patrick Boettcher79fcce32011-08-03 12:08:21 -0300225 int ret;
226
227 if (mutex_lock_interruptible(&state->i2c_buffer_lock) < 0) {
228 dprintk("could not acquire lock");
229 return -EINVAL;
230 }
231
Olivier Grenie5a0deee2011-05-03 12:27:33 -0300232 state->i2c_write_buffer[0] = (reg >> 8) & 0xff;
233 state->i2c_write_buffer[1] = reg & 0xff;
234 state->i2c_write_buffer[2] = (val >> 8) & 0xff;
235 state->i2c_write_buffer[3] = val & 0xff;
236
237 memset(&state->msg[0], 0, sizeof(struct i2c_msg));
238 state->msg[0].addr = state->i2c.addr >> 1;
239 state->msg[0].flags = 0;
240 state->msg[0].buf = state->i2c_write_buffer;
241 state->msg[0].len = 4;
242
Patrick Boettcher79fcce32011-08-03 12:08:21 -0300243 ret = (i2c_transfer(state->i2c.adap, state->msg, 1) != 1 ?
244 -EREMOTEIO : 0);
245 mutex_unlock(&state->i2c_buffer_lock);
246
247 return ret;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300248}
249
Olivier Grenie4c70e072011-01-03 15:33:37 -0300250static const s16 coeff_2k_sb_1seg_dqpsk[8] = {
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300251 (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 -0300252 (920 << 5) | 0x09
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300253};
254
Olivier Grenie4c70e072011-01-03 15:33:37 -0300255static const s16 coeff_2k_sb_1seg[8] = {
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300256 (692 << 5) | 0x0b, (683 << 5) | 0x01, (519 << 5) | 0x09, (692 << 5) | 0x0b, 0 | 0x1f, 0 | 0x1f, 0 | 0x1f, 0 | 0x1f
257};
258
Olivier Grenie4c70e072011-01-03 15:33:37 -0300259static const s16 coeff_2k_sb_3seg_0dqpsk_1dqpsk[8] = {
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300260 (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 -0300261 (-931 << 5) | 0x0f
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300262};
263
Olivier Grenie4c70e072011-01-03 15:33:37 -0300264static const s16 coeff_2k_sb_3seg_0dqpsk[8] = {
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300265 (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 -0300266 (982 << 5) | 0x0c
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300267};
268
Olivier Grenie4c70e072011-01-03 15:33:37 -0300269static const s16 coeff_2k_sb_3seg_1dqpsk[8] = {
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300270 (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 -0300271 (-720 << 5) | 0x0d
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300272};
273
Olivier Grenie4c70e072011-01-03 15:33:37 -0300274static const s16 coeff_2k_sb_3seg[8] = {
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300275 (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 -0300276 (-610 << 5) | 0x0a
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300277};
278
Olivier Grenie4c70e072011-01-03 15:33:37 -0300279static const s16 coeff_4k_sb_1seg_dqpsk[8] = {
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300280 (-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 -0300281 (-922 << 5) | 0x0d
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300282};
283
Olivier Grenie4c70e072011-01-03 15:33:37 -0300284static const s16 coeff_4k_sb_1seg[8] = {
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300285 (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 -0300286 (-655 << 5) | 0x0a
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300287};
288
Olivier Grenie4c70e072011-01-03 15:33:37 -0300289static const s16 coeff_4k_sb_3seg_0dqpsk_1dqpsk[8] = {
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300290 (-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 -0300291 (-958 << 5) | 0x13
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300292};
293
Olivier Grenie4c70e072011-01-03 15:33:37 -0300294static const s16 coeff_4k_sb_3seg_0dqpsk[8] = {
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300295 (-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 -0300296 (-568 << 5) | 0x0f
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300297};
298
Olivier Grenie4c70e072011-01-03 15:33:37 -0300299static const s16 coeff_4k_sb_3seg_1dqpsk[8] = {
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300300 (-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 -0300301 (-848 << 5) | 0x13
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300302};
303
Olivier Grenie4c70e072011-01-03 15:33:37 -0300304static const s16 coeff_4k_sb_3seg[8] = {
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300305 (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 -0300306 (-869 << 5) | 0x13
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300307};
308
Olivier Grenie4c70e072011-01-03 15:33:37 -0300309static const s16 coeff_8k_sb_1seg_dqpsk[8] = {
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300310 (-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 -0300311 (-598 << 5) | 0x10
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300312};
313
Olivier Grenie4c70e072011-01-03 15:33:37 -0300314static const s16 coeff_8k_sb_1seg[8] = {
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300315 (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 -0300316 (585 << 5) | 0x0f
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300317};
318
Olivier Grenie4c70e072011-01-03 15:33:37 -0300319static const s16 coeff_8k_sb_3seg_0dqpsk_1dqpsk[8] = {
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300320 (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 -0300321 (0 << 5) | 0x14
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300322};
323
Olivier Grenie4c70e072011-01-03 15:33:37 -0300324static const s16 coeff_8k_sb_3seg_0dqpsk[8] = {
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300325 (-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 -0300326 (-877 << 5) | 0x15
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300327};
328
Olivier Grenie4c70e072011-01-03 15:33:37 -0300329static const s16 coeff_8k_sb_3seg_1dqpsk[8] = {
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300330 (-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 -0300331 (-921 << 5) | 0x14
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300332};
333
Olivier Grenie4c70e072011-01-03 15:33:37 -0300334static const s16 coeff_8k_sb_3seg[8] = {
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300335 (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 -0300336 (690 << 5) | 0x14
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300337};
338
Olivier Grenie4c70e072011-01-03 15:33:37 -0300339static const s16 ana_fe_coeff_3seg[24] = {
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300340 81, 80, 78, 74, 68, 61, 54, 45, 37, 28, 19, 11, 4, 1022, 1017, 1013, 1010, 1008, 1008, 1008, 1008, 1010, 1014, 1017
341};
342
Olivier Grenie4c70e072011-01-03 15:33:37 -0300343static const s16 ana_fe_coeff_1seg[24] = {
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300344 249, 226, 164, 82, 5, 981, 970, 988, 1018, 20, 31, 26, 8, 1012, 1000, 1018, 1012, 8, 15, 14, 9, 3, 1017, 1003
345};
346
Olivier Grenie4c70e072011-01-03 15:33:37 -0300347static const s16 ana_fe_coeff_13seg[24] = {
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300348 396, 305, 105, -51, -77, -12, 41, 31, -11, -30, -11, 14, 15, -2, -13, -7, 5, 8, 1, -6, -7, -3, 0, 1
349};
350
351static u16 fft_to_mode(struct dib8000_state *state)
352{
353 u16 mode;
Olivier Grenie4c70e072011-01-03 15:33:37 -0300354 switch (state->fe[0]->dtv_property_cache.transmission_mode) {
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300355 case TRANSMISSION_MODE_2K:
356 mode = 1;
357 break;
358 case TRANSMISSION_MODE_4K:
359 mode = 2;
360 break;
361 default:
362 case TRANSMISSION_MODE_AUTO:
363 case TRANSMISSION_MODE_8K:
364 mode = 3;
365 break;
366 }
367 return mode;
368}
369
370static void dib8000_set_acquisition_mode(struct dib8000_state *state)
371{
372 u16 nud = dib8000_read_word(state, 298);
373 nud |= (1 << 3) | (1 << 0);
374 dprintk("acquisition mode activated");
375 dib8000_write_word(state, 298, nud);
376}
Olivier Grenie4c70e072011-01-03 15:33:37 -0300377static int dib8000_set_output_mode(struct dvb_frontend *fe, int mode)
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300378{
Olivier Grenie4c70e072011-01-03 15:33:37 -0300379 struct dib8000_state *state = fe->demodulator_priv;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300380 u16 outreg, fifo_threshold, smo_mode, sram = 0x0205; /* by default SDRAM deintlv is enabled */
381
Patrick Boettcher173a64c2013-04-22 12:45:52 -0300382 state->output_mode = mode;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300383 outreg = 0;
384 fifo_threshold = 1792;
385 smo_mode = (dib8000_read_word(state, 299) & 0x0050) | (1 << 1);
386
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300387 dprintk("-I- Setting output mode for demod %p to %d",
388 &state->fe[0], mode);
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300389
390 switch (mode) {
391 case OUTMODE_MPEG2_PAR_GATED_CLK: // STBs with parallel gated clock
392 outreg = (1 << 10); /* 0x0400 */
393 break;
394 case OUTMODE_MPEG2_PAR_CONT_CLK: // STBs with parallel continues clock
395 outreg = (1 << 10) | (1 << 6); /* 0x0440 */
396 break;
397 case OUTMODE_MPEG2_SERIAL: // STBs with serial input
398 outreg = (1 << 10) | (2 << 6) | (0 << 1); /* 0x0482 */
399 break;
400 case OUTMODE_DIVERSITY:
401 if (state->cfg.hostbus_diversity) {
402 outreg = (1 << 10) | (4 << 6); /* 0x0500 */
403 sram &= 0xfdff;
404 } else
405 sram |= 0x0c00;
406 break;
407 case OUTMODE_MPEG2_FIFO: // e.g. USB feeding
408 smo_mode |= (3 << 1);
409 fifo_threshold = 512;
410 outreg = (1 << 10) | (5 << 6);
411 break;
412 case OUTMODE_HIGH_Z: // disable
413 outreg = 0;
414 break;
415
416 case OUTMODE_ANALOG_ADC:
417 outreg = (1 << 10) | (3 << 6);
418 dib8000_set_acquisition_mode(state);
419 break;
420
421 default:
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300422 dprintk("Unhandled output_mode passed to be set for demod %p",
423 &state->fe[0]);
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300424 return -EINVAL;
425 }
426
427 if (state->cfg.output_mpeg2_in_188_bytes)
428 smo_mode |= (1 << 5);
429
430 dib8000_write_word(state, 299, smo_mode);
431 dib8000_write_word(state, 300, fifo_threshold); /* synchronous fread */
432 dib8000_write_word(state, 1286, outreg);
433 dib8000_write_word(state, 1291, sram);
434
435 return 0;
436}
437
438static int dib8000_set_diversity_in(struct dvb_frontend *fe, int onoff)
439{
440 struct dib8000_state *state = fe->demodulator_priv;
Patrick Boettcher173a64c2013-04-22 12:45:52 -0300441 u16 tmp, sync_wait = dib8000_read_word(state, 273) & 0xfff0;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300442
Patrick Boettcher173a64c2013-04-22 12:45:52 -0300443 dprintk("set diversity input to %i", onoff);
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300444 if (!state->differential_constellation) {
445 dib8000_write_word(state, 272, 1 << 9); //dvsy_off_lmod4 = 1
446 dib8000_write_word(state, 273, sync_wait | (1 << 2) | 2); // sync_enable = 1; comb_mode = 2
447 } else {
448 dib8000_write_word(state, 272, 0); //dvsy_off_lmod4 = 0
449 dib8000_write_word(state, 273, sync_wait); // sync_enable = 0; comb_mode = 0
450 }
451 state->diversity_onoff = onoff;
452
453 switch (onoff) {
454 case 0: /* only use the internal way - not the diversity input */
455 dib8000_write_word(state, 270, 1);
456 dib8000_write_word(state, 271, 0);
457 break;
458 case 1: /* both ways */
459 dib8000_write_word(state, 270, 6);
460 dib8000_write_word(state, 271, 6);
461 break;
462 case 2: /* only the diversity input */
463 dib8000_write_word(state, 270, 0);
464 dib8000_write_word(state, 271, 1);
465 break;
466 }
Patrick Boettcher173a64c2013-04-22 12:45:52 -0300467
468 if (state->revision == 0x8002) {
469 tmp = dib8000_read_word(state, 903);
470 dib8000_write_word(state, 903, tmp & ~(1 << 3));
471 msleep(30);
472 dib8000_write_word(state, 903, tmp | (1 << 3));
473 }
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300474 return 0;
475}
476
477static void dib8000_set_power_mode(struct dib8000_state *state, enum dib8000_power_mode mode)
478{
479 /* by default everything is going to be powered off */
480 u16 reg_774 = 0x3fff, reg_775 = 0xffff, reg_776 = 0xffff,
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300481 reg_900 = (dib8000_read_word(state, 900) & 0xfffc) | 0x3,
Olivier Grenie0c32dbd2011-08-10 05:17:18 -0300482 reg_1280;
483
484 if (state->revision != 0x8090)
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300485 reg_1280 = (dib8000_read_word(state, 1280) & 0x00ff) | 0xff00;
Olivier Grenie0c32dbd2011-08-10 05:17:18 -0300486 else
487 reg_1280 = (dib8000_read_word(state, 1280) & 0x707f) | 0x8f80;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300488
489 /* now, depending on the requested mode, we power on */
490 switch (mode) {
491 /* power up everything in the demod */
Olivier Grenie0c32dbd2011-08-10 05:17:18 -0300492 case DIB8000_POWER_ALL:
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300493 reg_774 = 0x0000;
494 reg_775 = 0x0000;
495 reg_776 = 0x0000;
496 reg_900 &= 0xfffc;
Olivier Grenie0c32dbd2011-08-10 05:17:18 -0300497 if (state->revision != 0x8090)
498 reg_1280 &= 0x00ff;
499 else
500 reg_1280 &= 0x707f;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300501 break;
Olivier Grenie0c32dbd2011-08-10 05:17:18 -0300502 case DIB8000_POWER_INTERFACE_ONLY:
503 if (state->revision != 0x8090)
504 reg_1280 &= 0x00ff;
505 else
506 reg_1280 &= 0xfa7b;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300507 break;
508 }
509
510 dprintk("powermode : 774 : %x ; 775 : %x; 776 : %x ; 900 : %x; 1280 : %x", reg_774, reg_775, reg_776, reg_900, reg_1280);
511 dib8000_write_word(state, 774, reg_774);
512 dib8000_write_word(state, 775, reg_775);
513 dib8000_write_word(state, 776, reg_776);
514 dib8000_write_word(state, 900, reg_900);
515 dib8000_write_word(state, 1280, reg_1280);
516}
517
518static int dib8000_set_adc_state(struct dib8000_state *state, enum dibx000_adc_states no)
519{
520 int ret = 0;
Olivier Grenie0c32dbd2011-08-10 05:17:18 -0300521 u16 reg, reg_907 = dib8000_read_word(state, 907);
522 u16 reg_908 = dib8000_read_word(state, 908);
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300523
524 switch (no) {
525 case DIBX000_SLOW_ADC_ON:
Olivier Grenie0c32dbd2011-08-10 05:17:18 -0300526 if (state->revision != 0x8090) {
527 reg_908 |= (1 << 1) | (1 << 0);
528 ret |= dib8000_write_word(state, 908, reg_908);
529 reg_908 &= ~(1 << 1);
530 } else {
531 reg = dib8000_read_word(state, 1925);
532 /* en_slowAdc = 1 & reset_sladc = 1 */
533 dib8000_write_word(state, 1925, reg |
534 (1<<4) | (1<<2));
535
536 /* read acces to make it works... strange ... */
537 reg = dib8000_read_word(state, 1925);
538 msleep(20);
539 /* en_slowAdc = 1 & reset_sladc = 0 */
540 dib8000_write_word(state, 1925, reg & ~(1<<4));
541
542 reg = dib8000_read_word(state, 921) & ~((0x3 << 14)
543 | (0x3 << 12));
544 /* ref = Vin1 => Vbg ; sel = Vin0 or Vin3 ;
545 (Vin2 = Vcm) */
546 dib8000_write_word(state, 921, reg | (1 << 14)
547 | (3 << 12));
548 }
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300549 break;
550
551 case DIBX000_SLOW_ADC_OFF:
Olivier Grenie0c32dbd2011-08-10 05:17:18 -0300552 if (state->revision == 0x8090) {
553 reg = dib8000_read_word(state, 1925);
554 /* reset_sladc = 1 en_slowAdc = 0 */
555 dib8000_write_word(state, 1925,
556 (reg & ~(1<<2)) | (1<<4));
557 }
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300558 reg_908 |= (1 << 1) | (1 << 0);
559 break;
560
561 case DIBX000_ADC_ON:
562 reg_907 &= 0x0fff;
563 reg_908 &= 0x0003;
564 break;
565
566 case DIBX000_ADC_OFF: // leave the VBG voltage on
567 reg_907 |= (1 << 14) | (1 << 13) | (1 << 12);
568 reg_908 |= (1 << 5) | (1 << 4) | (1 << 3) | (1 << 2);
569 break;
570
571 case DIBX000_VBG_ENABLE:
572 reg_907 &= ~(1 << 15);
573 break;
574
575 case DIBX000_VBG_DISABLE:
576 reg_907 |= (1 << 15);
577 break;
578
579 default:
580 break;
581 }
582
583 ret |= dib8000_write_word(state, 907, reg_907);
584 ret |= dib8000_write_word(state, 908, reg_908);
585
586 return ret;
587}
588
Olivier Grenie4c70e072011-01-03 15:33:37 -0300589static int dib8000_set_bandwidth(struct dvb_frontend *fe, u32 bw)
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300590{
Olivier Grenie4c70e072011-01-03 15:33:37 -0300591 struct dib8000_state *state = fe->demodulator_priv;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300592 u32 timf;
593
594 if (bw == 0)
595 bw = 6000;
596
597 if (state->timf == 0) {
598 dprintk("using default timf");
599 timf = state->timf_default;
600 } else {
601 dprintk("using updated timf");
602 timf = state->timf;
603 }
604
605 dib8000_write_word(state, 29, (u16) ((timf >> 16) & 0xffff));
606 dib8000_write_word(state, 30, (u16) ((timf) & 0xffff));
607
608 return 0;
609}
610
611static int dib8000_sad_calib(struct dib8000_state *state)
612{
Patrick Boettcher173a64c2013-04-22 12:45:52 -0300613 u8 sad_sel = 3;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300614
Patrick Boettcher173a64c2013-04-22 12:45:52 -0300615 if (state->revision == 0x8090) {
616 dib8000_write_word(state, 922, (sad_sel << 2));
617 dib8000_write_word(state, 923, 2048);
618
619 dib8000_write_word(state, 922, (sad_sel << 2) | 0x1);
620 dib8000_write_word(state, 922, (sad_sel << 2));
621 } else {
622 /* internal */
623 dib8000_write_word(state, 923, (0 << 1) | (0 << 0));
624 dib8000_write_word(state, 924, 776);
625
626 /* do the calibration */
627 dib8000_write_word(state, 923, (1 << 0));
628 dib8000_write_word(state, 923, (0 << 0));
629 }
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300630
631 msleep(1);
632 return 0;
633}
634
635int dib8000_set_wbd_ref(struct dvb_frontend *fe, u16 value)
636{
637 struct dib8000_state *state = fe->demodulator_priv;
638 if (value > 4095)
639 value = 4095;
640 state->wbd_ref = value;
641 return dib8000_write_word(state, 106, value);
642}
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300643EXPORT_SYMBOL(dib8000_set_wbd_ref);
Patrick Boettcher173a64c2013-04-22 12:45:52 -0300644
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300645static void dib8000_reset_pll_common(struct dib8000_state *state, const struct dibx000_bandwidth_config *bw)
646{
647 dprintk("ifreq: %d %x, inversion: %d", bw->ifreq, bw->ifreq, bw->ifreq >> 25);
Olivier Grenie0c32dbd2011-08-10 05:17:18 -0300648 if (state->revision != 0x8090) {
649 dib8000_write_word(state, 23,
650 (u16) (((bw->internal * 1000) >> 16) & 0xffff));
651 dib8000_write_word(state, 24,
652 (u16) ((bw->internal * 1000) & 0xffff));
653 } else {
654 dib8000_write_word(state, 23, (u16) (((bw->internal / 2 * 1000) >> 16) & 0xffff));
655 dib8000_write_word(state, 24,
656 (u16) ((bw->internal / 2 * 1000) & 0xffff));
657 }
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300658 dib8000_write_word(state, 27, (u16) ((bw->ifreq >> 16) & 0x01ff));
659 dib8000_write_word(state, 28, (u16) (bw->ifreq & 0xffff));
660 dib8000_write_word(state, 26, (u16) ((bw->ifreq >> 25) & 0x0003));
661
Olivier Grenie0c32dbd2011-08-10 05:17:18 -0300662 if (state->revision != 0x8090)
663 dib8000_write_word(state, 922, bw->sad_cfg);
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300664}
665
666static void dib8000_reset_pll(struct dib8000_state *state)
667{
668 const struct dibx000_bandwidth_config *pll = state->cfg.pll;
Olivier Grenie0c32dbd2011-08-10 05:17:18 -0300669 u16 clk_cfg1, reg;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300670
Olivier Grenie0c32dbd2011-08-10 05:17:18 -0300671 if (state->revision != 0x8090) {
672 dib8000_write_word(state, 901,
673 (pll->pll_prediv << 8) | (pll->pll_ratio << 0));
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300674
Olivier Grenie0c32dbd2011-08-10 05:17:18 -0300675 clk_cfg1 = (1 << 10) | (0 << 9) | (pll->IO_CLK_en_core << 8) |
676 (pll->bypclk_div << 5) | (pll->enable_refdiv << 4) |
677 (1 << 3) | (pll->pll_range << 1) |
678 (pll->pll_reset << 0);
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300679
Olivier Grenie0c32dbd2011-08-10 05:17:18 -0300680 dib8000_write_word(state, 902, clk_cfg1);
681 clk_cfg1 = (clk_cfg1 & 0xfff7) | (pll->pll_bypass << 3);
682 dib8000_write_word(state, 902, clk_cfg1);
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300683
Olivier Grenie0c32dbd2011-08-10 05:17:18 -0300684 dprintk("clk_cfg1: 0x%04x", clk_cfg1);
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300685
Olivier Grenie0c32dbd2011-08-10 05:17:18 -0300686 /* smpl_cfg: P_refclksel=2, P_ensmplsel=1 nodivsmpl=1 */
687 if (state->cfg.pll->ADClkSrc == 0)
688 dib8000_write_word(state, 904,
689 (0 << 15) | (0 << 12) | (0 << 10) |
690 (pll->modulo << 8) |
691 (pll->ADClkSrc << 7) | (0 << 1));
692 else if (state->cfg.refclksel != 0)
693 dib8000_write_word(state, 904, (0 << 15) | (1 << 12) |
694 ((state->cfg.refclksel & 0x3) << 10) |
695 (pll->modulo << 8) |
696 (pll->ADClkSrc << 7) | (0 << 1));
697 else
698 dib8000_write_word(state, 904, (0 << 15) | (1 << 12) |
699 (3 << 10) | (pll->modulo << 8) |
700 (pll->ADClkSrc << 7) | (0 << 1));
701 } else {
702 dib8000_write_word(state, 1856, (!pll->pll_reset<<13) |
703 (pll->pll_range<<12) | (pll->pll_ratio<<6) |
704 (pll->pll_prediv));
705
706 reg = dib8000_read_word(state, 1857);
707 dib8000_write_word(state, 1857, reg|(!pll->pll_bypass<<15));
708
709 reg = dib8000_read_word(state, 1858); /* Force clk out pll /2 */
710 dib8000_write_word(state, 1858, reg | 1);
711
712 dib8000_write_word(state, 904, (pll->modulo << 8));
713 }
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300714
715 dib8000_reset_pll_common(state, pll);
716}
717
Olivier Grenie0c32dbd2011-08-10 05:17:18 -0300718int dib8000_update_pll(struct dvb_frontend *fe,
Patrick Boettcher173a64c2013-04-22 12:45:52 -0300719 struct dibx000_bandwidth_config *pll, u32 bw, u8 ratio)
Olivier Grenie0c32dbd2011-08-10 05:17:18 -0300720{
721 struct dib8000_state *state = fe->demodulator_priv;
722 u16 reg_1857, reg_1856 = dib8000_read_word(state, 1856);
Patrick Boettcher173a64c2013-04-22 12:45:52 -0300723 u8 loopdiv, prediv, oldprediv = state->cfg.pll->pll_prediv ;
Olivier Grenie0c32dbd2011-08-10 05:17:18 -0300724 u32 internal, xtal;
725
726 /* get back old values */
727 prediv = reg_1856 & 0x3f;
728 loopdiv = (reg_1856 >> 6) & 0x3f;
729
Patrick Boettcher173a64c2013-04-22 12:45:52 -0300730 if ((pll == NULL) || (pll->pll_prediv == prediv &&
731 pll->pll_ratio == loopdiv))
732 return -EINVAL;
733
734 dprintk("Updating pll (prediv: old = %d new = %d ; loopdiv : old = %d new = %d)", prediv, pll->pll_prediv, loopdiv, pll->pll_ratio);
735 if (state->revision == 0x8090) {
Olivier Grenie0c32dbd2011-08-10 05:17:18 -0300736 reg_1856 &= 0xf000;
737 reg_1857 = dib8000_read_word(state, 1857);
738 /* disable PLL */
739 dib8000_write_word(state, 1857, reg_1857 & ~(1 << 15));
740
741 dib8000_write_word(state, 1856, reg_1856 |
742 ((pll->pll_ratio & 0x3f) << 6) |
743 (pll->pll_prediv & 0x3f));
744
745 /* write new system clk into P_sec_len */
746 internal = dib8000_read32(state, 23) / 1000;
747 dprintk("Old Internal = %d", internal);
748 xtal = 2 * (internal / loopdiv) * prediv;
749 internal = 1000 * (xtal/pll->pll_prediv) * pll->pll_ratio;
750 dprintk("Xtal = %d , New Fmem = %d New Fdemod = %d, New Fsampling = %d", xtal, internal/1000, internal/2000, internal/8000);
751 dprintk("New Internal = %d", internal);
752
753 dib8000_write_word(state, 23,
754 (u16) (((internal / 2) >> 16) & 0xffff));
755 dib8000_write_word(state, 24, (u16) ((internal / 2) & 0xffff));
756 /* enable PLL */
757 dib8000_write_word(state, 1857, reg_1857 | (1 << 15));
758
759 while (((dib8000_read_word(state, 1856)>>15)&0x1) != 1)
760 dprintk("Waiting for PLL to lock");
761
762 /* verify */
763 reg_1856 = dib8000_read_word(state, 1856);
764 dprintk("PLL Updated with prediv = %d and loopdiv = %d",
765 reg_1856&0x3f, (reg_1856>>6)&0x3f);
Patrick Boettcher173a64c2013-04-22 12:45:52 -0300766 } else {
767 if (bw != state->current_demod_bw) {
768 /** Bandwidth change => force PLL update **/
769 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 -0300770
Patrick Boettcher173a64c2013-04-22 12:45:52 -0300771 if (state->cfg.pll->pll_prediv != oldprediv) {
772 /** Full PLL change only if prediv is changed **/
773
774 /** full update => bypass and reconfigure **/
775 dprintk("PLL: New Setting for %d MHz Bandwidth (prediv: %d, ratio: %d)", bw/1000, state->cfg.pll->pll_prediv, state->cfg.pll->pll_ratio);
776 dib8000_write_word(state, 902, dib8000_read_word(state, 902) | (1<<3)); /* bypass PLL */
777 dib8000_reset_pll(state);
778 dib8000_write_word(state, 898, 0x0004); /* sad */
779 } else
780 ratio = state->cfg.pll->pll_ratio;
781
782 state->current_demod_bw = bw;
783 }
784
785 if (ratio != 0) {
786 /** ratio update => only change ratio **/
787 dprintk("PLL: Update ratio (prediv: %d, ratio: %d)", state->cfg.pll->pll_prediv, ratio);
788 dib8000_write_word(state, 901, (state->cfg.pll->pll_prediv << 8) | (ratio << 0)); /* only the PLL ratio is updated. */
789 }
790}
791
792 return 0;
Olivier Grenie0c32dbd2011-08-10 05:17:18 -0300793}
794EXPORT_SYMBOL(dib8000_update_pll);
795
796
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300797static int dib8000_reset_gpio(struct dib8000_state *st)
798{
799 /* reset the GPIOs */
800 dib8000_write_word(st, 1029, st->cfg.gpio_dir);
801 dib8000_write_word(st, 1030, st->cfg.gpio_val);
802
803 /* TODO 782 is P_gpio_od */
804
805 dib8000_write_word(st, 1032, st->cfg.gpio_pwm_pos);
806
807 dib8000_write_word(st, 1037, st->cfg.pwm_freq_div);
808 return 0;
809}
810
811static int dib8000_cfg_gpio(struct dib8000_state *st, u8 num, u8 dir, u8 val)
812{
813 st->cfg.gpio_dir = dib8000_read_word(st, 1029);
814 st->cfg.gpio_dir &= ~(1 << num); /* reset the direction bit */
815 st->cfg.gpio_dir |= (dir & 0x1) << num; /* set the new direction */
816 dib8000_write_word(st, 1029, st->cfg.gpio_dir);
817
818 st->cfg.gpio_val = dib8000_read_word(st, 1030);
819 st->cfg.gpio_val &= ~(1 << num); /* reset the direction bit */
820 st->cfg.gpio_val |= (val & 0x01) << num; /* set the new value */
821 dib8000_write_word(st, 1030, st->cfg.gpio_val);
822
823 dprintk("gpio dir: %x: gpio val: %x", st->cfg.gpio_dir, st->cfg.gpio_val);
824
825 return 0;
826}
827
828int dib8000_set_gpio(struct dvb_frontend *fe, u8 num, u8 dir, u8 val)
829{
830 struct dib8000_state *state = fe->demodulator_priv;
831 return dib8000_cfg_gpio(state, num, dir, val);
832}
833
834EXPORT_SYMBOL(dib8000_set_gpio);
835static const u16 dib8000_defaults[] = {
836 /* auto search configuration - lock0 by default waiting
837 * for cpil_lock; lock1 cpil_lock; lock2 tmcc_sync_lock */
838 3, 7,
839 0x0004,
840 0x0400,
841 0x0814,
842
843 12, 11,
844 0x001b,
845 0x7740,
846 0x005b,
847 0x8d80,
848 0x01c9,
849 0xc380,
850 0x0000,
851 0x0080,
852 0x0000,
853 0x0090,
854 0x0001,
855 0xd4c0,
856
857 /*1, 32,
Olivier Grenie4c70e072011-01-03 15:33:37 -0300858 0x6680 // P_corm_thres Lock algorithms configuration */
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300859
860 11, 80, /* set ADC level to -16 */
861 (1 << 13) - 825 - 117,
862 (1 << 13) - 837 - 117,
863 (1 << 13) - 811 - 117,
864 (1 << 13) - 766 - 117,
865 (1 << 13) - 737 - 117,
866 (1 << 13) - 693 - 117,
867 (1 << 13) - 648 - 117,
868 (1 << 13) - 619 - 117,
869 (1 << 13) - 575 - 117,
870 (1 << 13) - 531 - 117,
871 (1 << 13) - 501 - 117,
872
873 4, 108,
874 0,
875 0,
876 0,
877 0,
878
879 1, 175,
880 0x0410,
881 1, 179,
882 8192, // P_fft_nb_to_cut
883
884 6, 181,
885 0x2800, // P_coff_corthres_ ( 2k 4k 8k ) 0x2800
886 0x2800,
887 0x2800,
888 0x2800, // P_coff_cpilthres_ ( 2k 4k 8k ) 0x2800
889 0x2800,
890 0x2800,
891
892 2, 193,
893 0x0666, // P_pha3_thres
894 0x0000, // P_cti_use_cpe, P_cti_use_prog
895
896 2, 205,
897 0x200f, // P_cspu_regul, P_cspu_win_cut
898 0x000f, // P_des_shift_work
899
900 5, 215,
901 0x023d, // P_adp_regul_cnt
902 0x00a4, // P_adp_noise_cnt
903 0x00a4, // P_adp_regul_ext
904 0x7ff0, // P_adp_noise_ext
905 0x3ccc, // P_adp_fil
906
907 1, 230,
908 0x0000, // P_2d_byp_ti_num
909
910 1, 263,
911 0x800, //P_equal_thres_wgn
912
913 1, 268,
914 (2 << 9) | 39, // P_equal_ctrl_synchro, P_equal_speedmode
915
916 1, 270,
917 0x0001, // P_div_lock0_wait
918 1, 285,
919 0x0020, //p_fec_
920 1, 299,
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300921 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 -0300922
923 1, 338,
924 (1 << 12) | // P_ctrl_corm_thres4pre_freq_inh=1
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300925 (1 << 10) |
926 (0 << 9) | /* P_ctrl_pre_freq_inh=0 */
927 (3 << 5) | /* P_ctrl_pre_freq_step=3 */
928 (1 << 0), /* P_pre_freq_win_len=1 */
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300929
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300930 0,
931};
932
933static u16 dib8000_identify(struct i2c_device *client)
934{
935 u16 value;
936
937 //because of glitches sometimes
938 value = dib8000_i2c_read16(client, 896);
939
940 if ((value = dib8000_i2c_read16(client, 896)) != 0x01b3) {
941 dprintk("wrong Vendor ID (read=0x%x)", value);
942 return 0;
943 }
944
945 value = dib8000_i2c_read16(client, 897);
Olivier Grenie0c32dbd2011-08-10 05:17:18 -0300946 if (value != 0x8000 && value != 0x8001 &&
947 value != 0x8002 && value != 0x8090) {
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300948 dprintk("wrong Device ID (%x)", value);
949 return 0;
950 }
951
952 switch (value) {
953 case 0x8000:
954 dprintk("found DiB8000A");
955 break;
956 case 0x8001:
957 dprintk("found DiB8000B");
958 break;
959 case 0x8002:
960 dprintk("found DiB8000C");
961 break;
Olivier Grenie0c32dbd2011-08-10 05:17:18 -0300962 case 0x8090:
963 dprintk("found DiB8096P");
964 break;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300965 }
966 return value;
967}
968
969static int dib8000_reset(struct dvb_frontend *fe)
970{
971 struct dib8000_state *state = fe->demodulator_priv;
972
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300973 if ((state->revision = dib8000_identify(&state->i2c)) == 0)
974 return -EINVAL;
975
Olivier Grenie0c32dbd2011-08-10 05:17:18 -0300976 /* sram lead in, rdy */
977 if (state->revision != 0x8090)
978 dib8000_write_word(state, 1287, 0x0003);
979
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300980 if (state->revision == 0x8000)
981 dprintk("error : dib8000 MA not supported");
982
983 dibx000_reset_i2c_master(&state->i2c_master);
984
Olivier Grenie0c32dbd2011-08-10 05:17:18 -0300985 dib8000_set_power_mode(state, DIB8000_POWER_ALL);
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300986
987 /* always leave the VBG voltage on - it consumes almost nothing but takes a long time to start */
Patrick Boettcher173a64c2013-04-22 12:45:52 -0300988 dib8000_set_adc_state(state, DIBX000_ADC_OFF);
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300989
990 /* restart all parts */
991 dib8000_write_word(state, 770, 0xffff);
992 dib8000_write_word(state, 771, 0xffff);
993 dib8000_write_word(state, 772, 0xfffc);
Olivier Grenie0c32dbd2011-08-10 05:17:18 -0300994 if (state->revision == 0x8090)
995 dib8000_write_word(state, 1280, 0x0045);
996 else
997 dib8000_write_word(state, 1280, 0x004d);
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300998 dib8000_write_word(state, 1281, 0x000c);
999
1000 dib8000_write_word(state, 770, 0x0000);
1001 dib8000_write_word(state, 771, 0x0000);
1002 dib8000_write_word(state, 772, 0x0000);
1003 dib8000_write_word(state, 898, 0x0004); // sad
1004 dib8000_write_word(state, 1280, 0x0000);
1005 dib8000_write_word(state, 1281, 0x0000);
1006
1007 /* drives */
Olivier Grenie0c32dbd2011-08-10 05:17:18 -03001008 if (state->revision != 0x8090) {
1009 if (state->cfg.drives)
1010 dib8000_write_word(state, 906, state->cfg.drives);
1011 else {
1012 dprintk("using standard PAD-drive-settings, please adjust settings in config-struct to be optimal.");
1013 /* min drive SDRAM - not optimal - adjust */
1014 dib8000_write_word(state, 906, 0x2d98);
1015 }
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001016 }
1017
1018 dib8000_reset_pll(state);
Olivier Grenie0c32dbd2011-08-10 05:17:18 -03001019 if (state->revision != 0x8090)
1020 dib8000_write_word(state, 898, 0x0004);
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001021
1022 if (dib8000_reset_gpio(state) != 0)
1023 dprintk("GPIO reset was not successful.");
1024
Olivier Grenie0c32dbd2011-08-10 05:17:18 -03001025 if ((state->revision != 0x8090) &&
1026 (dib8000_set_output_mode(fe, OUTMODE_HIGH_Z) != 0))
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001027 dprintk("OUTPUT_MODE could not be resetted.");
1028
1029 state->current_agc = NULL;
1030
1031 // P_iqc_alpha_pha, P_iqc_alpha_amp, P_iqc_dcc_alpha, ...
1032 /* P_iqc_ca2 = 0; P_iqc_impnc_on = 0; P_iqc_mode = 0; */
1033 if (state->cfg.pll->ifreq == 0)
1034 dib8000_write_word(state, 40, 0x0755); /* P_iqc_corr_inh = 0 enable IQcorr block */
1035 else
1036 dib8000_write_word(state, 40, 0x1f55); /* P_iqc_corr_inh = 1 disable IQcorr block */
1037
1038 {
1039 u16 l = 0, r;
1040 const u16 *n;
1041 n = dib8000_defaults;
1042 l = *n++;
1043 while (l) {
1044 r = *n++;
1045 do {
1046 dib8000_write_word(state, r, *n++);
1047 r++;
1048 } while (--l);
1049 l = *n++;
1050 }
1051 }
Patrick Boettcher173a64c2013-04-22 12:45:52 -03001052
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001053 state->isdbt_cfg_loaded = 0;
1054
1055 //div_cfg override for special configs
Patrick Boettcher173a64c2013-04-22 12:45:52 -03001056 if ((state->revision != 8090) && (state->cfg.div_cfg != 0))
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001057 dib8000_write_word(state, 903, state->cfg.div_cfg);
1058
1059 /* unforce divstr regardless whether i2c enumeration was done or not */
1060 dib8000_write_word(state, 1285, dib8000_read_word(state, 1285) & ~(1 << 1));
1061
Olivier Grenie4c70e072011-01-03 15:33:37 -03001062 dib8000_set_bandwidth(fe, 6000);
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001063
1064 dib8000_set_adc_state(state, DIBX000_SLOW_ADC_ON);
Patrick Boettcher173a64c2013-04-22 12:45:52 -03001065 dib8000_sad_calib(state);
1066 if (state->revision != 0x8090)
Olivier Grenie0c32dbd2011-08-10 05:17:18 -03001067 dib8000_set_adc_state(state, DIBX000_SLOW_ADC_OFF);
Patrick Boettcher173a64c2013-04-22 12:45:52 -03001068
1069 /* ber_rs_len = 3 */
1070 dib8000_write_word(state, 285, (dib8000_read_word(state, 285) & ~0x60) | (3 << 5));
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001071
Olivier Grenie0c32dbd2011-08-10 05:17:18 -03001072 dib8000_set_power_mode(state, DIB8000_POWER_INTERFACE_ONLY);
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001073
1074 return 0;
1075}
1076
1077static void dib8000_restart_agc(struct dib8000_state *state)
1078{
1079 // P_restart_iqc & P_restart_agc
1080 dib8000_write_word(state, 770, 0x0a00);
1081 dib8000_write_word(state, 770, 0x0000);
1082}
1083
1084static int dib8000_update_lna(struct dib8000_state *state)
1085{
1086 u16 dyn_gain;
1087
1088 if (state->cfg.update_lna) {
1089 // read dyn_gain here (because it is demod-dependent and not tuner)
1090 dyn_gain = dib8000_read_word(state, 390);
1091
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001092 if (state->cfg.update_lna(state->fe[0], dyn_gain)) {
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001093 dib8000_restart_agc(state);
1094 return 1;
1095 }
1096 }
1097 return 0;
1098}
1099
1100static int dib8000_set_agc_config(struct dib8000_state *state, u8 band)
1101{
1102 struct dibx000_agc_config *agc = NULL;
1103 int i;
Olivier Grenie0c32dbd2011-08-10 05:17:18 -03001104 u16 reg;
1105
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001106 if (state->current_band == band && state->current_agc != NULL)
1107 return 0;
1108 state->current_band = band;
1109
1110 for (i = 0; i < state->cfg.agc_config_count; i++)
1111 if (state->cfg.agc[i].band_caps & band) {
1112 agc = &state->cfg.agc[i];
1113 break;
1114 }
1115
1116 if (agc == NULL) {
1117 dprintk("no valid AGC configuration found for band 0x%02x", band);
1118 return -EINVAL;
1119 }
1120
1121 state->current_agc = agc;
1122
1123 /* AGC */
1124 dib8000_write_word(state, 76, agc->setup);
1125 dib8000_write_word(state, 77, agc->inv_gain);
1126 dib8000_write_word(state, 78, agc->time_stabiliz);
1127 dib8000_write_word(state, 101, (agc->alpha_level << 12) | agc->thlock);
1128
1129 // Demod AGC loop configuration
1130 dib8000_write_word(state, 102, (agc->alpha_mant << 5) | agc->alpha_exp);
1131 dib8000_write_word(state, 103, (agc->beta_mant << 6) | agc->beta_exp);
1132
1133 dprintk("WBD: ref: %d, sel: %d, active: %d, alpha: %d",
1134 state->wbd_ref != 0 ? state->wbd_ref : agc->wbd_ref, agc->wbd_sel, !agc->perform_agc_softsplit, agc->wbd_sel);
1135
1136 /* AGC continued */
1137 if (state->wbd_ref != 0)
1138 dib8000_write_word(state, 106, state->wbd_ref);
1139 else // use default
1140 dib8000_write_word(state, 106, agc->wbd_ref);
Olivier Grenie0c32dbd2011-08-10 05:17:18 -03001141
1142 if (state->revision == 0x8090) {
1143 reg = dib8000_read_word(state, 922) & (0x3 << 2);
1144 dib8000_write_word(state, 922, reg | (agc->wbd_sel << 2));
1145 }
1146
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001147 dib8000_write_word(state, 107, (agc->wbd_alpha << 9) | (agc->perform_agc_softsplit << 8));
1148 dib8000_write_word(state, 108, agc->agc1_max);
1149 dib8000_write_word(state, 109, agc->agc1_min);
1150 dib8000_write_word(state, 110, agc->agc2_max);
1151 dib8000_write_word(state, 111, agc->agc2_min);
1152 dib8000_write_word(state, 112, (agc->agc1_pt1 << 8) | agc->agc1_pt2);
1153 dib8000_write_word(state, 113, (agc->agc1_slope1 << 8) | agc->agc1_slope2);
1154 dib8000_write_word(state, 114, (agc->agc2_pt1 << 8) | agc->agc2_pt2);
1155 dib8000_write_word(state, 115, (agc->agc2_slope1 << 8) | agc->agc2_slope2);
1156
1157 dib8000_write_word(state, 75, agc->agc1_pt3);
Olivier Grenie0c32dbd2011-08-10 05:17:18 -03001158 if (state->revision != 0x8090)
1159 dib8000_write_word(state, 923,
1160 (dib8000_read_word(state, 923) & 0xffe3) |
1161 (agc->wbd_inv << 4) | (agc->wbd_sel << 2));
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001162
1163 return 0;
1164}
1165
Olivier Grenie03245a52009-12-04 13:27:57 -03001166void dib8000_pwm_agc_reset(struct dvb_frontend *fe)
1167{
1168 struct dib8000_state *state = fe->demodulator_priv;
1169 dib8000_set_adc_state(state, DIBX000_ADC_ON);
1170 dib8000_set_agc_config(state, (unsigned char)(BAND_OF_FREQUENCY(fe->dtv_property_cache.frequency / 1000)));
1171}
1172EXPORT_SYMBOL(dib8000_pwm_agc_reset);
1173
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001174static int dib8000_agc_soft_split(struct dib8000_state *state)
1175{
1176 u16 agc, split_offset;
1177
1178 if (!state->current_agc || !state->current_agc->perform_agc_softsplit || state->current_agc->split.max == 0)
1179 return FE_CALLBACK_TIME_NEVER;
1180
1181 // n_agc_global
1182 agc = dib8000_read_word(state, 390);
1183
1184 if (agc > state->current_agc->split.min_thres)
1185 split_offset = state->current_agc->split.min;
1186 else if (agc < state->current_agc->split.max_thres)
1187 split_offset = state->current_agc->split.max;
1188 else
1189 split_offset = state->current_agc->split.max *
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001190 (agc - state->current_agc->split.min_thres) /
1191 (state->current_agc->split.max_thres - state->current_agc->split.min_thres);
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001192
1193 dprintk("AGC split_offset: %d", split_offset);
1194
1195 // P_agc_force_split and P_agc_split_offset
1196 dib8000_write_word(state, 107, (dib8000_read_word(state, 107) & 0xff00) | split_offset);
1197 return 5000;
1198}
1199
1200static int dib8000_agc_startup(struct dvb_frontend *fe)
1201{
1202 struct dib8000_state *state = fe->demodulator_priv;
1203 enum frontend_tune_state *tune_state = &state->tune_state;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001204 int ret = 0;
Olivier Grenie0c32dbd2011-08-10 05:17:18 -03001205 u16 reg, upd_demod_gain_period = 0x8000;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001206
1207 switch (*tune_state) {
1208 case CT_AGC_START:
1209 // set power-up level: interf+analog+AGC
1210
Olivier Grenie0c32dbd2011-08-10 05:17:18 -03001211 if (state->revision != 0x8090)
1212 dib8000_set_adc_state(state, DIBX000_ADC_ON);
1213 else {
1214 dib8000_set_power_mode(state, DIB8000_POWER_ALL);
1215
1216 reg = dib8000_read_word(state, 1947)&0xff00;
1217 dib8000_write_word(state, 1946,
1218 upd_demod_gain_period & 0xFFFF);
1219 /* bit 14 = enDemodGain */
1220 dib8000_write_word(state, 1947, reg | (1<<14) |
1221 ((upd_demod_gain_period >> 16) & 0xFF));
1222
1223 /* enable adc i & q */
1224 reg = dib8000_read_word(state, 1920);
1225 dib8000_write_word(state, 1920, (reg | 0x3) &
1226 (~(1 << 7)));
1227 }
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001228
1229 if (dib8000_set_agc_config(state, (unsigned char)(BAND_OF_FREQUENCY(fe->dtv_property_cache.frequency / 1000))) != 0) {
1230 *tune_state = CT_AGC_STOP;
1231 state->status = FE_STATUS_TUNE_FAILED;
1232 break;
1233 }
1234
1235 ret = 70;
1236 *tune_state = CT_AGC_STEP_0;
1237 break;
1238
1239 case CT_AGC_STEP_0:
1240 //AGC initialization
1241 if (state->cfg.agc_control)
Olivier Grenie4c70e072011-01-03 15:33:37 -03001242 state->cfg.agc_control(fe, 1);
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001243
1244 dib8000_restart_agc(state);
1245
1246 // wait AGC rough lock time
1247 ret = 50;
1248 *tune_state = CT_AGC_STEP_1;
1249 break;
1250
1251 case CT_AGC_STEP_1:
1252 // wait AGC accurate lock time
1253 ret = 70;
1254
1255 if (dib8000_update_lna(state))
1256 // wait only AGC rough lock time
1257 ret = 50;
1258 else
1259 *tune_state = CT_AGC_STEP_2;
1260 break;
1261
1262 case CT_AGC_STEP_2:
1263 dib8000_agc_soft_split(state);
1264
1265 if (state->cfg.agc_control)
Olivier Grenie4c70e072011-01-03 15:33:37 -03001266 state->cfg.agc_control(fe, 0);
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001267
1268 *tune_state = CT_AGC_STOP;
1269 break;
1270 default:
1271 ret = dib8000_agc_soft_split(state);
1272 break;
1273 }
1274 return ret;
1275
1276}
1277
Olivier Grenie0c32dbd2011-08-10 05:17:18 -03001278static void dib8096p_host_bus_drive(struct dib8000_state *state, u8 drive)
1279{
1280 u16 reg;
1281
1282 drive &= 0x7;
1283
1284 /* drive host bus 2, 3, 4 */
1285 reg = dib8000_read_word(state, 1798) &
1286 ~(0x7 | (0x7 << 6) | (0x7 << 12));
1287 reg |= (drive<<12) | (drive<<6) | drive;
1288 dib8000_write_word(state, 1798, reg);
1289
1290 /* drive host bus 5,6 */
1291 reg = dib8000_read_word(state, 1799) & ~((0x7 << 2) | (0x7 << 8));
1292 reg |= (drive<<8) | (drive<<2);
1293 dib8000_write_word(state, 1799, reg);
1294
1295 /* drive host bus 7, 8, 9 */
1296 reg = dib8000_read_word(state, 1800) &
1297 ~(0x7 | (0x7 << 6) | (0x7 << 12));
1298 reg |= (drive<<12) | (drive<<6) | drive;
1299 dib8000_write_word(state, 1800, reg);
1300
1301 /* drive host bus 10, 11 */
1302 reg = dib8000_read_word(state, 1801) & ~((0x7 << 2) | (0x7 << 8));
1303 reg |= (drive<<8) | (drive<<2);
1304 dib8000_write_word(state, 1801, reg);
1305
1306 /* drive host bus 12, 13, 14 */
1307 reg = dib8000_read_word(state, 1802) &
1308 ~(0x7 | (0x7 << 6) | (0x7 << 12));
1309 reg |= (drive<<12) | (drive<<6) | drive;
1310 dib8000_write_word(state, 1802, reg);
1311}
1312
1313static u32 dib8096p_calcSyncFreq(u32 P_Kin, u32 P_Kout,
1314 u32 insertExtSynchro, u32 syncSize)
1315{
1316 u32 quantif = 3;
1317 u32 nom = (insertExtSynchro * P_Kin+syncSize);
1318 u32 denom = P_Kout;
1319 u32 syncFreq = ((nom << quantif) / denom);
1320
1321 if ((syncFreq & ((1 << quantif) - 1)) != 0)
1322 syncFreq = (syncFreq >> quantif) + 1;
1323 else
1324 syncFreq = (syncFreq >> quantif);
1325
1326 if (syncFreq != 0)
1327 syncFreq = syncFreq - 1;
1328
1329 return syncFreq;
1330}
1331
1332static void dib8096p_cfg_DibTx(struct dib8000_state *state, u32 P_Kin,
1333 u32 P_Kout, u32 insertExtSynchro, u32 synchroMode,
1334 u32 syncWord, u32 syncSize)
1335{
1336 dprintk("Configure DibStream Tx");
1337
1338 dib8000_write_word(state, 1615, 1);
1339 dib8000_write_word(state, 1603, P_Kin);
1340 dib8000_write_word(state, 1605, P_Kout);
1341 dib8000_write_word(state, 1606, insertExtSynchro);
1342 dib8000_write_word(state, 1608, synchroMode);
1343 dib8000_write_word(state, 1609, (syncWord >> 16) & 0xffff);
1344 dib8000_write_word(state, 1610, syncWord & 0xffff);
1345 dib8000_write_word(state, 1612, syncSize);
1346 dib8000_write_word(state, 1615, 0);
1347}
1348
1349static void dib8096p_cfg_DibRx(struct dib8000_state *state, u32 P_Kin,
1350 u32 P_Kout, u32 synchroMode, u32 insertExtSynchro,
1351 u32 syncWord, u32 syncSize, u32 dataOutRate)
1352{
1353 u32 syncFreq;
1354
1355 dprintk("Configure DibStream Rx synchroMode = %d", synchroMode);
1356
1357 if ((P_Kin != 0) && (P_Kout != 0)) {
1358 syncFreq = dib8096p_calcSyncFreq(P_Kin, P_Kout,
1359 insertExtSynchro, syncSize);
1360 dib8000_write_word(state, 1542, syncFreq);
1361 }
1362
1363 dib8000_write_word(state, 1554, 1);
1364 dib8000_write_word(state, 1536, P_Kin);
1365 dib8000_write_word(state, 1537, P_Kout);
1366 dib8000_write_word(state, 1539, synchroMode);
1367 dib8000_write_word(state, 1540, (syncWord >> 16) & 0xffff);
1368 dib8000_write_word(state, 1541, syncWord & 0xffff);
1369 dib8000_write_word(state, 1543, syncSize);
1370 dib8000_write_word(state, 1544, dataOutRate);
1371 dib8000_write_word(state, 1554, 0);
1372}
1373
1374static void dib8096p_enMpegMux(struct dib8000_state *state, int onoff)
1375{
1376 u16 reg_1287;
1377
1378 reg_1287 = dib8000_read_word(state, 1287);
1379
1380 switch (onoff) {
1381 case 1:
1382 reg_1287 &= ~(1 << 8);
1383 break;
1384 case 0:
1385 reg_1287 |= (1 << 8);
1386 break;
1387 }
1388
1389 dib8000_write_word(state, 1287, reg_1287);
1390}
1391
1392static void dib8096p_configMpegMux(struct dib8000_state *state,
1393 u16 pulseWidth, u16 enSerialMode, u16 enSerialClkDiv2)
1394{
1395 u16 reg_1287;
1396
1397 dprintk("Enable Mpeg mux");
1398
1399 dib8096p_enMpegMux(state, 0);
1400
1401 /* If the input mode is MPEG do not divide the serial clock */
1402 if ((enSerialMode == 1) && (state->input_mode_mpeg == 1))
1403 enSerialClkDiv2 = 0;
1404
1405 reg_1287 = ((pulseWidth & 0x1f) << 3) |
1406 ((enSerialMode & 0x1) << 2) | (enSerialClkDiv2 & 0x1);
1407 dib8000_write_word(state, 1287, reg_1287);
1408
1409 dib8096p_enMpegMux(state, 1);
1410}
1411
1412static void dib8096p_setDibTxMux(struct dib8000_state *state, int mode)
1413{
1414 u16 reg_1288 = dib8000_read_word(state, 1288) & ~(0x7 << 7);
1415
1416 switch (mode) {
1417 case MPEG_ON_DIBTX:
1418 dprintk("SET MPEG ON DIBSTREAM TX");
1419 dib8096p_cfg_DibTx(state, 8, 5, 0, 0, 0, 0);
1420 reg_1288 |= (1 << 9); break;
1421 case DIV_ON_DIBTX:
1422 dprintk("SET DIV_OUT ON DIBSTREAM TX");
1423 dib8096p_cfg_DibTx(state, 5, 5, 0, 0, 0, 0);
1424 reg_1288 |= (1 << 8); break;
1425 case ADC_ON_DIBTX:
1426 dprintk("SET ADC_OUT ON DIBSTREAM TX");
1427 dib8096p_cfg_DibTx(state, 20, 5, 10, 0, 0, 0);
1428 reg_1288 |= (1 << 7); break;
1429 default:
1430 break;
1431 }
1432 dib8000_write_word(state, 1288, reg_1288);
1433}
1434
1435static void dib8096p_setHostBusMux(struct dib8000_state *state, int mode)
1436{
1437 u16 reg_1288 = dib8000_read_word(state, 1288) & ~(0x7 << 4);
1438
1439 switch (mode) {
1440 case DEMOUT_ON_HOSTBUS:
1441 dprintk("SET DEM OUT OLD INTERF ON HOST BUS");
1442 dib8096p_enMpegMux(state, 0);
1443 reg_1288 |= (1 << 6);
1444 break;
1445 case DIBTX_ON_HOSTBUS:
1446 dprintk("SET DIBSTREAM TX ON HOST BUS");
1447 dib8096p_enMpegMux(state, 0);
1448 reg_1288 |= (1 << 5);
1449 break;
1450 case MPEG_ON_HOSTBUS:
1451 dprintk("SET MPEG MUX ON HOST BUS");
1452 reg_1288 |= (1 << 4);
1453 break;
1454 default:
1455 break;
1456 }
1457 dib8000_write_word(state, 1288, reg_1288);
1458}
1459
1460static int dib8096p_set_diversity_in(struct dvb_frontend *fe, int onoff)
1461{
1462 struct dib8000_state *state = fe->demodulator_priv;
1463 u16 reg_1287;
1464
1465 switch (onoff) {
1466 case 0: /* only use the internal way - not the diversity input */
1467 dprintk("%s mode OFF : by default Enable Mpeg INPUT",
1468 __func__);
1469 /* outputRate = 8 */
1470 dib8096p_cfg_DibRx(state, 8, 5, 0, 0, 0, 8, 0);
1471
1472 /* Do not divide the serial clock of MPEG MUX in
1473 SERIAL MODE in case input mode MPEG is used */
1474 reg_1287 = dib8000_read_word(state, 1287);
1475 /* enSerialClkDiv2 == 1 ? */
1476 if ((reg_1287 & 0x1) == 1) {
1477 /* force enSerialClkDiv2 = 0 */
1478 reg_1287 &= ~0x1;
1479 dib8000_write_word(state, 1287, reg_1287);
1480 }
1481 state->input_mode_mpeg = 1;
1482 break;
1483 case 1: /* both ways */
1484 case 2: /* only the diversity input */
1485 dprintk("%s ON : Enable diversity INPUT", __func__);
1486 dib8096p_cfg_DibRx(state, 5, 5, 0, 0, 0, 0, 0);
1487 state->input_mode_mpeg = 0;
1488 break;
1489 }
1490
1491 dib8000_set_diversity_in(state->fe[0], onoff);
1492 return 0;
1493}
1494
1495static int dib8096p_set_output_mode(struct dvb_frontend *fe, int mode)
1496{
1497 struct dib8000_state *state = fe->demodulator_priv;
1498 u16 outreg, smo_mode, fifo_threshold;
1499 u8 prefer_mpeg_mux_use = 1;
1500 int ret = 0;
1501
Patrick Boettcher173a64c2013-04-22 12:45:52 -03001502 state->output_mode = mode;
Olivier Grenie0c32dbd2011-08-10 05:17:18 -03001503 dib8096p_host_bus_drive(state, 1);
1504
1505 fifo_threshold = 1792;
1506 smo_mode = (dib8000_read_word(state, 299) & 0x0050) | (1 << 1);
1507 outreg = dib8000_read_word(state, 1286) &
1508 ~((1 << 10) | (0x7 << 6) | (1 << 1));
1509
1510 switch (mode) {
1511 case OUTMODE_HIGH_Z:
1512 outreg = 0;
1513 break;
1514
1515 case OUTMODE_MPEG2_SERIAL:
1516 if (prefer_mpeg_mux_use) {
1517 dprintk("dib8096P setting output mode TS_SERIAL using Mpeg Mux");
1518 dib8096p_configMpegMux(state, 3, 1, 1);
1519 dib8096p_setHostBusMux(state, MPEG_ON_HOSTBUS);
1520 } else {/* Use Smooth block */
1521 dprintk("dib8096P setting output mode TS_SERIAL using Smooth bloc");
1522 dib8096p_setHostBusMux(state,
1523 DEMOUT_ON_HOSTBUS);
1524 outreg |= (2 << 6) | (0 << 1);
1525 }
1526 break;
1527
1528 case OUTMODE_MPEG2_PAR_GATED_CLK:
1529 if (prefer_mpeg_mux_use) {
1530 dprintk("dib8096P setting output mode TS_PARALLEL_GATED using Mpeg Mux");
1531 dib8096p_configMpegMux(state, 2, 0, 0);
1532 dib8096p_setHostBusMux(state, MPEG_ON_HOSTBUS);
1533 } else { /* Use Smooth block */
1534 dprintk("dib8096P setting output mode TS_PARALLEL_GATED using Smooth block");
1535 dib8096p_setHostBusMux(state,
1536 DEMOUT_ON_HOSTBUS);
1537 outreg |= (0 << 6);
1538 }
1539 break;
1540
1541 case OUTMODE_MPEG2_PAR_CONT_CLK: /* Using Smooth block only */
1542 dprintk("dib8096P setting output mode TS_PARALLEL_CONT using Smooth block");
1543 dib8096p_setHostBusMux(state, DEMOUT_ON_HOSTBUS);
1544 outreg |= (1 << 6);
1545 break;
1546
1547 case OUTMODE_MPEG2_FIFO:
1548 /* Using Smooth block because not supported
1549 by new Mpeg Mux bloc */
1550 dprintk("dib8096P setting output mode TS_FIFO using Smooth block");
1551 dib8096p_setHostBusMux(state, DEMOUT_ON_HOSTBUS);
1552 outreg |= (5 << 6);
1553 smo_mode |= (3 << 1);
1554 fifo_threshold = 512;
1555 break;
1556
1557 case OUTMODE_DIVERSITY:
1558 dprintk("dib8096P setting output mode MODE_DIVERSITY");
1559 dib8096p_setDibTxMux(state, DIV_ON_DIBTX);
1560 dib8096p_setHostBusMux(state, DIBTX_ON_HOSTBUS);
1561 break;
1562
1563 case OUTMODE_ANALOG_ADC:
1564 dprintk("dib8096P setting output mode MODE_ANALOG_ADC");
1565 dib8096p_setDibTxMux(state, ADC_ON_DIBTX);
1566 dib8096p_setHostBusMux(state, DIBTX_ON_HOSTBUS);
1567 break;
1568 }
1569
1570 if (mode != OUTMODE_HIGH_Z)
1571 outreg |= (1<<10);
1572
1573 dprintk("output_mpeg2_in_188_bytes = %d",
1574 state->cfg.output_mpeg2_in_188_bytes);
1575 if (state->cfg.output_mpeg2_in_188_bytes)
1576 smo_mode |= (1 << 5);
1577
1578 ret |= dib8000_write_word(state, 299, smo_mode);
1579 /* synchronous fread */
1580 ret |= dib8000_write_word(state, 299 + 1, fifo_threshold);
1581 ret |= dib8000_write_word(state, 1286, outreg);
1582
1583 return ret;
1584}
1585
1586static int map_addr_to_serpar_number(struct i2c_msg *msg)
1587{
1588 if (msg->buf[0] <= 15)
1589 msg->buf[0] -= 1;
1590 else if (msg->buf[0] == 17)
1591 msg->buf[0] = 15;
1592 else if (msg->buf[0] == 16)
1593 msg->buf[0] = 17;
1594 else if (msg->buf[0] == 19)
1595 msg->buf[0] = 16;
1596 else if (msg->buf[0] >= 21 && msg->buf[0] <= 25)
1597 msg->buf[0] -= 3;
1598 else if (msg->buf[0] == 28)
1599 msg->buf[0] = 23;
1600 else if (msg->buf[0] == 99)
1601 msg->buf[0] = 99;
1602 else
1603 return -EINVAL;
1604 return 0;
1605}
1606
1607static int dib8096p_tuner_write_serpar(struct i2c_adapter *i2c_adap,
1608 struct i2c_msg msg[], int num)
1609{
1610 struct dib8000_state *state = i2c_get_adapdata(i2c_adap);
1611 u8 n_overflow = 1;
1612 u16 i = 1000;
1613 u16 serpar_num = msg[0].buf[0];
1614
1615 while (n_overflow == 1 && i) {
1616 n_overflow = (dib8000_read_word(state, 1984) >> 1) & 0x1;
1617 i--;
1618 if (i == 0)
1619 dprintk("Tuner ITF: write busy (overflow)");
1620 }
1621 dib8000_write_word(state, 1985, (1 << 6) | (serpar_num & 0x3f));
1622 dib8000_write_word(state, 1986, (msg[0].buf[1] << 8) | msg[0].buf[2]);
1623
1624 return num;
1625}
1626
1627static int dib8096p_tuner_read_serpar(struct i2c_adapter *i2c_adap,
1628 struct i2c_msg msg[], int num)
1629{
1630 struct dib8000_state *state = i2c_get_adapdata(i2c_adap);
1631 u8 n_overflow = 1, n_empty = 1;
1632 u16 i = 1000;
1633 u16 serpar_num = msg[0].buf[0];
1634 u16 read_word;
1635
1636 while (n_overflow == 1 && i) {
1637 n_overflow = (dib8000_read_word(state, 1984) >> 1) & 0x1;
1638 i--;
1639 if (i == 0)
1640 dprintk("TunerITF: read busy (overflow)");
1641 }
1642 dib8000_write_word(state, 1985, (0<<6) | (serpar_num&0x3f));
1643
1644 i = 1000;
1645 while (n_empty == 1 && i) {
1646 n_empty = dib8000_read_word(state, 1984)&0x1;
1647 i--;
1648 if (i == 0)
1649 dprintk("TunerITF: read busy (empty)");
1650 }
1651
1652 read_word = dib8000_read_word(state, 1987);
1653 msg[1].buf[0] = (read_word >> 8) & 0xff;
1654 msg[1].buf[1] = (read_word) & 0xff;
1655
1656 return num;
1657}
1658
1659static int dib8096p_tuner_rw_serpar(struct i2c_adapter *i2c_adap,
1660 struct i2c_msg msg[], int num)
1661{
1662 if (map_addr_to_serpar_number(&msg[0]) == 0) {
1663 if (num == 1) /* write */
1664 return dib8096p_tuner_write_serpar(i2c_adap, msg, 1);
1665 else /* read */
1666 return dib8096p_tuner_read_serpar(i2c_adap, msg, 2);
1667 }
1668 return num;
1669}
1670
1671static int dib8096p_rw_on_apb(struct i2c_adapter *i2c_adap,
1672 struct i2c_msg msg[], int num, u16 apb_address)
1673{
1674 struct dib8000_state *state = i2c_get_adapdata(i2c_adap);
1675 u16 word;
1676
1677 if (num == 1) { /* write */
1678 dib8000_write_word(state, apb_address,
1679 ((msg[0].buf[1] << 8) | (msg[0].buf[2])));
1680 } else {
1681 word = dib8000_read_word(state, apb_address);
1682 msg[1].buf[0] = (word >> 8) & 0xff;
1683 msg[1].buf[1] = (word) & 0xff;
1684 }
1685 return num;
1686}
1687
1688static int dib8096p_tuner_xfer(struct i2c_adapter *i2c_adap,
1689 struct i2c_msg msg[], int num)
1690{
1691 struct dib8000_state *state = i2c_get_adapdata(i2c_adap);
1692 u16 apb_address = 0, word;
1693 int i = 0;
1694
1695 switch (msg[0].buf[0]) {
1696 case 0x12:
1697 apb_address = 1920;
1698 break;
1699 case 0x14:
1700 apb_address = 1921;
1701 break;
1702 case 0x24:
1703 apb_address = 1922;
1704 break;
1705 case 0x1a:
1706 apb_address = 1923;
1707 break;
1708 case 0x22:
1709 apb_address = 1924;
1710 break;
1711 case 0x33:
1712 apb_address = 1926;
1713 break;
1714 case 0x34:
1715 apb_address = 1927;
1716 break;
1717 case 0x35:
1718 apb_address = 1928;
1719 break;
1720 case 0x36:
1721 apb_address = 1929;
1722 break;
1723 case 0x37:
1724 apb_address = 1930;
1725 break;
1726 case 0x38:
1727 apb_address = 1931;
1728 break;
1729 case 0x39:
1730 apb_address = 1932;
1731 break;
1732 case 0x2a:
1733 apb_address = 1935;
1734 break;
1735 case 0x2b:
1736 apb_address = 1936;
1737 break;
1738 case 0x2c:
1739 apb_address = 1937;
1740 break;
1741 case 0x2d:
1742 apb_address = 1938;
1743 break;
1744 case 0x2e:
1745 apb_address = 1939;
1746 break;
1747 case 0x2f:
1748 apb_address = 1940;
1749 break;
1750 case 0x30:
1751 apb_address = 1941;
1752 break;
1753 case 0x31:
1754 apb_address = 1942;
1755 break;
1756 case 0x32:
1757 apb_address = 1943;
1758 break;
1759 case 0x3e:
1760 apb_address = 1944;
1761 break;
1762 case 0x3f:
1763 apb_address = 1945;
1764 break;
1765 case 0x40:
1766 apb_address = 1948;
1767 break;
1768 case 0x25:
1769 apb_address = 936;
1770 break;
1771 case 0x26:
1772 apb_address = 937;
1773 break;
1774 case 0x27:
1775 apb_address = 938;
1776 break;
1777 case 0x28:
1778 apb_address = 939;
1779 break;
1780 case 0x1d:
1781 /* get sad sel request */
1782 i = ((dib8000_read_word(state, 921) >> 12)&0x3);
1783 word = dib8000_read_word(state, 924+i);
1784 msg[1].buf[0] = (word >> 8) & 0xff;
1785 msg[1].buf[1] = (word) & 0xff;
1786 return num;
1787 case 0x1f:
1788 if (num == 1) { /* write */
1789 word = (u16) ((msg[0].buf[1] << 8) |
1790 msg[0].buf[2]);
1791 /* in the VGAMODE Sel are located on bit 0/1 */
1792 word &= 0x3;
1793 word = (dib8000_read_word(state, 921) &
1794 ~(3<<12)) | (word<<12);
1795 /* Set the proper input */
1796 dib8000_write_word(state, 921, word);
1797 return num;
1798 }
1799 }
1800
1801 if (apb_address != 0) /* R/W acces via APB */
1802 return dib8096p_rw_on_apb(i2c_adap, msg, num, apb_address);
1803 else /* R/W access via SERPAR */
1804 return dib8096p_tuner_rw_serpar(i2c_adap, msg, num);
1805
1806 return 0;
1807}
1808
1809static u32 dib8096p_i2c_func(struct i2c_adapter *adapter)
1810{
1811 return I2C_FUNC_I2C;
1812}
1813
1814static struct i2c_algorithm dib8096p_tuner_xfer_algo = {
1815 .master_xfer = dib8096p_tuner_xfer,
1816 .functionality = dib8096p_i2c_func,
1817};
1818
1819struct i2c_adapter *dib8096p_get_i2c_tuner(struct dvb_frontend *fe)
1820{
1821 struct dib8000_state *st = fe->demodulator_priv;
1822 return &st->dib8096p_tuner_adap;
1823}
1824EXPORT_SYMBOL(dib8096p_get_i2c_tuner);
1825
1826int dib8096p_tuner_sleep(struct dvb_frontend *fe, int onoff)
1827{
1828 struct dib8000_state *state = fe->demodulator_priv;
1829 u16 en_cur_state;
1830
1831 dprintk("sleep dib8096p: %d", onoff);
1832
1833 en_cur_state = dib8000_read_word(state, 1922);
1834
1835 /* LNAs and MIX are ON and therefore it is a valid configuration */
1836 if (en_cur_state > 0xff)
1837 state->tuner_enable = en_cur_state ;
1838
1839 if (onoff)
1840 en_cur_state &= 0x00ff;
1841 else {
1842 if (state->tuner_enable != 0)
1843 en_cur_state = state->tuner_enable;
1844 }
1845
1846 dib8000_write_word(state, 1922, en_cur_state);
1847
1848 return 0;
1849}
1850EXPORT_SYMBOL(dib8096p_tuner_sleep);
1851
Olivier Grenie4c70e072011-01-03 15:33:37 -03001852static const s32 lut_1000ln_mant[] =
Olivier Grenie03245a52009-12-04 13:27:57 -03001853{
Olivier Grenie9c783032009-12-07 07:49:40 -03001854 908, 7003, 7090, 7170, 7244, 7313, 7377, 7438, 7495, 7549, 7600
Olivier Grenie03245a52009-12-04 13:27:57 -03001855};
1856
Olivier Grenie4c70e072011-01-03 15:33:37 -03001857s32 dib8000_get_adc_power(struct dvb_frontend *fe, u8 mode)
Olivier Grenie03245a52009-12-04 13:27:57 -03001858{
Olivier Grenie4c70e072011-01-03 15:33:37 -03001859 struct dib8000_state *state = fe->demodulator_priv;
1860 u32 ix = 0, tmp_val = 0, exp = 0, mant = 0;
1861 s32 val;
Olivier Grenie03245a52009-12-04 13:27:57 -03001862
Olivier Grenie4c70e072011-01-03 15:33:37 -03001863 val = dib8000_read32(state, 384);
Olivier Grenie4c70e072011-01-03 15:33:37 -03001864 if (mode) {
1865 tmp_val = val;
1866 while (tmp_val >>= 1)
1867 exp++;
1868 mant = (val * 1000 / (1<<exp));
1869 ix = (u8)((mant-1000)/100); /* index of the LUT */
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001870 val = (lut_1000ln_mant[ix] + 693*(exp-20) - 6908);
Olivier Grenie4c70e072011-01-03 15:33:37 -03001871 val = (val*256)/1000;
1872 }
1873 return val;
Olivier Grenie03245a52009-12-04 13:27:57 -03001874}
1875EXPORT_SYMBOL(dib8000_get_adc_power);
1876
Olivier Grenie0c32dbd2011-08-10 05:17:18 -03001877int dib8090p_get_dc_power(struct dvb_frontend *fe, u8 IQ)
1878{
1879 struct dib8000_state *state = fe->demodulator_priv;
1880 int val = 0;
1881
1882 switch (IQ) {
1883 case 1:
1884 val = dib8000_read_word(state, 403);
1885 break;
1886 case 0:
1887 val = dib8000_read_word(state, 404);
1888 break;
1889 }
1890 if (val & 0x200)
1891 val -= 1024;
1892
1893 return val;
1894}
1895EXPORT_SYMBOL(dib8090p_get_dc_power);
1896
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001897static void dib8000_update_timf(struct dib8000_state *state)
1898{
1899 u32 timf = state->timf = dib8000_read32(state, 435);
1900
1901 dib8000_write_word(state, 29, (u16) (timf >> 16));
1902 dib8000_write_word(state, 30, (u16) (timf & 0xffff));
1903 dprintk("Updated timing frequency: %d (default: %d)", state->timf, state->timf_default);
1904}
1905
Olivier Grenie0c32dbd2011-08-10 05:17:18 -03001906u32 dib8000_ctrl_timf(struct dvb_frontend *fe, uint8_t op, uint32_t timf)
1907{
1908 struct dib8000_state *state = fe->demodulator_priv;
1909
1910 switch (op) {
1911 case DEMOD_TIMF_SET:
1912 state->timf = timf;
1913 break;
1914 case DEMOD_TIMF_UPDATE:
1915 dib8000_update_timf(state);
1916 break;
1917 case DEMOD_TIMF_GET:
1918 break;
1919 }
1920 dib8000_set_bandwidth(state->fe[0], 6000);
1921
1922 return state->timf;
1923}
1924EXPORT_SYMBOL(dib8000_ctrl_timf);
1925
Olivier Grenie5a0deee2011-05-03 12:27:33 -03001926static const u16 adc_target_16dB[11] = {
1927 (1 << 13) - 825 - 117,
1928 (1 << 13) - 837 - 117,
1929 (1 << 13) - 811 - 117,
1930 (1 << 13) - 766 - 117,
1931 (1 << 13) - 737 - 117,
1932 (1 << 13) - 693 - 117,
1933 (1 << 13) - 648 - 117,
1934 (1 << 13) - 619 - 117,
1935 (1 << 13) - 575 - 117,
1936 (1 << 13) - 531 - 117,
1937 (1 << 13) - 501 - 117
1938};
1939static const u8 permu_seg[] = { 6, 5, 7, 4, 8, 3, 9, 2, 10, 1, 11, 0, 12 };
1940
Patrick Boettcher173a64c2013-04-22 12:45:52 -03001941static u16 dib8000_set_layer(struct dib8000_state *state, u8 layer_index, u16 max_constellation)
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001942{
Patrick Boettcher173a64c2013-04-22 12:45:52 -03001943 u8 cr, constellation, time_intlv;
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03001944 struct dtv_frontend_properties *c = &state->fe[0]->dtv_property_cache;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001945
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03001946 switch (c->layer[layer_index].modulation) {
Patrick Boettcher173a64c2013-04-22 12:45:52 -03001947 case DQPSK:
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001948 constellation = 0;
1949 break;
Patrick Boettcher173a64c2013-04-22 12:45:52 -03001950 case QPSK:
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001951 constellation = 1;
1952 break;
Patrick Boettcher173a64c2013-04-22 12:45:52 -03001953 case QAM_16:
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001954 constellation = 2;
1955 break;
Patrick Boettcher173a64c2013-04-22 12:45:52 -03001956 case QAM_64:
1957 default:
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001958 constellation = 3;
1959 break;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001960 }
1961
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03001962 switch (c->layer[layer_index].fec) {
Patrick Boettcher173a64c2013-04-22 12:45:52 -03001963 case FEC_1_2:
1964 cr = 1;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001965 break;
Patrick Boettcher173a64c2013-04-22 12:45:52 -03001966 case FEC_2_3:
1967 cr = 2;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001968 break;
Patrick Boettcher173a64c2013-04-22 12:45:52 -03001969 case FEC_3_4:
1970 cr = 3;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001971 break;
Patrick Boettcher173a64c2013-04-22 12:45:52 -03001972 case FEC_5_6:
1973 cr = 5;
1974 break;
1975 case FEC_7_8:
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001976 default:
Patrick Boettcher173a64c2013-04-22 12:45:52 -03001977 cr = 7;
1978 break;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001979 }
Patrick Boettcher173a64c2013-04-22 12:45:52 -03001980
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03001981 if ((c->layer[layer_index].interleaving > 0) && ((c->layer[layer_index].interleaving <= 3) || (c->layer[layer_index].interleaving == 4 && c->isdbt_sb_mode == 1)))
1982 time_intlv = c->layer[layer_index].interleaving;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001983 else
Patrick Boettcher173a64c2013-04-22 12:45:52 -03001984 time_intlv = 0;
1985
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03001986 dib8000_write_word(state, 2 + layer_index, (constellation << 10) | ((c->layer[layer_index].segment_count & 0xf) << 6) | (cr << 3) | time_intlv);
1987 if (c->layer[layer_index].segment_count > 0) {
Patrick Boettcher173a64c2013-04-22 12:45:52 -03001988 switch (max_constellation) {
1989 case DQPSK:
1990 case QPSK:
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03001991 if (c->layer[layer_index].modulation == QAM_16 || c->layer[layer_index].modulation == QAM_64)
1992 max_constellation = c->layer[layer_index].modulation;
Patrick Boettcher173a64c2013-04-22 12:45:52 -03001993 break;
1994 case QAM_16:
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03001995 if (c->layer[layer_index].modulation == QAM_64)
1996 max_constellation = c->layer[layer_index].modulation;
Patrick Boettcher173a64c2013-04-22 12:45:52 -03001997 break;
1998 }
1999 }
2000
2001 return max_constellation;
2002}
2003
2004static 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 */
2005static 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 */
2006static 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 */
2007static u16 dib8000_adp_fine_tune(struct dib8000_state *state, u16 max_constellation)
2008{
2009 u16 i, ana_gain = 0;
2010 const u16 *adp;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002011
2012 /* channel estimation fine configuration */
2013 switch (max_constellation) {
2014 case QAM_64:
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002015 ana_gain = 0x7;
2016 adp = &adp_Q64[0];
2017 break;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002018 case QAM_16:
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002019 ana_gain = 0x7;
2020 adp = &adp_Q16[0];
2021 break;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002022 default:
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002023 ana_gain = 0;
2024 adp = &adp_Qdefault[0];
2025 break;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002026 }
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002027
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002028 for (i = 0; i < 4; i++)
2029 dib8000_write_word(state, 215 + i, adp[i]);
2030
2031 return ana_gain;
2032}
2033
2034static void dib8000_update_ana_gain(struct dib8000_state *state, u16 ana_gain)
2035{
2036 u16 i;
2037
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002038 dib8000_write_word(state, 116, ana_gain);
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002039
2040 /* update ADC target depending on ana_gain */
2041 if (ana_gain) { /* set -16dB ADC target for ana_gain=-1 */
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002042 for (i = 0; i < 10; i++)
2043 dib8000_write_word(state, 80 + i, adc_target_16dB[i]);
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002044 } else { /* set -22dB ADC target for ana_gain=0 */
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002045 for (i = 0; i < 10; i++)
2046 dib8000_write_word(state, 80 + i, adc_target_16dB[i] - 355);
2047 }
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002048}
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002049
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002050static void dib8000_load_ana_fe_coefs(struct dib8000_state *state, const s16 *ana_fe)
2051{
2052 u16 mode = 0;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002053
2054 if (state->isdbt_cfg_loaded == 0)
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002055 for (mode = 0; mode < 24; mode++)
2056 dib8000_write_word(state, 117 + mode, ana_fe[mode]);
2057}
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002058
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002059static const u16 lut_prbs_2k[14] = {
2060 0, 0x423, 0x009, 0x5C7, 0x7A6, 0x3D8, 0x527, 0x7FF, 0x79B, 0x3D6, 0x3A2, 0x53B, 0x2F4, 0x213
2061};
2062static const u16 lut_prbs_4k[14] = {
2063 0, 0x208, 0x0C3, 0x7B9, 0x423, 0x5C7, 0x3D8, 0x7FF, 0x3D6, 0x53B, 0x213, 0x029, 0x0D0, 0x48E
2064};
2065static const u16 lut_prbs_8k[14] = {
2066 0, 0x740, 0x069, 0x7DD, 0x208, 0x7B9, 0x5C7, 0x7FF, 0x53B, 0x029, 0x48E, 0x4C4, 0x367, 0x684
2067};
2068
2069static u16 dib8000_get_init_prbs(struct dib8000_state *state, u16 subchannel)
2070{
2071 int sub_channel_prbs_group = 0;
2072
2073 sub_channel_prbs_group = (subchannel / 3) + 1;
2074 dprintk("sub_channel_prbs_group = %d , subchannel =%d prbs = 0x%04x", sub_channel_prbs_group, subchannel, lut_prbs_8k[sub_channel_prbs_group]);
2075
2076 switch (state->fe[0]->dtv_property_cache.transmission_mode) {
2077 case TRANSMISSION_MODE_2K:
2078 return lut_prbs_2k[sub_channel_prbs_group];
2079 case TRANSMISSION_MODE_4K:
2080 return lut_prbs_4k[sub_channel_prbs_group];
2081 default:
2082 case TRANSMISSION_MODE_8K:
2083 return lut_prbs_8k[sub_channel_prbs_group];
2084 }
2085}
2086
2087static void dib8000_set_13seg_channel(struct dib8000_state *state)
2088{
2089 u16 i;
2090 u16 coff_pow = 0x2800;
2091
2092 state->seg_mask = 0x1fff; /* All 13 segments enabled */
2093
2094 /* ---- COFF ---- Carloff, the most robust --- */
2095 if (state->isdbt_cfg_loaded == 0) { /* if not Sound Broadcasting mode : put default values for 13 segments */
2096 dib8000_write_word(state, 180, (16 << 6) | 9);
2097 dib8000_write_word(state, 187, (4 << 12) | (8 << 5) | 0x2);
2098 coff_pow = 0x2800;
2099 for (i = 0; i < 6; i++)
2100 dib8000_write_word(state, 181+i, coff_pow);
2101
2102 /* P_ctrl_corm_thres4pre_freq_inh=1, P_ctrl_pre_freq_mode_sat=1 */
2103 /* 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 */
2104 dib8000_write_word(state, 338, (1 << 12) | (1 << 10) | (0 << 9) | (3 << 5) | 1);
2105
2106 /* P_ctrl_pre_freq_win_len=8, P_ctrl_pre_freq_thres_lockin=6 */
2107 dib8000_write_word(state, 340, (8 << 6) | (6 << 0));
2108 /* P_ctrl_pre_freq_thres_lockout=4, P_small_use_tmcc/ac/cp=1 */
2109 dib8000_write_word(state, 341, (4 << 3) | (1 << 2) | (1 << 1) | (1 << 0));
2110
2111 dib8000_write_word(state, 228, 0); /* default value */
2112 dib8000_write_word(state, 265, 31); /* default value */
2113 dib8000_write_word(state, 205, 0x200f); /* init value */
2114 }
2115
2116 /*
2117 * make the cpil_coff_lock more robust but slower p_coff_winlen
2118 * 6bits; p_coff_thres_lock 6bits (for coff lock if needed)
2119 */
2120
2121 if (state->cfg.pll->ifreq == 0)
2122 dib8000_write_word(state, 266, ~state->seg_mask | state->seg_diff_mask | 0x40); /* P_equal_noise_seg_inh */
2123
2124 dib8000_load_ana_fe_coefs(state, ana_fe_coeff_13seg);
2125}
2126
2127static void dib8000_set_subchannel_prbs(struct dib8000_state *state, u16 init_prbs)
2128{
2129 u16 reg_1;
2130
2131 reg_1 = dib8000_read_word(state, 1);
2132 dib8000_write_word(state, 1, (init_prbs << 2) | (reg_1 & 0x3)); /* ADDR 1 */
2133}
2134
2135static void dib8000_small_fine_tune(struct dib8000_state *state)
2136{
2137 u16 i;
2138 const s16 *ncoeff;
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03002139 struct dtv_frontend_properties *c = &state->fe[0]->dtv_property_cache;
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002140
2141 dib8000_write_word(state, 352, state->seg_diff_mask);
2142 dib8000_write_word(state, 353, state->seg_mask);
2143
2144 /* 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 -03002145 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 -03002146
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03002147 if (c->isdbt_sb_mode) {
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002148 /* ---- SMALL ---- */
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03002149 switch (c->transmission_mode) {
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002150 case TRANSMISSION_MODE_2K:
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03002151 if (c->isdbt_partial_reception == 0) { /* 1-seg */
2152 if (c->layer[0].modulation == DQPSK) /* DQPSK */
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002153 ncoeff = coeff_2k_sb_1seg_dqpsk;
2154 else /* QPSK or QAM */
2155 ncoeff = coeff_2k_sb_1seg;
2156 } else { /* 3-segments */
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03002157 if (c->layer[0].modulation == DQPSK) { /* DQPSK on central segment */
2158 if (c->layer[1].modulation == DQPSK) /* DQPSK on external segments */
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002159 ncoeff = coeff_2k_sb_3seg_0dqpsk_1dqpsk;
2160 else /* QPSK or QAM on external segments */
2161 ncoeff = coeff_2k_sb_3seg_0dqpsk;
2162 } else { /* QPSK or QAM on central segment */
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03002163 if (c->layer[1].modulation == DQPSK) /* DQPSK on external segments */
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002164 ncoeff = coeff_2k_sb_3seg_1dqpsk;
2165 else /* QPSK or QAM on external segments */
2166 ncoeff = coeff_2k_sb_3seg;
2167 }
2168 }
2169 break;
2170 case TRANSMISSION_MODE_4K:
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03002171 if (c->isdbt_partial_reception == 0) { /* 1-seg */
2172 if (c->layer[0].modulation == DQPSK) /* DQPSK */
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002173 ncoeff = coeff_4k_sb_1seg_dqpsk;
2174 else /* QPSK or QAM */
2175 ncoeff = coeff_4k_sb_1seg;
2176 } else { /* 3-segments */
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03002177 if (c->layer[0].modulation == DQPSK) { /* DQPSK on central segment */
2178 if (c->layer[1].modulation == DQPSK) /* DQPSK on external segments */
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002179 ncoeff = coeff_4k_sb_3seg_0dqpsk_1dqpsk;
2180 else /* QPSK or QAM on external segments */
2181 ncoeff = coeff_4k_sb_3seg_0dqpsk;
2182 } else { /* QPSK or QAM on central segment */
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03002183 if (c->layer[1].modulation == DQPSK) /* DQPSK on external segments */
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002184 ncoeff = coeff_4k_sb_3seg_1dqpsk;
2185 else /* QPSK or QAM on external segments */
2186 ncoeff = coeff_4k_sb_3seg;
2187 }
2188 }
2189 break;
2190 case TRANSMISSION_MODE_AUTO:
2191 case TRANSMISSION_MODE_8K:
2192 default:
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03002193 if (c->isdbt_partial_reception == 0) { /* 1-seg */
2194 if (c->layer[0].modulation == DQPSK) /* DQPSK */
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002195 ncoeff = coeff_8k_sb_1seg_dqpsk;
2196 else /* QPSK or QAM */
2197 ncoeff = coeff_8k_sb_1seg;
2198 } else { /* 3-segments */
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03002199 if (c->layer[0].modulation == DQPSK) { /* DQPSK on central segment */
2200 if (c->layer[1].modulation == DQPSK) /* DQPSK on external segments */
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002201 ncoeff = coeff_8k_sb_3seg_0dqpsk_1dqpsk;
2202 else /* QPSK or QAM on external segments */
2203 ncoeff = coeff_8k_sb_3seg_0dqpsk;
2204 } else { /* QPSK or QAM on central segment */
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03002205 if (c->layer[1].modulation == DQPSK) /* DQPSK on external segments */
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002206 ncoeff = coeff_8k_sb_3seg_1dqpsk;
2207 else /* QPSK or QAM on external segments */
2208 ncoeff = coeff_8k_sb_3seg;
2209 }
2210 }
2211 break;
2212 }
2213
2214 for (i = 0; i < 8; i++)
2215 dib8000_write_word(state, 343 + i, ncoeff[i]);
2216 }
2217}
2218
2219static const u16 coff_thres_1seg[3] = {300, 150, 80};
2220static const u16 coff_thres_3seg[3] = {350, 300, 250};
2221static void dib8000_set_sb_channel(struct dib8000_state *state)
2222{
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03002223 struct dtv_frontend_properties *c = &state->fe[0]->dtv_property_cache;
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002224 const u16 *coff;
2225 u16 i;
2226
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03002227 if (c->transmission_mode == TRANSMISSION_MODE_2K || c->transmission_mode == TRANSMISSION_MODE_4K) {
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002228 dib8000_write_word(state, 219, dib8000_read_word(state, 219) | 0x1); /* adp_pass =1 */
2229 dib8000_write_word(state, 190, dib8000_read_word(state, 190) | (0x1 << 14)); /* pha3_force_pha_shift = 1 */
2230 } else {
2231 dib8000_write_word(state, 219, dib8000_read_word(state, 219) & 0xfffe); /* adp_pass =0 */
2232 dib8000_write_word(state, 190, dib8000_read_word(state, 190) & 0xbfff); /* pha3_force_pha_shift = 0 */
2233 }
2234
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03002235 if (c->isdbt_partial_reception == 1) /* 3-segments */
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002236 state->seg_mask = 0x00E0;
2237 else /* 1-segment */
2238 state->seg_mask = 0x0040;
2239
2240 dib8000_write_word(state, 268, (dib8000_read_word(state, 268) & 0xF9FF) | 0x0200);
2241
2242 /* ---- COFF ---- Carloff, the most robust --- */
2243 /* 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 -03002244 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 -03002245
2246 dib8000_write_word(state, 340, (16 << 6) | (8 << 0)); /* P_ctrl_pre_freq_win_len=16, P_ctrl_pre_freq_thres_lockin=8 */
2247 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 */
2248
2249 /* Sound Broadcasting mode 1 seg */
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03002250 if (c->isdbt_partial_reception == 0) {
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002251 /* 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) */
2252 if (state->mode == 3)
2253 dib8000_write_word(state, 180, 0x1fcf | ((state->mode - 1) << 14));
2254 else
2255 dib8000_write_word(state, 180, 0x0fcf | ((state->mode - 1) << 14));
2256
2257 /* 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 */
2258 dib8000_write_word(state, 338, (1 << 12) | (1 << 10) | (0 << 9) | (5 << 5) | 4);
2259 coff = &coff_thres_1seg[0];
2260 } else { /* Sound Broadcasting mode 3 seg */
2261 dib8000_write_word(state, 180, 0x1fcf | (1 << 14));
2262 /* 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 */
2263 dib8000_write_word(state, 338, (1 << 12) | (1 << 10) | (0 << 9) | (4 << 5) | 4);
2264 coff = &coff_thres_3seg[0];
2265 }
2266
2267 dib8000_write_word(state, 228, 1); /* P_2d_mode_byp=1 */
2268 dib8000_write_word(state, 205, dib8000_read_word(state, 205) & 0xfff0); /* P_cspu_win_cut = 0 */
2269
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03002270 if (c->isdbt_partial_reception == 0 && c->transmission_mode == TRANSMISSION_MODE_2K)
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002271 dib8000_write_word(state, 265, 15); /* P_equal_noise_sel = 15 */
2272
2273 /* Write COFF thres */
2274 for (i = 0 ; i < 3; i++) {
2275 dib8000_write_word(state, 181+i, coff[i]);
2276 dib8000_write_word(state, 184+i, coff[i]);
2277 }
2278
2279 /*
2280 * make the cpil_coff_lock more robust but slower p_coff_winlen
2281 * 6bits; p_coff_thres_lock 6bits (for coff lock if needed)
2282 */
2283
2284 dib8000_write_word(state, 266, ~state->seg_mask | state->seg_diff_mask); /* P_equal_noise_seg_inh */
2285
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03002286 if (c->isdbt_partial_reception == 0)
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002287 dib8000_write_word(state, 178, 64); /* P_fft_powrange = 64 */
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002288 else
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002289 dib8000_write_word(state, 178, 32); /* P_fft_powrange = 32 */
2290}
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002291
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002292static void dib8000_set_isdbt_common_channel(struct dib8000_state *state, u8 seq, u8 autosearching)
2293{
2294 u16 p_cfr_left_edge = 0, p_cfr_right_edge = 0;
2295 u16 tmcc_pow = 0, ana_gain = 0, tmp = 0, i = 0, nbseg_diff = 0 ;
2296 u16 max_constellation = DQPSK;
2297 int init_prbs;
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03002298 struct dtv_frontend_properties *c = &state->fe[0]->dtv_property_cache;
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002299
2300 /* P_mode */
2301 dib8000_write_word(state, 10, (seq << 4));
2302
2303 /* init mode */
2304 state->mode = fft_to_mode(state);
2305
2306 /* set guard */
2307 tmp = dib8000_read_word(state, 1);
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03002308 dib8000_write_word(state, 1, (tmp&0xfffc) | (c->guard_interval & 0x3));
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002309
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03002310 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 -03002311
2312 /* signal optimization parameter */
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03002313 if (c->isdbt_partial_reception) {
2314 state->seg_diff_mask = (c->layer[0].modulation == DQPSK) << permu_seg[0];
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002315 for (i = 1; i < 3; i++)
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03002316 nbseg_diff += (c->layer[i].modulation == DQPSK) * c->layer[i].segment_count;
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002317 for (i = 0; i < nbseg_diff; i++)
2318 state->seg_diff_mask |= 1 << permu_seg[i+1];
2319 } else {
2320 for (i = 0; i < 3; i++)
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03002321 nbseg_diff += (c->layer[i].modulation == DQPSK) * c->layer[i].segment_count;
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002322 for (i = 0; i < nbseg_diff; i++)
2323 state->seg_diff_mask |= 1 << permu_seg[i];
2324 }
2325
2326 if (state->seg_diff_mask)
2327 dib8000_write_word(state, 268, (dib8000_read_word(state, 268) & 0xF9FF) | 0x0200);
2328 else
2329 dib8000_write_word(state, 268, (2 << 9) | 39); /*init value */
2330
2331 for (i = 0; i < 3; i++)
2332 max_constellation = dib8000_set_layer(state, i, max_constellation);
2333 if (autosearching == 0) {
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03002334 state->layer_b_nb_seg = c->layer[1].segment_count;
2335 state->layer_c_nb_seg = c->layer[2].segment_count;
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002336 }
2337
2338 /* WRITE: Mode & Diff mask */
2339 dib8000_write_word(state, 0, (state->mode << 13) | state->seg_diff_mask);
2340
2341 state->differential_constellation = (state->seg_diff_mask != 0);
2342
2343 /* channel estimation fine configuration */
2344 ana_gain = dib8000_adp_fine_tune(state, max_constellation);
2345
2346 /* update ana_gain depending on max constellation */
2347 dib8000_update_ana_gain(state, ana_gain);
2348
2349 /* ---- ANA_FE ---- */
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03002350 if (c->isdbt_partial_reception) /* 3-segments */
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002351 dib8000_load_ana_fe_coefs(state, ana_fe_coeff_3seg);
2352 else
2353 dib8000_load_ana_fe_coefs(state, ana_fe_coeff_1seg); /* 1-segment */
2354
2355 /* TSB or ISDBT ? apply it now */
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03002356 if (c->isdbt_sb_mode) {
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002357 dib8000_set_sb_channel(state);
Mauro Carvalho Chehab746f7ae2013-04-25 11:15:54 -03002358 if (c->isdbt_sb_subchannel < 14)
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03002359 init_prbs = dib8000_get_init_prbs(state, c->isdbt_sb_subchannel);
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002360 else
2361 init_prbs = 0;
2362 } else {
2363 dib8000_set_13seg_channel(state);
2364 init_prbs = 0xfff;
2365 }
2366
2367 /* SMALL */
2368 dib8000_small_fine_tune(state);
2369
2370 dib8000_set_subchannel_prbs(state, init_prbs);
2371
2372 /* ---- CHAN_BLK ---- */
2373 for (i = 0; i < 13; i++) {
2374 if ((((~state->seg_diff_mask) >> i) & 1) == 1) {
2375 p_cfr_left_edge += (1 << i) * ((i == 0) || ((((state->seg_mask & (~state->seg_diff_mask)) >> (i - 1)) & 1) == 0));
2376 p_cfr_right_edge += (1 << i) * ((i == 12) || ((((state->seg_mask & (~state->seg_diff_mask)) >> (i + 1)) & 1) == 0));
2377 }
2378 }
2379 dib8000_write_word(state, 222, p_cfr_left_edge); /* p_cfr_left_edge */
2380 dib8000_write_word(state, 223, p_cfr_right_edge); /* p_cfr_right_edge */
2381 /* "P_cspu_left_edge" & "P_cspu_right_edge" not used => do not care */
2382
2383 dib8000_write_word(state, 189, ~state->seg_mask | state->seg_diff_mask); /* P_lmod4_seg_inh */
2384 dib8000_write_word(state, 192, ~state->seg_mask | state->seg_diff_mask); /* P_pha3_seg_inh */
2385 dib8000_write_word(state, 225, ~state->seg_mask | state->seg_diff_mask); /* P_tac_seg_inh */
2386
2387 if (!autosearching)
2388 dib8000_write_word(state, 288, (~state->seg_mask | state->seg_diff_mask) & 0x1fff); /* P_tmcc_seg_eq_inh */
2389 else
2390 dib8000_write_word(state, 288, 0x1fff); /*disable equalisation of the tmcc when autosearch to be able to find the DQPSK channels. */
2391
2392 dib8000_write_word(state, 211, state->seg_mask & (~state->seg_diff_mask)); /* P_des_seg_enabled */
2393 dib8000_write_word(state, 287, ~state->seg_mask | 0x1000); /* P_tmcc_seg_inh */
2394
2395 dib8000_write_word(state, 178, 32); /* P_fft_powrange = 32 */
2396
2397 /* ---- TMCC ---- */
2398 for (i = 0; i < 3; i++)
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03002399 tmcc_pow += (((c->layer[i].modulation == DQPSK) * 4 + 1) * c->layer[i].segment_count) ;
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002400
2401 /* Quantif of "P_tmcc_dec_thres_?k" is (0, 5+mode, 9); */
2402 /* Threshold is set at 1/4 of max power. */
2403 tmcc_pow *= (1 << (9-2));
2404 dib8000_write_word(state, 290, tmcc_pow); /* P_tmcc_dec_thres_2k */
2405 dib8000_write_word(state, 291, tmcc_pow); /* P_tmcc_dec_thres_4k */
2406 dib8000_write_word(state, 292, tmcc_pow); /* P_tmcc_dec_thres_8k */
2407 /*dib8000_write_word(state, 287, (1 << 13) | 0x1000 ); */
2408
2409 /* ---- PHA3 ---- */
2410 if (state->isdbt_cfg_loaded == 0)
2411 dib8000_write_word(state, 250, 3285); /* p_2d_hspeed_thr0 */
2412
2413 state->isdbt_cfg_loaded = 0;
2414}
2415
Mauro Carvalho Chehab6f7ee062013-04-25 10:36:56 -03002416static u32 dib8000_wait_lock(struct dib8000_state *state, u32 internal,
2417 u32 wait0_ms, u32 wait1_ms, u32 wait2_ms)
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002418{
Mauro Carvalho Chehab13122f92013-04-25 15:22:20 -03002419 u32 value = 0; /* P_search_end0 wait time */
2420 u16 reg = 11; /* P_search_end0 start addr */
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002421
2422 for (reg = 11; reg < 16; reg += 2) {
2423 if (reg == 11) {
2424 if (state->revision == 0x8090)
Mauro Carvalho Chehab13122f92013-04-25 15:22:20 -03002425 value = internal * wait1_ms;
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002426 else
Mauro Carvalho Chehab13122f92013-04-25 15:22:20 -03002427 value = internal * wait0_ms;
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002428 } else if (reg == 13)
Mauro Carvalho Chehab13122f92013-04-25 15:22:20 -03002429 value = internal * wait1_ms;
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002430 else if (reg == 15)
Mauro Carvalho Chehab13122f92013-04-25 15:22:20 -03002431 value = internal * wait2_ms;
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002432 dib8000_write_word(state, reg, (u16)((value >> 16) & 0xffff));
2433 dib8000_write_word(state, (reg + 1), (u16)(value & 0xffff));
2434 }
2435 return value;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002436}
2437
2438static int dib8000_autosearch_start(struct dvb_frontend *fe)
2439{
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002440 struct dib8000_state *state = fe->demodulator_priv;
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03002441 struct dtv_frontend_properties *c = &state->fe[0]->dtv_property_cache;
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002442 u8 slist = 0;
2443 u32 value, internal = state->cfg.pll->internal;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002444
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002445 if (state->revision == 0x8090)
2446 internal = dib8000_read32(state, 23) / 1000;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002447
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002448 if (state->autosearch_state == AS_SEARCHING_FFT) {
2449 dib8000_write_word(state, 37, 0x0065); /* P_ctrl_pha_off_max default values */
2450 dib8000_write_word(state, 116, 0x0000); /* P_ana_gain to 0 */
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002451
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002452 dib8000_write_word(state, 0, (dib8000_read_word(state, 0) & 0x1fff) | (0 << 13) | (1 << 15)); /* P_mode = 0, P_restart_search=1 */
2453 dib8000_write_word(state, 1, (dib8000_read_word(state, 1) & 0xfffc) | 0); /* P_guard = 0 */
2454 dib8000_write_word(state, 6, 0); /* P_lock0_mask = 0 */
2455 dib8000_write_word(state, 7, 0); /* P_lock1_mask = 0 */
2456 dib8000_write_word(state, 8, 0); /* P_lock2_mask = 0 */
2457 dib8000_write_word(state, 10, (dib8000_read_word(state, 10) & 0x200) | (16 << 4) | (0 << 0)); /* P_search_list=16, P_search_maxtrial=0 */
2458
2459 if (state->revision == 0x8090)
2460 value = dib8000_wait_lock(state, internal, 10, 10, 10); /* time in ms configure P_search_end0 P_search_end1 P_search_end2 */
2461 else
2462 value = dib8000_wait_lock(state, internal, 20, 20, 20); /* time in ms configure P_search_end0 P_search_end1 P_search_end2 */
2463
2464 dib8000_write_word(state, 17, 0);
2465 dib8000_write_word(state, 18, 200); /* P_search_rstst = 200 */
2466 dib8000_write_word(state, 19, 0);
2467 dib8000_write_word(state, 20, 400); /* P_search_rstend = 400 */
2468 dib8000_write_word(state, 21, (value >> 16) & 0xffff); /* P_search_checkst */
2469 dib8000_write_word(state, 22, value & 0xffff);
2470
2471 if (state->revision == 0x8090)
2472 dib8000_write_word(state, 32, (dib8000_read_word(state, 32) & 0xf0ff) | (0 << 8)); /* P_corm_alpha = 0 */
2473 else
2474 dib8000_write_word(state, 32, (dib8000_read_word(state, 32) & 0xf0ff) | (9 << 8)); /* P_corm_alpha = 3 */
2475 dib8000_write_word(state, 355, 2); /* P_search_param_max = 2 */
2476
2477 /* P_search_param_select = (1 | 1<<4 | 1 << 8) */
2478 dib8000_write_word(state, 356, 0);
2479 dib8000_write_word(state, 357, 0x111);
2480
2481 dib8000_write_word(state, 770, (dib8000_read_word(state, 770) & 0xdfff) | (1 << 13)); /* P_restart_ccg = 1 */
2482 dib8000_write_word(state, 770, (dib8000_read_word(state, 770) & 0xdfff) | (0 << 13)); /* P_restart_ccg = 0 */
2483 dib8000_write_word(state, 0, (dib8000_read_word(state, 0) & 0x7ff) | (0 << 15) | (1 << 13)); /* P_restart_search = 0; */
2484 } else if (state->autosearch_state == AS_SEARCHING_GUARD) {
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03002485 c->transmission_mode = TRANSMISSION_MODE_8K;
2486 c->guard_interval = GUARD_INTERVAL_1_8;
2487 c->inversion = 0;
2488 c->layer[0].modulation = QAM_64;
2489 c->layer[0].fec = FEC_2_3;
2490 c->layer[0].interleaving = 0;
2491 c->layer[0].segment_count = 13;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002492
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002493 slist = 16;
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03002494 c->transmission_mode = state->found_nfft;
Patrick Boettcher78f3bc62009-08-17 12:53:51 -03002495
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002496 dib8000_set_isdbt_common_channel(state, slist, 1);
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002497
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002498 /* set lock_mask values */
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002499 dib8000_write_word(state, 6, 0x4);
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002500 if (state->revision == 0x8090)
2501 dib8000_write_word(state, 7, ((1 << 12) | (1 << 11) | (1 << 10)));/* tmcc_dec_lock, tmcc_sync_lock, tmcc_data_lock, tmcc_bch_uncor */
2502 else
2503 dib8000_write_word(state, 7, 0x8);
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002504 dib8000_write_word(state, 8, 0x1000);
2505
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002506 /* set lock_mask wait time values */
2507 if (state->revision == 0x8090)
2508 dib8000_wait_lock(state, internal, 50, 100, 1000); /* time in ms configure P_search_end0 P_search_end1 P_search_end2 */
2509 else
2510 dib8000_wait_lock(state, internal, 50, 200, 1000); /* time in ms configure P_search_end0 P_search_end1 P_search_end2 */
2511
2512 dib8000_write_word(state, 355, 3); /* P_search_param_max = 3 */
2513
2514 /* P_search_param_select = 0xf; look for the 4 different guard intervals */
2515 dib8000_write_word(state, 356, 0);
2516 dib8000_write_word(state, 357, 0xf);
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002517
2518 value = dib8000_read_word(state, 0);
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002519 dib8000_write_word(state, 0, (u16)((1 << 15) | value));
2520 dib8000_read_word(state, 1284); /* reset the INT. n_irq_pending */
2521 dib8000_write_word(state, 0, (u16)value);
2522 } else {
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03002523 c->inversion = 0;
2524 c->layer[0].modulation = QAM_64;
2525 c->layer[0].fec = FEC_2_3;
2526 c->layer[0].interleaving = 0;
2527 c->layer[0].segment_count = 13;
2528 if (!c->isdbt_sb_mode)
2529 c->layer[0].segment_count = 13;
Patrick Boettcher78f3bc62009-08-17 12:53:51 -03002530
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002531 /* choose the right list, in sb, always do everything */
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03002532 if (c->isdbt_sb_mode) {
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002533 slist = 7;
2534 dib8000_write_word(state, 0, (dib8000_read_word(state, 0) & 0x9fff) | (1 << 13));
2535 } else {
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03002536 if (c->guard_interval == GUARD_INTERVAL_AUTO) {
2537 if (c->transmission_mode == TRANSMISSION_MODE_AUTO) {
2538 c->transmission_mode = TRANSMISSION_MODE_8K;
2539 c->guard_interval = GUARD_INTERVAL_1_8;
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002540 slist = 7;
2541 dib8000_write_word(state, 0, (dib8000_read_word(state, 0) & 0x9fff) | (1 << 13)); /* P_mode = 1 to have autosearch start ok with mode2 */
2542 } else {
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03002543 c->guard_interval = GUARD_INTERVAL_1_8;
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002544 slist = 3;
2545 }
2546 } else {
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03002547 if (c->transmission_mode == TRANSMISSION_MODE_AUTO) {
2548 c->transmission_mode = TRANSMISSION_MODE_8K;
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002549 slist = 2;
2550 dib8000_write_word(state, 0, (dib8000_read_word(state, 0) & 0x9fff) | (1 << 13)); /* P_mode = 1 */
2551 } else
2552 slist = 0;
2553 }
2554 }
2555 dprintk("Using list for autosearch : %d", slist);
2556
2557 dib8000_set_isdbt_common_channel(state, slist, 1);
2558
2559 /* set lock_mask values */
2560 dib8000_write_word(state, 6, 0x4);
2561 if (state->revision == 0x8090)
2562 dib8000_write_word(state, 7, (1 << 12) | (1 << 11) | (1 << 10));
2563 else
2564 dib8000_write_word(state, 7, 0x8);
2565 dib8000_write_word(state, 8, 0x1000);
2566
2567 /* set lock_mask wait time values */
2568 if (state->revision == 0x8090)
2569 dib8000_wait_lock(state, internal, 50, 200, 1000); /* time in ms configure P_search_end0 P_search_end1 P_search_end2 */
2570 else
2571 dib8000_wait_lock(state, internal, 50, 100, 1000); /* time in ms configure P_search_end0 P_search_end1 P_search_end2 */
2572
2573 value = dib8000_read_word(state, 0);
2574 dib8000_write_word(state, 0, (u16)((1 << 15) | value));
2575 dib8000_read_word(state, 1284); /* reset the INT. n_irq_pending */
2576 dib8000_write_word(state, 0, (u16)value);
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002577 }
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002578 return 0;
2579}
2580
2581static int dib8000_autosearch_irq(struct dvb_frontend *fe)
2582{
2583 struct dib8000_state *state = fe->demodulator_priv;
2584 u16 irq_pending = dib8000_read_word(state, 1284);
2585
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002586 if (state->autosearch_state == AS_SEARCHING_FFT) {
2587 if (irq_pending & 0x1) {
2588 dprintk("dib8000_autosearch_irq: max correlation result available");
2589 return 3;
2590 }
2591 } else {
2592 if (irq_pending & 0x1) { /* failed */
2593 dprintk("dib8000_autosearch_irq failed");
2594 return 1;
2595 }
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002596
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002597 if (irq_pending & 0x2) { /* succeeded */
2598 dprintk("dib8000_autosearch_irq succeeded");
2599 return 2;
2600 }
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002601 }
2602
2603 return 0; // still pending
2604}
2605
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002606static void dib8000_viterbi_state(struct dib8000_state *state, u8 onoff)
2607{
2608 u16 tmp;
2609
2610 tmp = dib8000_read_word(state, 771);
2611 if (onoff) /* start P_restart_chd : channel_decoder */
2612 dib8000_write_word(state, 771, tmp & 0xfffd);
2613 else /* stop P_restart_chd : channel_decoder */
2614 dib8000_write_word(state, 771, tmp | (1<<1));
2615}
2616
2617static void dib8000_set_dds(struct dib8000_state *state, s32 offset_khz)
2618{
2619 s16 unit_khz_dds_val;
2620 u32 abs_offset_khz = ABS(offset_khz);
2621 u32 dds = state->cfg.pll->ifreq & 0x1ffffff;
2622 u8 invert = !!(state->cfg.pll->ifreq & (1 << 25));
2623 u8 ratio;
2624
2625 if (state->revision == 0x8090) {
2626 ratio = 4;
2627 unit_khz_dds_val = (1<<26) / (dib8000_read32(state, 23) / 1000);
2628 if (offset_khz < 0)
2629 dds = (1 << 26) - (abs_offset_khz * unit_khz_dds_val);
2630 else
2631 dds = (abs_offset_khz * unit_khz_dds_val);
2632
2633 if (invert)
2634 dds = (1<<26) - dds;
2635 } else {
2636 ratio = 2;
2637 unit_khz_dds_val = (u16) (67108864 / state->cfg.pll->internal);
2638
2639 if (offset_khz < 0)
2640 unit_khz_dds_val *= -1;
2641
2642 /* IF tuner */
2643 if (invert)
2644 dds -= abs_offset_khz * unit_khz_dds_val;
2645 else
2646 dds += abs_offset_khz * unit_khz_dds_val;
2647 }
2648
2649 dprintk("setting a DDS frequency offset of %c%dkHz", invert ? '-' : ' ', dds / unit_khz_dds_val);
2650
2651 if (abs_offset_khz <= (state->cfg.pll->internal / ratio)) {
2652 /* Max dds offset is the half of the demod freq */
2653 dib8000_write_word(state, 26, invert);
2654 dib8000_write_word(state, 27, (u16)(dds >> 16) & 0x1ff);
2655 dib8000_write_word(state, 28, (u16)(dds & 0xffff));
2656 }
2657}
2658
2659static void dib8000_set_frequency_offset(struct dib8000_state *state)
2660{
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03002661 struct dtv_frontend_properties *c = &state->fe[0]->dtv_property_cache;
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002662 int i;
2663 u32 current_rf;
2664 int total_dds_offset_khz;
2665
2666 if (state->fe[0]->ops.tuner_ops.get_frequency)
2667 state->fe[0]->ops.tuner_ops.get_frequency(state->fe[0], &current_rf);
2668 else
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03002669 current_rf = c->frequency;
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002670 current_rf /= 1000;
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03002671 total_dds_offset_khz = (int)current_rf - (int)c->frequency / 1000;
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002672
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03002673 if (c->isdbt_sb_mode) {
2674 state->subchannel = c->isdbt_sb_subchannel;
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002675
2676 i = dib8000_read_word(state, 26) & 1; /* P_dds_invspec */
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03002677 dib8000_write_word(state, 26, c->inversion ^ i);
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002678
2679 if (state->cfg.pll->ifreq == 0) { /* low if tuner */
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03002680 if ((c->inversion ^ i) == 0)
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002681 dib8000_write_word(state, 26, dib8000_read_word(state, 26) | 1);
2682 } else {
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03002683 if ((c->inversion ^ i) == 0)
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002684 total_dds_offset_khz *= -1;
2685 }
2686 }
2687
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03002688 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 -03002689
2690 /* apply dds offset now */
2691 dib8000_set_dds(state, total_dds_offset_khz);
2692}
2693
2694static u16 LUT_isdbt_symbol_duration[4] = { 26, 101, 63 };
Mauro Carvalho Chehab6f7ee062013-04-25 10:36:56 -03002695
2696static u32 dib8000_get_symbol_duration(struct dib8000_state *state)
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002697{
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03002698 struct dtv_frontend_properties *c = &state->fe[0]->dtv_property_cache;
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002699 u16 i;
2700
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03002701 switch (c->transmission_mode) {
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002702 case TRANSMISSION_MODE_2K:
2703 i = 0;
2704 break;
2705 case TRANSMISSION_MODE_4K:
2706 i = 2;
2707 break;
2708 default:
2709 case TRANSMISSION_MODE_AUTO:
2710 case TRANSMISSION_MODE_8K:
2711 i = 1;
2712 break;
2713 }
2714
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03002715 return (LUT_isdbt_symbol_duration[i] / (c->bandwidth_hz / 1000)) + 1;
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002716}
2717
2718static void dib8000_set_isdbt_loop_params(struct dib8000_state *state, enum param_loop_step loop_step)
2719{
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03002720 struct dtv_frontend_properties *c = &state->fe[0]->dtv_property_cache;
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002721 u16 reg_32 = 0, reg_37 = 0;
2722
2723 switch (loop_step) {
2724 case LOOP_TUNE_1:
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03002725 if (c->isdbt_sb_mode) {
2726 if (c->isdbt_partial_reception == 0) {
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002727 reg_32 = ((11 - state->mode) << 12) | (6 << 8) | 0x40; /* P_timf_alpha = (11-P_mode), P_corm_alpha=6, P_corm_thres=0x40 */
2728 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) */
2729 } else { /* Sound Broadcasting mode 3 seg */
2730 reg_32 = ((10 - state->mode) << 12) | (6 << 8) | 0x60; /* P_timf_alpha = (10-P_mode), P_corm_alpha=6, P_corm_thres=0x60 */
2731 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) */
2732 }
2733 } else { /* 13-seg start conf offset loop parameters */
2734 reg_32 = ((9 - state->mode) << 12) | (6 << 8) | 0x80; /* P_timf_alpha = (9-P_mode, P_corm_alpha=6, P_corm_thres=0x80 */
2735 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 */
2736 }
2737 break;
2738 case LOOP_TUNE_2:
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03002739 if (c->isdbt_sb_mode) {
2740 if (c->isdbt_partial_reception == 0) { /* Sound Broadcasting mode 1 seg */
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002741 reg_32 = ((13-state->mode) << 12) | (6 << 8) | 0x40; /* P_timf_alpha = (13-P_mode) , P_corm_alpha=6, P_corm_thres=0x40*/
2742 reg_37 = (12-state->mode) | ((5 + state->mode) << 5);
2743 } else { /* Sound Broadcasting mode 3 seg */
2744 reg_32 = ((12-state->mode) << 12) | (6 << 8) | 0x60; /* P_timf_alpha = (12-P_mode) , P_corm_alpha=6, P_corm_thres=0x60 */
2745 reg_37 = (11-state->mode) | ((5 + state->mode) << 5);
2746 }
2747 } else { /* 13 seg */
2748 reg_32 = ((11-state->mode) << 12) | (6 << 8) | 0x80; /* P_timf_alpha = 8 , P_corm_alpha=6, P_corm_thres=0x80 */
2749 reg_37 = ((5+state->mode) << 5) | (10 - state->mode);
2750 }
2751 break;
2752 }
2753 dib8000_write_word(state, 32, reg_32);
2754 dib8000_write_word(state, 37, reg_37);
2755}
2756
2757static void dib8000_demod_restart(struct dib8000_state *state)
2758{
2759 dib8000_write_word(state, 770, 0x4000);
2760 dib8000_write_word(state, 770, 0x0000);
2761 return;
2762}
2763
2764static void dib8000_set_sync_wait(struct dib8000_state *state)
2765{
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03002766 struct dtv_frontend_properties *c = &state->fe[0]->dtv_property_cache;
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002767 u16 sync_wait = 64;
2768
2769 /* P_dvsy_sync_wait - reuse mode */
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03002770 switch (c->transmission_mode) {
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002771 case TRANSMISSION_MODE_8K:
2772 sync_wait = 256;
2773 break;
2774 case TRANSMISSION_MODE_4K:
2775 sync_wait = 128;
2776 break;
2777 default:
2778 case TRANSMISSION_MODE_2K:
2779 sync_wait = 64;
2780 break;
2781 }
2782
2783 if (state->cfg.diversity_delay == 0)
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03002784 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 -03002785 else
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03002786 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 -03002787
2788 dib8000_write_word(state, 273, (dib8000_read_word(state, 273) & 0x000f) | (sync_wait << 4));
2789}
2790
2791static u32 dib8000_get_timeout(struct dib8000_state *state, u32 delay, enum timeout_mode mode)
2792{
2793 if (mode == SYMBOL_DEPENDENT_ON)
2794 return systime() + (delay * state->symbol_duration);
2795 else
2796 return systime() + delay;
2797}
2798
2799static s32 dib8000_get_status(struct dvb_frontend *fe)
2800{
2801 struct dib8000_state *state = fe->demodulator_priv;
2802 return state->status;
2803}
2804
2805enum frontend_tune_state dib8000_get_tune_state(struct dvb_frontend *fe)
2806{
2807 struct dib8000_state *state = fe->demodulator_priv;
2808 return state->tune_state;
2809}
2810EXPORT_SYMBOL(dib8000_get_tune_state);
2811
2812int dib8000_set_tune_state(struct dvb_frontend *fe, enum frontend_tune_state tune_state)
2813{
2814 struct dib8000_state *state = fe->demodulator_priv;
2815
2816 state->tune_state = tune_state;
2817 return 0;
2818}
2819EXPORT_SYMBOL(dib8000_set_tune_state);
2820
2821static int dib8000_tune_restart_from_demod(struct dvb_frontend *fe)
2822{
2823 struct dib8000_state *state = fe->demodulator_priv;
2824
2825 state->status = FE_STATUS_TUNE_PENDING;
2826 state->tune_state = CT_DEMOD_START;
2827 return 0;
2828}
2829
2830static u16 dib8000_read_lock(struct dvb_frontend *fe)
2831{
2832 struct dib8000_state *state = fe->demodulator_priv;
2833
2834 if (state->revision == 0x8090)
2835 return dib8000_read_word(state, 570);
2836 return dib8000_read_word(state, 568);
2837}
2838
2839static int dib8090p_init_sdram(struct dib8000_state *state)
2840{
2841 u16 reg = 0;
2842 dprintk("init sdram");
2843
2844 reg = dib8000_read_word(state, 274) & 0xfff0;
2845 dib8000_write_word(state, 274, reg | 0x7); /* P_dintlv_delay_ram = 7 because of MobileSdram */
2846
2847 dib8000_write_word(state, 1803, (7 << 2));
2848
2849 reg = dib8000_read_word(state, 1280);
2850 dib8000_write_word(state, 1280, reg | (1 << 2)); /* force restart P_restart_sdram */
2851 dib8000_write_word(state, 1280, reg); /* release restart P_restart_sdram */
2852
2853 return 0;
2854}
2855
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002856static int dib8000_tune(struct dvb_frontend *fe)
2857{
2858 struct dib8000_state *state = fe->demodulator_priv;
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03002859 struct dtv_frontend_properties *c = &state->fe[0]->dtv_property_cache;
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002860 enum frontend_tune_state *tune_state = &state->tune_state;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002861
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002862 u16 locks, deeper_interleaver = 0, i;
2863 int ret = 1; /* 1 symbol duration (in 100us unit) delay most of the time */
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002864
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002865 u32 *timeout = &state->timeout;
2866 u32 now = systime();
2867#ifdef DIB8000_AGC_FREEZE
2868 u16 agc1, agc2;
2869#endif
Dan Carpentere04f4b22012-07-20 07:11:57 -03002870
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002871 u32 corm[4] = {0, 0, 0, 0};
2872 u8 find_index, max_value;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002873
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002874#if 0
2875 if (*tune_state < CT_DEMOD_STOP)
2876 dprintk("IN: context status = %d, TUNE_STATE %d autosearch step = %u systime = %u", state->channel_parameters_set, *tune_state, state->autosearch_state, now);
2877#endif
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002878
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002879 switch (*tune_state) {
2880 case CT_DEMOD_START: /* 30 */
2881 if (state->revision == 0x8090)
2882 dib8090p_init_sdram(state);
2883 state->status = FE_STATUS_TUNE_PENDING;
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03002884 if ((c->delivery_system != SYS_ISDBT) ||
2885 (c->inversion == INVERSION_AUTO) ||
2886 (c->transmission_mode == TRANSMISSION_MODE_AUTO) ||
2887 (c->guard_interval == GUARD_INTERVAL_AUTO) ||
2888 (((c->isdbt_layer_enabled & (1 << 0)) != 0) &&
2889 (c->layer[0].segment_count != 0xff) &&
2890 (c->layer[0].segment_count != 0) &&
2891 ((c->layer[0].modulation == QAM_AUTO) ||
2892 (c->layer[0].fec == FEC_AUTO))) ||
2893 (((c->isdbt_layer_enabled & (1 << 1)) != 0) &&
2894 (c->layer[1].segment_count != 0xff) &&
2895 (c->layer[1].segment_count != 0) &&
2896 ((c->layer[1].modulation == QAM_AUTO) ||
2897 (c->layer[1].fec == FEC_AUTO))) ||
2898 (((c->isdbt_layer_enabled & (1 << 2)) != 0) &&
2899 (c->layer[2].segment_count != 0xff) &&
2900 (c->layer[2].segment_count != 0) &&
2901 ((c->layer[2].modulation == QAM_AUTO) ||
2902 (c->layer[2].fec == FEC_AUTO))) ||
2903 (((c->layer[0].segment_count == 0) ||
2904 ((c->isdbt_layer_enabled & (1 << 0)) == 0)) &&
2905 ((c->layer[1].segment_count == 0) ||
2906 ((c->isdbt_layer_enabled & (2 << 0)) == 0)) &&
2907 ((c->layer[2].segment_count == 0) || ((c->isdbt_layer_enabled & (3 << 0)) == 0))))
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002908 state->channel_parameters_set = 0; /* auto search */
2909 else
2910 state->channel_parameters_set = 1; /* channel parameters are known */
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002911
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002912 dib8000_viterbi_state(state, 0); /* force chan dec in restart */
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002913
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002914 /* Layer monit */
2915 dib8000_write_word(state, 285, dib8000_read_word(state, 285) & 0x60);
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002916
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002917 dib8000_set_frequency_offset(state);
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03002918 dib8000_set_bandwidth(fe, c->bandwidth_hz / 1000);
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002919
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002920 if (state->channel_parameters_set == 0) { /* The channel struct is unknown, search it ! */
2921#ifdef DIB8000_AGC_FREEZE
2922 if (state->revision != 0x8090) {
2923 state->agc1_max = dib8000_read_word(state, 108);
2924 state->agc1_min = dib8000_read_word(state, 109);
2925 state->agc2_max = dib8000_read_word(state, 110);
2926 state->agc2_min = dib8000_read_word(state, 111);
2927 agc1 = dib8000_read_word(state, 388);
2928 agc2 = dib8000_read_word(state, 389);
2929 dib8000_write_word(state, 108, agc1);
2930 dib8000_write_word(state, 109, agc1);
2931 dib8000_write_word(state, 110, agc2);
2932 dib8000_write_word(state, 111, agc2);
2933 }
2934#endif
2935 state->autosearch_state = AS_SEARCHING_FFT;
2936 state->found_nfft = TRANSMISSION_MODE_AUTO;
2937 state->found_guard = GUARD_INTERVAL_AUTO;
2938 *tune_state = CT_DEMOD_SEARCH_NEXT;
2939 } else { /* we already know the channel struct so TUNE only ! */
2940 state->autosearch_state = AS_DONE;
2941 *tune_state = CT_DEMOD_STEP_3;
2942 }
2943 state->symbol_duration = dib8000_get_symbol_duration(state);
2944 break;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002945
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002946 case CT_DEMOD_SEARCH_NEXT: /* 51 */
2947 dib8000_autosearch_start(fe);
2948 if (state->revision == 0x8090)
2949 ret = 50;
2950 else
2951 ret = 15;
2952 *tune_state = CT_DEMOD_STEP_1;
2953 break;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002954
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002955 case CT_DEMOD_STEP_1: /* 31 */
2956 switch (dib8000_autosearch_irq(fe)) {
2957 case 1: /* fail */
2958 state->status = FE_STATUS_TUNE_FAILED;
2959 state->autosearch_state = AS_DONE;
2960 *tune_state = CT_DEMOD_STOP; /* else we are done here */
2961 break;
2962 case 2: /* Succes */
2963 state->status = FE_STATUS_FFT_SUCCESS; /* signal to the upper layer, that there was a channel found and the parameters can be read */
2964 *tune_state = CT_DEMOD_STEP_3;
2965 if (state->autosearch_state == AS_SEARCHING_GUARD)
2966 *tune_state = CT_DEMOD_STEP_2;
2967 else
2968 state->autosearch_state = AS_DONE;
2969 break;
2970 case 3: /* Autosearch FFT max correlation endded */
2971 *tune_state = CT_DEMOD_STEP_2;
2972 break;
2973 }
2974 break;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002975
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002976 case CT_DEMOD_STEP_2:
2977 switch (state->autosearch_state) {
2978 case AS_SEARCHING_FFT:
2979 /* searching for the correct FFT */
2980 if (state->revision == 0x8090) {
2981 corm[2] = (dib8000_read_word(state, 596) << 16) | (dib8000_read_word(state, 597));
2982 corm[1] = (dib8000_read_word(state, 598) << 16) | (dib8000_read_word(state, 599));
2983 corm[0] = (dib8000_read_word(state, 600) << 16) | (dib8000_read_word(state, 601));
2984 } else {
2985 corm[2] = (dib8000_read_word(state, 594) << 16) | (dib8000_read_word(state, 595));
2986 corm[1] = (dib8000_read_word(state, 596) << 16) | (dib8000_read_word(state, 597));
2987 corm[0] = (dib8000_read_word(state, 598) << 16) | (dib8000_read_word(state, 599));
2988 }
2989 /* dprintk("corm fft: %u %u %u", corm[0], corm[1], corm[2]); */
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002990
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002991 max_value = 0;
2992 for (find_index = 1 ; find_index < 3 ; find_index++) {
2993 if (corm[max_value] < corm[find_index])
2994 max_value = find_index ;
2995 }
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002996
Patrick Boettcher173a64c2013-04-22 12:45:52 -03002997 switch (max_value) {
2998 case 0:
2999 state->found_nfft = TRANSMISSION_MODE_2K;
3000 break;
3001 case 1:
3002 state->found_nfft = TRANSMISSION_MODE_4K;
3003 break;
3004 case 2:
3005 default:
3006 state->found_nfft = TRANSMISSION_MODE_8K;
3007 break;
3008 }
3009 /* dprintk("Autosearch FFT has found Mode %d", max_value + 1); */
3010
3011 *tune_state = CT_DEMOD_SEARCH_NEXT;
3012 state->autosearch_state = AS_SEARCHING_GUARD;
3013 if (state->revision == 0x8090)
3014 ret = 50;
3015 else
3016 ret = 10;
3017 break;
3018 case AS_SEARCHING_GUARD:
3019 /* searching for the correct guard interval */
3020 if (state->revision == 0x8090)
3021 state->found_guard = dib8000_read_word(state, 572) & 0x3;
3022 else
3023 state->found_guard = dib8000_read_word(state, 570) & 0x3;
3024 /* dprintk("guard interval found=%i", state->found_guard); */
3025
3026 *tune_state = CT_DEMOD_STEP_3;
3027 break;
3028 default:
3029 /* the demod should never be in this state */
3030 state->status = FE_STATUS_TUNE_FAILED;
3031 state->autosearch_state = AS_DONE;
3032 *tune_state = CT_DEMOD_STOP; /* else we are done here */
3033 break;
3034 }
3035 break;
3036
3037 case CT_DEMOD_STEP_3: /* 33 */
3038 state->symbol_duration = dib8000_get_symbol_duration(state);
3039 dib8000_set_isdbt_loop_params(state, LOOP_TUNE_1);
3040 dib8000_set_isdbt_common_channel(state, 0, 0);/* setting the known channel parameters here */
3041 *tune_state = CT_DEMOD_STEP_4;
3042 break;
3043
3044 case CT_DEMOD_STEP_4: /* (34) */
3045 dib8000_demod_restart(state);
3046
3047 dib8000_set_sync_wait(state);
3048 dib8000_set_diversity_in(state->fe[0], state->diversity_onoff);
3049
3050 locks = (dib8000_read_word(state, 180) >> 6) & 0x3f; /* P_coff_winlen ? */
3051 /* coff should lock over P_coff_winlen ofdm symbols : give 3 times this lenght to lock */
3052 *timeout = dib8000_get_timeout(state, 2 * locks, SYMBOL_DEPENDENT_ON);
3053 *tune_state = CT_DEMOD_STEP_5;
3054 break;
3055
3056 case CT_DEMOD_STEP_5: /* (35) */
3057 locks = dib8000_read_lock(fe);
3058 if (locks & (0x3 << 11)) { /* coff-lock and off_cpil_lock achieved */
3059 dib8000_update_timf(state); /* we achieved a coff_cpil_lock - it's time to update the timf */
3060 if (!state->differential_constellation) {
3061 /* 2 times lmod4_win_len + 10 symbols (pipe delay after coff + nb to compute a 1st correlation) */
3062 *timeout = dib8000_get_timeout(state, (20 * ((dib8000_read_word(state, 188)>>5)&0x1f)), SYMBOL_DEPENDENT_ON);
3063 *tune_state = CT_DEMOD_STEP_7;
3064 } else {
3065 *tune_state = CT_DEMOD_STEP_8;
3066 }
3067 } else if (now > *timeout) {
3068 *tune_state = CT_DEMOD_STEP_6; /* goto check for diversity input connection */
3069 }
3070 break;
3071
3072 case CT_DEMOD_STEP_6: /* (36) if there is an input (diversity) */
3073 if ((state->fe[1] != NULL) && (state->output_mode != OUTMODE_DIVERSITY)) {
3074 /* 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 */
3075 if (dib8000_get_status(state->fe[1]) <= FE_STATUS_STD_SUCCESS) /* Something is locked on the input fe */
3076 *tune_state = CT_DEMOD_STEP_8; /* go for mpeg */
3077 else if (dib8000_get_status(state->fe[1]) >= FE_STATUS_TUNE_TIME_TOO_SHORT) { /* fe in input failled also, break the current one */
3078 *tune_state = CT_DEMOD_STOP; /* else we are done here ; step 8 will close the loops and exit */
3079 dib8000_viterbi_state(state, 1); /* start viterbi chandec */
3080 dib8000_set_isdbt_loop_params(state, LOOP_TUNE_2);
3081 state->status = FE_STATUS_TUNE_FAILED;
3082 }
3083 } else {
3084 dib8000_viterbi_state(state, 1); /* start viterbi chandec */
3085 dib8000_set_isdbt_loop_params(state, LOOP_TUNE_2);
3086 *tune_state = CT_DEMOD_STOP; /* else we are done here ; step 8 will close the loops and exit */
3087 state->status = FE_STATUS_TUNE_FAILED;
3088 }
3089 break;
3090
3091 case CT_DEMOD_STEP_7: /* 37 */
3092 locks = dib8000_read_lock(fe);
3093 if (locks & (1<<10)) { /* lmod4_lock */
3094 ret = 14; /* wait for 14 symbols */
3095 *tune_state = CT_DEMOD_STEP_8;
3096 } else if (now > *timeout)
3097 *tune_state = CT_DEMOD_STEP_6; /* goto check for diversity input connection */
3098 break;
3099
3100 case CT_DEMOD_STEP_8: /* 38 */
3101 dib8000_viterbi_state(state, 1); /* start viterbi chandec */
3102 dib8000_set_isdbt_loop_params(state, LOOP_TUNE_2);
3103
3104 /* mpeg will never lock on this condition because init_prbs is not set : search for it !*/
Mauro Carvalho Chehab746f7ae2013-04-25 11:15:54 -03003105 if (c->isdbt_sb_mode
3106 && c->isdbt_sb_subchannel < 14
3107 && !state->differential_constellation) {
Patrick Boettcher173a64c2013-04-22 12:45:52 -03003108 state->subchannel = 0;
3109 *tune_state = CT_DEMOD_STEP_11;
3110 } else {
3111 *tune_state = CT_DEMOD_STEP_9;
3112 state->status = FE_STATUS_LOCKED;
3113 }
3114 break;
3115
3116 case CT_DEMOD_STEP_9: /* 39 */
3117 if ((state->revision == 0x8090) || ((dib8000_read_word(state, 1291) >> 9) & 0x1)) { /* fe capable of deinterleaving : esram */
3118 /* defines timeout for mpeg lock depending on interleaver lenght of longest layer */
3119 for (i = 0; i < 3; i++) {
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03003120 if (c->layer[i].interleaving >= deeper_interleaver) {
3121 dprintk("layer%i: time interleaver = %d ", i, c->layer[i].interleaving);
3122 if (c->layer[i].segment_count > 0) { /* valid layer */
3123 deeper_interleaver = c->layer[0].interleaving;
Patrick Boettcher173a64c2013-04-22 12:45:52 -03003124 state->longest_intlv_layer = i;
3125 }
3126 }
3127 }
3128
3129 if (deeper_interleaver == 0)
3130 locks = 2; /* locks is the tmp local variable name */
3131 else if (deeper_interleaver == 3)
3132 locks = 8;
3133 else
3134 locks = 2 * deeper_interleaver;
3135
3136 if (state->diversity_onoff != 0) /* because of diversity sync */
3137 locks *= 2;
3138
3139 *timeout = now + (2000 * locks); /* give the mpeg lock 800ms if sram is present */
3140 dprintk("Deeper interleaver mode = %d on layer %d : timeout mult factor = %d => will use timeout = %d", deeper_interleaver, state->longest_intlv_layer, locks, *timeout);
3141
3142 *tune_state = CT_DEMOD_STEP_10;
3143 } else
3144 *tune_state = CT_DEMOD_STOP;
3145 break;
3146
3147 case CT_DEMOD_STEP_10: /* 40 */
3148 locks = dib8000_read_lock(fe);
3149 if (locks&(1<<(7-state->longest_intlv_layer))) { /* mpeg lock : check the longest one */
3150 dprintk("Mpeg locks [ L0 : %d | L1 : %d | L2 : %d ]", (locks>>7)&0x1, (locks>>6)&0x1, (locks>>5)&0x1);
Mauro Carvalho Chehab746f7ae2013-04-25 11:15:54 -03003151 if (c->isdbt_sb_mode
3152 && c->isdbt_sb_subchannel < 14
3153 && !state->differential_constellation)
Patrick Boettcher173a64c2013-04-22 12:45:52 -03003154 /* signal to the upper layer, that there was a channel found and the parameters can be read */
3155 state->status = FE_STATUS_DEMOD_SUCCESS;
3156 else
3157 state->status = FE_STATUS_DATA_LOCKED;
3158 *tune_state = CT_DEMOD_STOP;
3159 } else if (now > *timeout) {
Mauro Carvalho Chehab746f7ae2013-04-25 11:15:54 -03003160 if (c->isdbt_sb_mode
3161 && c->isdbt_sb_subchannel < 14
3162 && !state->differential_constellation) { /* continue to try init prbs autosearch */
Patrick Boettcher173a64c2013-04-22 12:45:52 -03003163 state->subchannel += 3;
3164 *tune_state = CT_DEMOD_STEP_11;
3165 } 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 */
3166 if (locks & (0x7<<5)) {
3167 dprintk("Mpeg locks [ L0 : %d | L1 : %d | L2 : %d ]", (locks>>7)&0x1, (locks>>6)&0x1, (locks>>5)&0x1);
3168 state->status = FE_STATUS_DATA_LOCKED;
3169 } else
3170 state->status = FE_STATUS_TUNE_FAILED;
3171 *tune_state = CT_DEMOD_STOP;
3172 }
3173 }
3174 break;
3175
3176 case CT_DEMOD_STEP_11: /* 41 : init prbs autosearch */
3177 if (state->subchannel <= 41) {
3178 dib8000_set_subchannel_prbs(state, dib8000_get_init_prbs(state, state->subchannel));
3179 *tune_state = CT_DEMOD_STEP_9;
3180 } else {
3181 *tune_state = CT_DEMOD_STOP;
3182 state->status = FE_STATUS_TUNE_FAILED;
3183 }
3184 break;
3185
3186 default:
3187 break;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003188 }
3189
Patrick Boettcher173a64c2013-04-22 12:45:52 -03003190 /* tuning is finished - cleanup the demod */
3191 switch (*tune_state) {
3192 case CT_DEMOD_STOP: /* (42) */
3193#ifdef DIB8000_AGC_FREEZE
3194 if ((state->revision != 0x8090) && (state->agc1_max != 0)) {
3195 dib8000_write_word(state, 108, state->agc1_max);
3196 dib8000_write_word(state, 109, state->agc1_min);
3197 dib8000_write_word(state, 110, state->agc2_max);
3198 dib8000_write_word(state, 111, state->agc2_min);
3199 state->agc1_max = 0;
3200 state->agc1_min = 0;
3201 state->agc2_max = 0;
3202 state->agc2_min = 0;
3203 }
3204#endif
3205 ret = FE_CALLBACK_TIME_NEVER;
3206 break;
3207 default:
3208 break;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003209 }
3210
Patrick Boettcher173a64c2013-04-22 12:45:52 -03003211 if ((ret > 0) && (*tune_state > CT_DEMOD_STEP_3))
3212 return ret * state->symbol_duration;
3213 if ((ret > 0) && (ret < state->symbol_duration))
3214 return state->symbol_duration; /* at least one symbol */
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003215 return ret;
3216}
3217
3218static int dib8000_wakeup(struct dvb_frontend *fe)
3219{
3220 struct dib8000_state *state = fe->demodulator_priv;
Olivier Grenie4c70e072011-01-03 15:33:37 -03003221 u8 index_frontend;
3222 int ret;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003223
Olivier Grenie0c32dbd2011-08-10 05:17:18 -03003224 dib8000_set_power_mode(state, DIB8000_POWER_ALL);
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003225 dib8000_set_adc_state(state, DIBX000_ADC_ON);
3226 if (dib8000_set_adc_state(state, DIBX000_SLOW_ADC_ON) != 0)
3227 dprintk("could not start Slow ADC");
3228
Patrick Boettcher173a64c2013-04-22 12:45:52 -03003229 if (state->revision == 0x8090)
Olivier Grenie0c32dbd2011-08-10 05:17:18 -03003230 dib8000_sad_calib(state);
3231
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03003232 for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
Olivier Grenie4c70e072011-01-03 15:33:37 -03003233 ret = state->fe[index_frontend]->ops.init(state->fe[index_frontend]);
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03003234 if (ret < 0)
Olivier Grenie4c70e072011-01-03 15:33:37 -03003235 return ret;
3236 }
3237
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003238 return 0;
3239}
3240
3241static int dib8000_sleep(struct dvb_frontend *fe)
3242{
Olivier Grenie4c70e072011-01-03 15:33:37 -03003243 struct dib8000_state *state = fe->demodulator_priv;
3244 u8 index_frontend;
3245 int ret;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003246
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03003247 for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
Olivier Grenie4c70e072011-01-03 15:33:37 -03003248 ret = state->fe[index_frontend]->ops.sleep(state->fe[index_frontend]);
3249 if (ret < 0)
3250 return ret;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003251 }
Olivier Grenie4c70e072011-01-03 15:33:37 -03003252
Olivier Grenie0c32dbd2011-08-10 05:17:18 -03003253 if (state->revision != 0x8090)
3254 dib8000_set_output_mode(fe, OUTMODE_HIGH_Z);
3255 dib8000_set_power_mode(state, DIB8000_POWER_INTERFACE_ONLY);
Olivier Grenie4c70e072011-01-03 15:33:37 -03003256 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 -03003257}
3258
Mauro Carvalho Chehab7c61d802011-12-30 11:30:21 -03003259static int dib8000_get_frontend(struct dvb_frontend *fe)
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003260{
3261 struct dib8000_state *state = fe->demodulator_priv;
3262 u16 i, val = 0;
Olivier Grenie4c70e072011-01-03 15:33:37 -03003263 fe_status_t stat;
3264 u8 index_frontend, sub_index_frontend;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003265
3266 fe->dtv_property_cache.bandwidth_hz = 6000000;
3267
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03003268 for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
Olivier Grenie4c70e072011-01-03 15:33:37 -03003269 state->fe[index_frontend]->ops.read_status(state->fe[index_frontend], &stat);
3270 if (stat&FE_HAS_SYNC) {
3271 dprintk("TMCC lock on the slave%i", index_frontend);
3272 /* synchronize the cache with the other frontends */
Mauro Carvalho Chehab7c61d802011-12-30 11:30:21 -03003273 state->fe[index_frontend]->ops.get_frontend(state->fe[index_frontend]);
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03003274 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 -03003275 if (sub_index_frontend != index_frontend) {
3276 state->fe[sub_index_frontend]->dtv_property_cache.isdbt_sb_mode = state->fe[index_frontend]->dtv_property_cache.isdbt_sb_mode;
3277 state->fe[sub_index_frontend]->dtv_property_cache.inversion = state->fe[index_frontend]->dtv_property_cache.inversion;
3278 state->fe[sub_index_frontend]->dtv_property_cache.transmission_mode = state->fe[index_frontend]->dtv_property_cache.transmission_mode;
3279 state->fe[sub_index_frontend]->dtv_property_cache.guard_interval = state->fe[index_frontend]->dtv_property_cache.guard_interval;
3280 state->fe[sub_index_frontend]->dtv_property_cache.isdbt_partial_reception = state->fe[index_frontend]->dtv_property_cache.isdbt_partial_reception;
3281 for (i = 0; i < 3; i++) {
3282 state->fe[sub_index_frontend]->dtv_property_cache.layer[i].segment_count = state->fe[index_frontend]->dtv_property_cache.layer[i].segment_count;
3283 state->fe[sub_index_frontend]->dtv_property_cache.layer[i].interleaving = state->fe[index_frontend]->dtv_property_cache.layer[i].interleaving;
3284 state->fe[sub_index_frontend]->dtv_property_cache.layer[i].fec = state->fe[index_frontend]->dtv_property_cache.layer[i].fec;
3285 state->fe[sub_index_frontend]->dtv_property_cache.layer[i].modulation = state->fe[index_frontend]->dtv_property_cache.layer[i].modulation;
3286 }
3287 }
3288 }
3289 return 0;
3290 }
3291 }
3292
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003293 fe->dtv_property_cache.isdbt_sb_mode = dib8000_read_word(state, 508) & 0x1;
3294
Olivier Grenie0c32dbd2011-08-10 05:17:18 -03003295 if (state->revision == 0x8090)
3296 val = dib8000_read_word(state, 572);
3297 else
3298 val = dib8000_read_word(state, 570);
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003299 fe->dtv_property_cache.inversion = (val & 0x40) >> 6;
3300 switch ((val & 0x30) >> 4) {
3301 case 1:
3302 fe->dtv_property_cache.transmission_mode = TRANSMISSION_MODE_2K;
3303 break;
3304 case 3:
3305 default:
3306 fe->dtv_property_cache.transmission_mode = TRANSMISSION_MODE_8K;
3307 break;
3308 }
3309
3310 switch (val & 0x3) {
3311 case 0:
3312 fe->dtv_property_cache.guard_interval = GUARD_INTERVAL_1_32;
3313 dprintk("dib8000_get_frontend GI = 1/32 ");
3314 break;
3315 case 1:
3316 fe->dtv_property_cache.guard_interval = GUARD_INTERVAL_1_16;
3317 dprintk("dib8000_get_frontend GI = 1/16 ");
3318 break;
3319 case 2:
3320 dprintk("dib8000_get_frontend GI = 1/8 ");
3321 fe->dtv_property_cache.guard_interval = GUARD_INTERVAL_1_8;
3322 break;
3323 case 3:
3324 dprintk("dib8000_get_frontend GI = 1/4 ");
3325 fe->dtv_property_cache.guard_interval = GUARD_INTERVAL_1_4;
3326 break;
3327 }
3328
3329 val = dib8000_read_word(state, 505);
3330 fe->dtv_property_cache.isdbt_partial_reception = val & 1;
3331 dprintk("dib8000_get_frontend : partial_reception = %d ", fe->dtv_property_cache.isdbt_partial_reception);
3332
3333 for (i = 0; i < 3; i++) {
3334 val = dib8000_read_word(state, 493 + i);
3335 fe->dtv_property_cache.layer[i].segment_count = val & 0x0F;
3336 dprintk("dib8000_get_frontend : Layer %d segments = %d ", i, fe->dtv_property_cache.layer[i].segment_count);
3337
3338 val = dib8000_read_word(state, 499 + i);
3339 fe->dtv_property_cache.layer[i].interleaving = val & 0x3;
3340 dprintk("dib8000_get_frontend : Layer %d time_intlv = %d ", i, fe->dtv_property_cache.layer[i].interleaving);
3341
3342 val = dib8000_read_word(state, 481 + i);
3343 switch (val & 0x7) {
3344 case 1:
3345 fe->dtv_property_cache.layer[i].fec = FEC_1_2;
3346 dprintk("dib8000_get_frontend : Layer %d Code Rate = 1/2 ", i);
3347 break;
3348 case 2:
3349 fe->dtv_property_cache.layer[i].fec = FEC_2_3;
3350 dprintk("dib8000_get_frontend : Layer %d Code Rate = 2/3 ", i);
3351 break;
3352 case 3:
3353 fe->dtv_property_cache.layer[i].fec = FEC_3_4;
3354 dprintk("dib8000_get_frontend : Layer %d Code Rate = 3/4 ", i);
3355 break;
3356 case 5:
3357 fe->dtv_property_cache.layer[i].fec = FEC_5_6;
3358 dprintk("dib8000_get_frontend : Layer %d Code Rate = 5/6 ", i);
3359 break;
3360 default:
3361 fe->dtv_property_cache.layer[i].fec = FEC_7_8;
3362 dprintk("dib8000_get_frontend : Layer %d Code Rate = 7/8 ", i);
3363 break;
3364 }
3365
3366 val = dib8000_read_word(state, 487 + i);
3367 switch (val & 0x3) {
3368 case 0:
3369 dprintk("dib8000_get_frontend : Layer %d DQPSK ", i);
3370 fe->dtv_property_cache.layer[i].modulation = DQPSK;
3371 break;
3372 case 1:
3373 fe->dtv_property_cache.layer[i].modulation = QPSK;
3374 dprintk("dib8000_get_frontend : Layer %d QPSK ", i);
3375 break;
3376 case 2:
3377 fe->dtv_property_cache.layer[i].modulation = QAM_16;
3378 dprintk("dib8000_get_frontend : Layer %d QAM16 ", i);
3379 break;
3380 case 3:
3381 default:
3382 dprintk("dib8000_get_frontend : Layer %d QAM64 ", i);
3383 fe->dtv_property_cache.layer[i].modulation = QAM_64;
3384 break;
3385 }
3386 }
Olivier Grenie4c70e072011-01-03 15:33:37 -03003387
3388 /* synchronize the cache with the other frontends */
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03003389 for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
Olivier Grenie4c70e072011-01-03 15:33:37 -03003390 state->fe[index_frontend]->dtv_property_cache.isdbt_sb_mode = fe->dtv_property_cache.isdbt_sb_mode;
3391 state->fe[index_frontend]->dtv_property_cache.inversion = fe->dtv_property_cache.inversion;
3392 state->fe[index_frontend]->dtv_property_cache.transmission_mode = fe->dtv_property_cache.transmission_mode;
3393 state->fe[index_frontend]->dtv_property_cache.guard_interval = fe->dtv_property_cache.guard_interval;
3394 state->fe[index_frontend]->dtv_property_cache.isdbt_partial_reception = fe->dtv_property_cache.isdbt_partial_reception;
3395 for (i = 0; i < 3; i++) {
3396 state->fe[index_frontend]->dtv_property_cache.layer[i].segment_count = fe->dtv_property_cache.layer[i].segment_count;
3397 state->fe[index_frontend]->dtv_property_cache.layer[i].interleaving = fe->dtv_property_cache.layer[i].interleaving;
3398 state->fe[index_frontend]->dtv_property_cache.layer[i].fec = fe->dtv_property_cache.layer[i].fec;
3399 state->fe[index_frontend]->dtv_property_cache.layer[i].modulation = fe->dtv_property_cache.layer[i].modulation;
3400 }
3401 }
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003402 return 0;
3403}
3404
Mauro Carvalho Chehab490ecd62011-12-22 20:38:27 -03003405static int dib8000_set_frontend(struct dvb_frontend *fe)
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003406{
3407 struct dib8000_state *state = fe->demodulator_priv;
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03003408 struct dtv_frontend_properties *c = &state->fe[0]->dtv_property_cache;
Geert Uytterhoeven4d8d5d92013-06-02 13:52:17 -03003409 int l, i, active, time, time_slave = FE_CALLBACK_TIME_NEVER;
Patrick Boettcher173a64c2013-04-22 12:45:52 -03003410 u8 exit_condition, index_frontend;
3411 u32 delay, callback_time;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003412
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03003413 if (c->frequency == 0) {
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003414 dprintk("dib8000: must at least specify frequency ");
3415 return 0;
3416 }
3417
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03003418 if (c->bandwidth_hz == 0) {
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003419 dprintk("dib8000: no bandwidth specified, set to default ");
Mauro Carvalho Chehabc82056d2013-04-25 10:51:15 -03003420 c->bandwidth_hz = 6000000;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003421 }
3422
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03003423 for (index_frontend = 0; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
Olivier Grenie4c70e072011-01-03 15:33:37 -03003424 /* synchronization of the cache */
3425 state->fe[index_frontend]->dtv_property_cache.delivery_system = SYS_ISDBT;
3426 memcpy(&state->fe[index_frontend]->dtv_property_cache, &fe->dtv_property_cache, sizeof(struct dtv_frontend_properties));
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003427
Patrick Boettcher173a64c2013-04-22 12:45:52 -03003428 /* set output mode and diversity input */
3429 if (state->revision != 0x8090) {
3430 dib8000_set_diversity_in(state->fe[index_frontend], 1);
3431 if (index_frontend != 0)
3432 dib8000_set_output_mode(state->fe[index_frontend],
3433 OUTMODE_DIVERSITY);
3434 else
3435 dib8000_set_output_mode(state->fe[0], OUTMODE_HIGH_Z);
3436 } else {
3437 dib8096p_set_diversity_in(state->fe[index_frontend], 1);
3438 if (index_frontend != 0)
3439 dib8096p_set_output_mode(state->fe[index_frontend],
3440 OUTMODE_DIVERSITY);
3441 else
3442 dib8096p_set_output_mode(state->fe[0], OUTMODE_HIGH_Z);
3443 }
3444
3445 /* tune the tuner */
Olivier Grenie4c70e072011-01-03 15:33:37 -03003446 if (state->fe[index_frontend]->ops.tuner_ops.set_params)
Mauro Carvalho Chehab14d24d12011-12-24 12:24:33 -03003447 state->fe[index_frontend]->ops.tuner_ops.set_params(state->fe[index_frontend]);
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003448
Olivier Grenie4c70e072011-01-03 15:33:37 -03003449 dib8000_set_tune_state(state->fe[index_frontend], CT_AGC_START);
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003450 }
3451
Patrick Boettcher173a64c2013-04-22 12:45:52 -03003452 /* turn off the diversity of the last chip */
3453 if (state->revision != 0x8090)
3454 dib8000_set_diversity_in(state->fe[index_frontend - 1], 0);
3455 else
3456 dib8096p_set_diversity_in(state->fe[index_frontend - 1], 0);
3457
Olivier Grenie4c70e072011-01-03 15:33:37 -03003458 /* start up the AGC */
3459 do {
3460 time = dib8000_agc_startup(state->fe[0]);
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03003461 for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
Olivier Grenie4c70e072011-01-03 15:33:37 -03003462 time_slave = dib8000_agc_startup(state->fe[index_frontend]);
3463 if (time == FE_CALLBACK_TIME_NEVER)
3464 time = time_slave;
3465 else if ((time_slave != FE_CALLBACK_TIME_NEVER) && (time_slave > time))
3466 time = time_slave;
3467 }
3468 if (time != FE_CALLBACK_TIME_NEVER)
3469 msleep(time / 10);
3470 else
3471 break;
3472 exit_condition = 1;
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03003473 for (index_frontend = 0; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
Olivier Grenie4c70e072011-01-03 15:33:37 -03003474 if (dib8000_get_tune_state(state->fe[index_frontend]) != CT_AGC_STOP) {
3475 exit_condition = 0;
3476 break;
3477 }
3478 }
3479 } while (exit_condition == 0);
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003480
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03003481 for (index_frontend = 0; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++)
Olivier Grenie4c70e072011-01-03 15:33:37 -03003482 dib8000_set_tune_state(state->fe[index_frontend], CT_DEMOD_START);
3483
Patrick Boettcher173a64c2013-04-22 12:45:52 -03003484 active = 1;
3485 do {
3486 callback_time = FE_CALLBACK_TIME_NEVER;
Mauro Carvalho Chehab2c2c4412011-01-16 13:02:52 -02003487 for (index_frontend = 0; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
Patrick Boettcher173a64c2013-04-22 12:45:52 -03003488 delay = dib8000_tune(state->fe[index_frontend]);
3489 if (delay != FE_CALLBACK_TIME_NEVER)
3490 delay += systime();
Olivier Grenie4c70e072011-01-03 15:33:37 -03003491
Patrick Boettcher173a64c2013-04-22 12:45:52 -03003492 /* we are in autosearch */
3493 if (state->channel_parameters_set == 0) { /* searching */
3494 if ((dib8000_get_status(state->fe[index_frontend]) == FE_STATUS_DEMOD_SUCCESS) || (dib8000_get_status(state->fe[index_frontend]) == FE_STATUS_FFT_SUCCESS)) {
3495 dprintk("autosearch succeeded on fe%i", index_frontend);
3496 dib8000_get_frontend(state->fe[index_frontend]); /* we read the channel parameters from the frontend which was successful */
3497 state->channel_parameters_set = 1;
3498
3499 for (l = 0; (l < MAX_NUMBER_OF_FRONTENDS) && (state->fe[l] != NULL); l++) {
3500 if (l != index_frontend) { /* and for all frontend except the successful one */
3501 dib8000_tune_restart_from_demod(state->fe[l]);
3502
3503 state->fe[l]->dtv_property_cache.isdbt_sb_mode = state->fe[index_frontend]->dtv_property_cache.isdbt_sb_mode;
3504 state->fe[l]->dtv_property_cache.inversion = state->fe[index_frontend]->dtv_property_cache.inversion;
3505 state->fe[l]->dtv_property_cache.transmission_mode = state->fe[index_frontend]->dtv_property_cache.transmission_mode;
3506 state->fe[l]->dtv_property_cache.guard_interval = state->fe[index_frontend]->dtv_property_cache.guard_interval;
3507 state->fe[l]->dtv_property_cache.isdbt_partial_reception = state->fe[index_frontend]->dtv_property_cache.isdbt_partial_reception;
3508 for (i = 0; i < 3; i++) {
3509 state->fe[l]->dtv_property_cache.layer[i].segment_count = state->fe[index_frontend]->dtv_property_cache.layer[i].segment_count;
3510 state->fe[l]->dtv_property_cache.layer[i].interleaving = state->fe[index_frontend]->dtv_property_cache.layer[i].interleaving;
3511 state->fe[l]->dtv_property_cache.layer[i].fec = state->fe[index_frontend]->dtv_property_cache.layer[i].fec;
3512 state->fe[l]->dtv_property_cache.layer[i].modulation = state->fe[index_frontend]->dtv_property_cache.layer[i].modulation;
3513 }
3514
3515 }
Mauro Carvalho Chehab2c2c4412011-01-16 13:02:52 -02003516 }
3517 }
3518 }
Patrick Boettcher173a64c2013-04-22 12:45:52 -03003519 if (delay < callback_time)
3520 callback_time = delay;
3521 }
3522 /* tuning is done when the master frontend is done (failed or success) */
3523 if (dib8000_get_status(state->fe[0]) == FE_STATUS_TUNE_FAILED ||
3524 dib8000_get_status(state->fe[0]) == FE_STATUS_LOCKED ||
3525 dib8000_get_status(state->fe[0]) == FE_STATUS_DATA_LOCKED) {
3526 active = 0;
3527 /* we need to wait for all frontends to be finished */
3528 for (index_frontend = 0; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
3529 if (dib8000_get_tune_state(state->fe[index_frontend]) != CT_DEMOD_STOP)
3530 active = 1;
3531 }
3532 if (active == 0)
3533 dprintk("tuning done with status %d", dib8000_get_status(state->fe[0]));
Mauro Carvalho Chehab2c2c4412011-01-16 13:02:52 -02003534 }
Olivier Grenie4c70e072011-01-03 15:33:37 -03003535
Patrick Boettcher173a64c2013-04-22 12:45:52 -03003536 if ((active == 1) && (callback_time == FE_CALLBACK_TIME_NEVER)) {
3537 dprintk("strange callback time something went wrong");
3538 active = 0;
3539 }
Olivier Grenie4c70e072011-01-03 15:33:37 -03003540
Patrick Boettcher173a64c2013-04-22 12:45:52 -03003541 while ((active == 1) && (systime() < callback_time))
3542 msleep(100);
3543 } while (active);
Olivier Grenie4c70e072011-01-03 15:33:37 -03003544
Patrick Boettcher173a64c2013-04-22 12:45:52 -03003545 /* set output mode */
3546 if (state->revision != 0x8090)
Olivier Grenie0c32dbd2011-08-10 05:17:18 -03003547 dib8000_set_output_mode(state->fe[0], state->cfg.output_mode);
Patrick Boettcher173a64c2013-04-22 12:45:52 -03003548 else {
Olivier Grenie0c32dbd2011-08-10 05:17:18 -03003549 dib8096p_set_output_mode(state->fe[0], state->cfg.output_mode);
3550 if (state->cfg.enMpegOutput == 0) {
3551 dib8096p_setDibTxMux(state, MPEG_ON_DIBTX);
3552 dib8096p_setHostBusMux(state, DIBTX_ON_HOSTBUS);
3553 }
Olivier Grenie0c32dbd2011-08-10 05:17:18 -03003554 }
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003555
Geert Uytterhoeven4d8d5d92013-06-02 13:52:17 -03003556 return 0;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003557}
3558
3559static int dib8000_read_status(struct dvb_frontend *fe, fe_status_t * stat)
3560{
3561 struct dib8000_state *state = fe->demodulator_priv;
Olivier Grenie0c32dbd2011-08-10 05:17:18 -03003562 u16 lock_slave = 0, lock;
Olivier Grenie4c70e072011-01-03 15:33:37 -03003563 u8 index_frontend;
3564
Patrick Boettcher173a64c2013-04-22 12:45:52 -03003565 lock = dib8000_read_lock(fe);
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03003566 for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++)
Olivier Grenie4c70e072011-01-03 15:33:37 -03003567 lock_slave |= dib8000_read_lock(state->fe[index_frontend]);
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003568
3569 *stat = 0;
3570
Olivier Grenie4c70e072011-01-03 15:33:37 -03003571 if (((lock >> 13) & 1) || ((lock_slave >> 13) & 1))
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003572 *stat |= FE_HAS_SIGNAL;
3573
Olivier Grenie4c70e072011-01-03 15:33:37 -03003574 if (((lock >> 8) & 1) || ((lock_slave >> 8) & 1)) /* Equal */
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003575 *stat |= FE_HAS_CARRIER;
3576
Olivier Grenie4c70e072011-01-03 15:33:37 -03003577 if ((((lock >> 1) & 0xf) == 0xf) || (((lock_slave >> 1) & 0xf) == 0xf)) /* TMCC_SYNC */
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003578 *stat |= FE_HAS_SYNC;
3579
Olivier Grenie4c70e072011-01-03 15:33:37 -03003580 if ((((lock >> 12) & 1) || ((lock_slave >> 12) & 1)) && ((lock >> 5) & 7)) /* FEC MPEG */
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003581 *stat |= FE_HAS_LOCK;
3582
Olivier Grenie4c70e072011-01-03 15:33:37 -03003583 if (((lock >> 12) & 1) || ((lock_slave >> 12) & 1)) {
Olivier Grenie89dfc552009-11-30 06:38:49 -03003584 lock = dib8000_read_word(state, 554); /* Viterbi Layer A */
3585 if (lock & 0x01)
3586 *stat |= FE_HAS_VITERBI;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003587
Olivier Grenie89dfc552009-11-30 06:38:49 -03003588 lock = dib8000_read_word(state, 555); /* Viterbi Layer B */
3589 if (lock & 0x01)
3590 *stat |= FE_HAS_VITERBI;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003591
Olivier Grenie89dfc552009-11-30 06:38:49 -03003592 lock = dib8000_read_word(state, 556); /* Viterbi Layer C */
3593 if (lock & 0x01)
3594 *stat |= FE_HAS_VITERBI;
3595 }
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003596
3597 return 0;
3598}
3599
3600static int dib8000_read_ber(struct dvb_frontend *fe, u32 * ber)
3601{
3602 struct dib8000_state *state = fe->demodulator_priv;
Olivier Grenie0c32dbd2011-08-10 05:17:18 -03003603
3604 /* 13 segments */
3605 if (state->revision == 0x8090)
3606 *ber = (dib8000_read_word(state, 562) << 16) |
3607 dib8000_read_word(state, 563);
3608 else
3609 *ber = (dib8000_read_word(state, 560) << 16) |
3610 dib8000_read_word(state, 561);
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003611 return 0;
3612}
3613
3614static int dib8000_read_unc_blocks(struct dvb_frontend *fe, u32 * unc)
3615{
3616 struct dib8000_state *state = fe->demodulator_priv;
Olivier Grenie0c32dbd2011-08-10 05:17:18 -03003617
3618 /* packet error on 13 seg */
3619 if (state->revision == 0x8090)
3620 *unc = dib8000_read_word(state, 567);
3621 else
3622 *unc = dib8000_read_word(state, 565);
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003623 return 0;
3624}
3625
3626static int dib8000_read_signal_strength(struct dvb_frontend *fe, u16 * strength)
3627{
3628 struct dib8000_state *state = fe->demodulator_priv;
Olivier Grenie4c70e072011-01-03 15:33:37 -03003629 u8 index_frontend;
3630 u16 val;
3631
3632 *strength = 0;
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03003633 for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
Olivier Grenie4c70e072011-01-03 15:33:37 -03003634 state->fe[index_frontend]->ops.read_signal_strength(state->fe[index_frontend], &val);
3635 if (val > 65535 - *strength)
3636 *strength = 65535;
3637 else
3638 *strength += val;
3639 }
3640
3641 val = 65535 - dib8000_read_word(state, 390);
3642 if (val > 65535 - *strength)
3643 *strength = 65535;
3644 else
3645 *strength += val;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003646 return 0;
3647}
3648
Olivier Grenie4c70e072011-01-03 15:33:37 -03003649static u32 dib8000_get_snr(struct dvb_frontend *fe)
3650{
3651 struct dib8000_state *state = fe->demodulator_priv;
3652 u32 n, s, exp;
3653 u16 val;
3654
Olivier Grenie0c32dbd2011-08-10 05:17:18 -03003655 if (state->revision != 0x8090)
3656 val = dib8000_read_word(state, 542);
3657 else
3658 val = dib8000_read_word(state, 544);
Olivier Grenie4c70e072011-01-03 15:33:37 -03003659 n = (val >> 6) & 0xff;
3660 exp = (val & 0x3f);
3661 if ((exp & 0x20) != 0)
3662 exp -= 0x40;
3663 n <<= exp+16;
3664
Olivier Grenie0c32dbd2011-08-10 05:17:18 -03003665 if (state->revision != 0x8090)
3666 val = dib8000_read_word(state, 543);
3667 else
3668 val = dib8000_read_word(state, 545);
Olivier Grenie4c70e072011-01-03 15:33:37 -03003669 s = (val >> 6) & 0xff;
3670 exp = (val & 0x3f);
3671 if ((exp & 0x20) != 0)
3672 exp -= 0x40;
3673 s <<= exp+16;
3674
3675 if (n > 0) {
3676 u32 t = (s/n) << 16;
3677 return t + ((s << 16) - n*t) / n;
3678 }
3679 return 0xffffffff;
3680}
3681
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003682static int dib8000_read_snr(struct dvb_frontend *fe, u16 * snr)
3683{
3684 struct dib8000_state *state = fe->demodulator_priv;
Olivier Grenie4c70e072011-01-03 15:33:37 -03003685 u8 index_frontend;
3686 u32 snr_master;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003687
Olivier Grenie4c70e072011-01-03 15:33:37 -03003688 snr_master = dib8000_get_snr(fe);
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03003689 for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++)
Olivier Grenie4c70e072011-01-03 15:33:37 -03003690 snr_master += dib8000_get_snr(state->fe[index_frontend]);
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003691
Olivier Grenie1f6bfcc2011-07-04 12:33:54 -03003692 if ((snr_master >> 16) != 0) {
Olivier Grenie4c70e072011-01-03 15:33:37 -03003693 snr_master = 10*intlog10(snr_master>>16);
3694 *snr = snr_master / ((1 << 24) / 10);
3695 }
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003696 else
Olivier Grenie4c70e072011-01-03 15:33:37 -03003697 *snr = 0;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003698
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003699 return 0;
3700}
3701
Olivier Grenie4c70e072011-01-03 15:33:37 -03003702int dib8000_set_slave_frontend(struct dvb_frontend *fe, struct dvb_frontend *fe_slave)
3703{
3704 struct dib8000_state *state = fe->demodulator_priv;
3705 u8 index_frontend = 1;
3706
3707 while ((index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL))
3708 index_frontend++;
3709 if (index_frontend < MAX_NUMBER_OF_FRONTENDS) {
3710 dprintk("set slave fe %p to index %i", fe_slave, index_frontend);
3711 state->fe[index_frontend] = fe_slave;
3712 return 0;
3713 }
3714
3715 dprintk("too many slave frontend");
3716 return -ENOMEM;
3717}
3718EXPORT_SYMBOL(dib8000_set_slave_frontend);
3719
3720int dib8000_remove_slave_frontend(struct dvb_frontend *fe)
3721{
3722 struct dib8000_state *state = fe->demodulator_priv;
3723 u8 index_frontend = 1;
3724
3725 while ((index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL))
3726 index_frontend++;
3727 if (index_frontend != 1) {
3728 dprintk("remove slave fe %p (index %i)", state->fe[index_frontend-1], index_frontend-1);
3729 state->fe[index_frontend] = NULL;
3730 return 0;
3731 }
3732
3733 dprintk("no frontend to be removed");
3734 return -ENODEV;
3735}
3736EXPORT_SYMBOL(dib8000_remove_slave_frontend);
3737
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03003738struct dvb_frontend *dib8000_get_slave_frontend(struct dvb_frontend *fe, int slave_index)
Olivier Grenie4c70e072011-01-03 15:33:37 -03003739{
3740 struct dib8000_state *state = fe->demodulator_priv;
3741
3742 if (slave_index >= MAX_NUMBER_OF_FRONTENDS)
3743 return NULL;
3744 return state->fe[slave_index];
3745}
3746EXPORT_SYMBOL(dib8000_get_slave_frontend);
3747
3748
Olivier Grenie0c32dbd2011-08-10 05:17:18 -03003749int dib8000_i2c_enumeration(struct i2c_adapter *host, int no_of_demods,
3750 u8 default_addr, u8 first_addr, u8 is_dib8096p)
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003751{
Olivier Grenie5a0deee2011-05-03 12:27:33 -03003752 int k = 0, ret = 0;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003753 u8 new_addr = 0;
3754 struct i2c_device client = {.adap = host };
3755
Olivier Grenie5a0deee2011-05-03 12:27:33 -03003756 client.i2c_write_buffer = kzalloc(4 * sizeof(u8), GFP_KERNEL);
3757 if (!client.i2c_write_buffer) {
3758 dprintk("%s: not enough memory", __func__);
3759 return -ENOMEM;
3760 }
3761 client.i2c_read_buffer = kzalloc(4 * sizeof(u8), GFP_KERNEL);
3762 if (!client.i2c_read_buffer) {
3763 dprintk("%s: not enough memory", __func__);
3764 ret = -ENOMEM;
Patrick Boettcher79fcce32011-08-03 12:08:21 -03003765 goto error_memory_read;
Olivier Grenie5a0deee2011-05-03 12:27:33 -03003766 }
Patrick Boettcher79fcce32011-08-03 12:08:21 -03003767 client.i2c_buffer_lock = kzalloc(sizeof(struct mutex), GFP_KERNEL);
3768 if (!client.i2c_buffer_lock) {
3769 dprintk("%s: not enough memory", __func__);
3770 ret = -ENOMEM;
3771 goto error_memory_lock;
3772 }
3773 mutex_init(client.i2c_buffer_lock);
Olivier Grenie5a0deee2011-05-03 12:27:33 -03003774
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003775 for (k = no_of_demods - 1; k >= 0; k--) {
3776 /* designated i2c address */
3777 new_addr = first_addr + (k << 1);
3778
3779 client.addr = new_addr;
Olivier Grenie0c32dbd2011-08-10 05:17:18 -03003780 if (!is_dib8096p)
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003781 dib8000_i2c_write16(&client, 1287, 0x0003); /* sram lead in, rdy */
Olivier Grenie0c32dbd2011-08-10 05:17:18 -03003782 if (dib8000_identify(&client) == 0) {
3783 /* sram lead in, rdy */
3784 if (!is_dib8096p)
3785 dib8000_i2c_write16(&client, 1287, 0x0003);
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003786 client.addr = default_addr;
3787 if (dib8000_identify(&client) == 0) {
3788 dprintk("#%d: not identified", k);
Olivier Grenie5a0deee2011-05-03 12:27:33 -03003789 ret = -EINVAL;
3790 goto error;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003791 }
3792 }
3793
3794 /* start diversity to pull_down div_str - just for i2c-enumeration */
3795 dib8000_i2c_write16(&client, 1286, (1 << 10) | (4 << 6));
3796
3797 /* set new i2c address and force divstart */
3798 dib8000_i2c_write16(&client, 1285, (new_addr << 2) | 0x2);
3799 client.addr = new_addr;
3800 dib8000_identify(&client);
3801
3802 dprintk("IC %d initialized (to i2c_address 0x%x)", k, new_addr);
3803 }
3804
3805 for (k = 0; k < no_of_demods; k++) {
3806 new_addr = first_addr | (k << 1);
3807 client.addr = new_addr;
3808
3809 // unforce divstr
3810 dib8000_i2c_write16(&client, 1285, new_addr << 2);
3811
3812 /* deactivate div - it was just for i2c-enumeration */
3813 dib8000_i2c_write16(&client, 1286, 0);
3814 }
3815
Olivier Grenie5a0deee2011-05-03 12:27:33 -03003816error:
Patrick Boettcher79fcce32011-08-03 12:08:21 -03003817 kfree(client.i2c_buffer_lock);
3818error_memory_lock:
Olivier Grenie5a0deee2011-05-03 12:27:33 -03003819 kfree(client.i2c_read_buffer);
Patrick Boettcher79fcce32011-08-03 12:08:21 -03003820error_memory_read:
Olivier Grenie5a0deee2011-05-03 12:27:33 -03003821 kfree(client.i2c_write_buffer);
3822
3823 return ret;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003824}
3825
3826EXPORT_SYMBOL(dib8000_i2c_enumeration);
3827static int dib8000_fe_get_tune_settings(struct dvb_frontend *fe, struct dvb_frontend_tune_settings *tune)
3828{
3829 tune->min_delay_ms = 1000;
3830 tune->step_size = 0;
3831 tune->max_drift = 0;
3832 return 0;
3833}
3834
3835static void dib8000_release(struct dvb_frontend *fe)
3836{
3837 struct dib8000_state *st = fe->demodulator_priv;
Olivier Grenie4c70e072011-01-03 15:33:37 -03003838 u8 index_frontend;
3839
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03003840 for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (st->fe[index_frontend] != NULL); index_frontend++)
Olivier Grenie4c70e072011-01-03 15:33:37 -03003841 dvb_frontend_detach(st->fe[index_frontend]);
3842
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003843 dibx000_exit_i2c_master(&st->i2c_master);
Olivier Grenie0c32dbd2011-08-10 05:17:18 -03003844 i2c_del_adapter(&st->dib8096p_tuner_adap);
Olivier Grenie4c70e072011-01-03 15:33:37 -03003845 kfree(st->fe[0]);
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003846 kfree(st);
3847}
3848
3849struct i2c_adapter *dib8000_get_i2c_master(struct dvb_frontend *fe, enum dibx000_i2c_interface intf, int gating)
3850{
3851 struct dib8000_state *st = fe->demodulator_priv;
3852 return dibx000_get_i2c_adapter(&st->i2c_master, intf, gating);
3853}
3854
3855EXPORT_SYMBOL(dib8000_get_i2c_master);
3856
Olivier Grenief8731f42009-09-18 04:08:43 -03003857int dib8000_pid_filter_ctrl(struct dvb_frontend *fe, u8 onoff)
3858{
3859 struct dib8000_state *st = fe->demodulator_priv;
Olivier Grenie4c70e072011-01-03 15:33:37 -03003860 u16 val = dib8000_read_word(st, 299) & 0xffef;
3861 val |= (onoff & 0x1) << 4;
Olivier Grenief8731f42009-09-18 04:08:43 -03003862
Olivier Grenie4c70e072011-01-03 15:33:37 -03003863 dprintk("pid filter enabled %d", onoff);
3864 return dib8000_write_word(st, 299, val);
Olivier Grenief8731f42009-09-18 04:08:43 -03003865}
3866EXPORT_SYMBOL(dib8000_pid_filter_ctrl);
3867
3868int dib8000_pid_filter(struct dvb_frontend *fe, u8 id, u16 pid, u8 onoff)
3869{
3870 struct dib8000_state *st = fe->demodulator_priv;
Olivier Grenie4c70e072011-01-03 15:33:37 -03003871 dprintk("Index %x, PID %d, OnOff %d", id, pid, onoff);
3872 return dib8000_write_word(st, 305 + id, onoff ? (1 << 13) | pid : 0);
Olivier Grenief8731f42009-09-18 04:08:43 -03003873}
3874EXPORT_SYMBOL(dib8000_pid_filter);
3875
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003876static const struct dvb_frontend_ops dib8000_ops = {
Mauro Carvalho Chehab490ecd62011-12-22 20:38:27 -03003877 .delsys = { SYS_ISDBT },
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003878 .info = {
3879 .name = "DiBcom 8000 ISDB-T",
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003880 .frequency_min = 44250000,
3881 .frequency_max = 867250000,
3882 .frequency_stepsize = 62500,
3883 .caps = FE_CAN_INVERSION_AUTO |
3884 FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
3885 FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
3886 FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO |
3887 FE_CAN_TRANSMISSION_MODE_AUTO | FE_CAN_GUARD_INTERVAL_AUTO | FE_CAN_RECOVER | FE_CAN_HIERARCHY_AUTO,
3888 },
3889
3890 .release = dib8000_release,
3891
3892 .init = dib8000_wakeup,
3893 .sleep = dib8000_sleep,
3894
Mauro Carvalho Chehab490ecd62011-12-22 20:38:27 -03003895 .set_frontend = dib8000_set_frontend,
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003896 .get_tune_settings = dib8000_fe_get_tune_settings,
Mauro Carvalho Chehab490ecd62011-12-22 20:38:27 -03003897 .get_frontend = dib8000_get_frontend,
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003898
3899 .read_status = dib8000_read_status,
3900 .read_ber = dib8000_read_ber,
3901 .read_signal_strength = dib8000_read_signal_strength,
3902 .read_snr = dib8000_read_snr,
3903 .read_ucblocks = dib8000_read_unc_blocks,
3904};
3905
3906struct dvb_frontend *dib8000_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr, struct dib8000_config *cfg)
3907{
3908 struct dvb_frontend *fe;
3909 struct dib8000_state *state;
3910
3911 dprintk("dib8000_attach");
3912
3913 state = kzalloc(sizeof(struct dib8000_state), GFP_KERNEL);
3914 if (state == NULL)
3915 return NULL;
Olivier Grenie4c70e072011-01-03 15:33:37 -03003916 fe = kzalloc(sizeof(struct dvb_frontend), GFP_KERNEL);
3917 if (fe == NULL)
Dan Carpentered54c0e2011-01-19 11:27:58 -03003918 goto error;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003919
3920 memcpy(&state->cfg, cfg, sizeof(struct dib8000_config));
3921 state->i2c.adap = i2c_adap;
3922 state->i2c.addr = i2c_addr;
Olivier Grenie5a0deee2011-05-03 12:27:33 -03003923 state->i2c.i2c_write_buffer = state->i2c_write_buffer;
3924 state->i2c.i2c_read_buffer = state->i2c_read_buffer;
Patrick Boettcher79fcce32011-08-03 12:08:21 -03003925 mutex_init(&state->i2c_buffer_lock);
3926 state->i2c.i2c_buffer_lock = &state->i2c_buffer_lock;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003927 state->gpio_val = cfg->gpio_val;
3928 state->gpio_dir = cfg->gpio_dir;
3929
3930 /* Ensure the output mode remains at the previous default if it's
3931 * not specifically set by the caller.
3932 */
3933 if ((state->cfg.output_mode != OUTMODE_MPEG2_SERIAL) && (state->cfg.output_mode != OUTMODE_MPEG2_PAR_GATED_CLK))
3934 state->cfg.output_mode = OUTMODE_MPEG2_FIFO;
3935
Olivier Grenie4c70e072011-01-03 15:33:37 -03003936 state->fe[0] = fe;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003937 fe->demodulator_priv = state;
Olivier Grenie4c70e072011-01-03 15:33:37 -03003938 memcpy(&state->fe[0]->ops, &dib8000_ops, sizeof(struct dvb_frontend_ops));
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003939
3940 state->timf_default = cfg->pll->timf;
3941
3942 if (dib8000_identify(&state->i2c) == 0)
3943 goto error;
3944
3945 dibx000_init_i2c_master(&state->i2c_master, DIB8000, state->i2c.adap, state->i2c.addr);
3946
Olivier Grenie0c32dbd2011-08-10 05:17:18 -03003947 /* init 8096p tuner adapter */
3948 strncpy(state->dib8096p_tuner_adap.name, "DiB8096P tuner interface",
3949 sizeof(state->dib8096p_tuner_adap.name));
3950 state->dib8096p_tuner_adap.algo = &dib8096p_tuner_xfer_algo;
3951 state->dib8096p_tuner_adap.algo_data = NULL;
3952 state->dib8096p_tuner_adap.dev.parent = state->i2c.adap->dev.parent;
3953 i2c_set_adapdata(&state->dib8096p_tuner_adap, state);
3954 i2c_add_adapter(&state->dib8096p_tuner_adap);
3955
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003956 dib8000_reset(fe);
3957
3958 dib8000_write_word(state, 285, (dib8000_read_word(state, 285) & ~0x60) | (3 << 5)); /* ber_rs_len = 3 */
Patrick Boettcher173a64c2013-04-22 12:45:52 -03003959 state->current_demod_bw = 6000;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003960
3961 return fe;
3962
Patrick Boettcher173a64c2013-04-22 12:45:52 -03003963error:
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03003964 kfree(state);
3965 return NULL;
3966}
3967
3968EXPORT_SYMBOL(dib8000_attach);
3969
3970MODULE_AUTHOR("Olivier Grenie <Olivier.Grenie@dibcom.fr, " "Patrick Boettcher <pboettcher@dibcom.fr>");
3971MODULE_DESCRIPTION("Driver for the DiBcom 8000 ISDB-T demodulator");
3972MODULE_LICENSE("GPL");