blob: 625e4210d2ddc40562092891e6d78171704947ed [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>
13#include "dvb_math.h"
14
15#include "dvb_frontend.h"
16
17#include "dib8000.h"
18
19#define LAYER_ALL -1
20#define LAYER_A 1
21#define LAYER_B 2
22#define LAYER_C 3
23
24#define FE_CALLBACK_TIME_NEVER 0xffffffff
Olivier Grenie4c70e072011-01-03 15:33:37 -030025#define MAX_NUMBER_OF_FRONTENDS 6
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -030026
Patrick Boettcher78f3bc62009-08-17 12:53:51 -030027static int debug;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -030028module_param(debug, int, 0644);
29MODULE_PARM_DESC(debug, "turn on debugging (default: 0)");
30
31#define dprintk(args...) do { if (debug) { printk(KERN_DEBUG "DiB8000: "); printk(args); printk("\n"); } } while (0)
32
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -030033#define FE_STATUS_TUNE_FAILED 0
34
35struct i2c_device {
36 struct i2c_adapter *adap;
37 u8 addr;
38};
39
40struct dib8000_state {
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -030041 struct dib8000_config cfg;
42
43 struct i2c_device i2c;
44
45 struct dibx000_i2c_master i2c_master;
46
47 u16 wbd_ref;
48
49 u8 current_band;
50 u32 current_bandwidth;
51 struct dibx000_agc_config *current_agc;
52 u32 timf;
53 u32 timf_default;
54
55 u8 div_force_off:1;
56 u8 div_state:1;
57 u16 div_sync_wait;
58
59 u8 agc_state;
60 u8 differential_constellation;
61 u8 diversity_onoff;
62
63 s16 ber_monitored_layer;
64 u16 gpio_dir;
65 u16 gpio_val;
66
67 u16 revision;
68 u8 isdbt_cfg_loaded;
69 enum frontend_tune_state tune_state;
70 u32 status;
Olivier Grenie4c70e072011-01-03 15:33:37 -030071
72 struct dvb_frontend *fe[MAX_NUMBER_OF_FRONTENDS];
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -030073};
74
75enum dib8000_power_mode {
76 DIB8000M_POWER_ALL = 0,
77 DIB8000M_POWER_INTERFACE_ONLY,
78};
79
80static u16 dib8000_i2c_read16(struct i2c_device *i2c, u16 reg)
81{
82 u8 wb[2] = { reg >> 8, reg & 0xff };
83 u8 rb[2];
84 struct i2c_msg msg[2] = {
85 {.addr = i2c->addr >> 1,.flags = 0,.buf = wb,.len = 2},
86 {.addr = i2c->addr >> 1,.flags = I2C_M_RD,.buf = rb,.len = 2},
87 };
88
89 if (i2c_transfer(i2c->adap, msg, 2) != 2)
90 dprintk("i2c read error on %d", reg);
91
92 return (rb[0] << 8) | rb[1];
93}
94
95static u16 dib8000_read_word(struct dib8000_state *state, u16 reg)
96{
97 return dib8000_i2c_read16(&state->i2c, reg);
98}
99
100static u32 dib8000_read32(struct dib8000_state *state, u16 reg)
101{
102 u16 rw[2];
103
104 rw[0] = dib8000_read_word(state, reg + 0);
105 rw[1] = dib8000_read_word(state, reg + 1);
106
107 return ((rw[0] << 16) | (rw[1]));
108}
109
110static int dib8000_i2c_write16(struct i2c_device *i2c, u16 reg, u16 val)
111{
112 u8 b[4] = {
113 (reg >> 8) & 0xff, reg & 0xff,
114 (val >> 8) & 0xff, val & 0xff,
115 };
116 struct i2c_msg msg = {
117 .addr = i2c->addr >> 1,.flags = 0,.buf = b,.len = 4
118 };
119 return i2c_transfer(i2c->adap, &msg, 1) != 1 ? -EREMOTEIO : 0;
120}
121
122static int dib8000_write_word(struct dib8000_state *state, u16 reg, u16 val)
123{
124 return dib8000_i2c_write16(&state->i2c, reg, val);
125}
126
Olivier Grenie4c70e072011-01-03 15:33:37 -0300127static const s16 coeff_2k_sb_1seg_dqpsk[8] = {
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300128 (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 -0300129 (920 << 5) | 0x09
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300130};
131
Olivier Grenie4c70e072011-01-03 15:33:37 -0300132static const s16 coeff_2k_sb_1seg[8] = {
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300133 (692 << 5) | 0x0b, (683 << 5) | 0x01, (519 << 5) | 0x09, (692 << 5) | 0x0b, 0 | 0x1f, 0 | 0x1f, 0 | 0x1f, 0 | 0x1f
134};
135
Olivier Grenie4c70e072011-01-03 15:33:37 -0300136static const s16 coeff_2k_sb_3seg_0dqpsk_1dqpsk[8] = {
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300137 (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 -0300138 (-931 << 5) | 0x0f
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300139};
140
Olivier Grenie4c70e072011-01-03 15:33:37 -0300141static const s16 coeff_2k_sb_3seg_0dqpsk[8] = {
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300142 (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 -0300143 (982 << 5) | 0x0c
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300144};
145
Olivier Grenie4c70e072011-01-03 15:33:37 -0300146static const s16 coeff_2k_sb_3seg_1dqpsk[8] = {
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300147 (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 -0300148 (-720 << 5) | 0x0d
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300149};
150
Olivier Grenie4c70e072011-01-03 15:33:37 -0300151static const s16 coeff_2k_sb_3seg[8] = {
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300152 (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 -0300153 (-610 << 5) | 0x0a
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300154};
155
Olivier Grenie4c70e072011-01-03 15:33:37 -0300156static const s16 coeff_4k_sb_1seg_dqpsk[8] = {
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300157 (-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 -0300158 (-922 << 5) | 0x0d
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300159};
160
Olivier Grenie4c70e072011-01-03 15:33:37 -0300161static const s16 coeff_4k_sb_1seg[8] = {
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300162 (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 -0300163 (-655 << 5) | 0x0a
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300164};
165
Olivier Grenie4c70e072011-01-03 15:33:37 -0300166static const s16 coeff_4k_sb_3seg_0dqpsk_1dqpsk[8] = {
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300167 (-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 -0300168 (-958 << 5) | 0x13
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300169};
170
Olivier Grenie4c70e072011-01-03 15:33:37 -0300171static const s16 coeff_4k_sb_3seg_0dqpsk[8] = {
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300172 (-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 -0300173 (-568 << 5) | 0x0f
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300174};
175
Olivier Grenie4c70e072011-01-03 15:33:37 -0300176static const s16 coeff_4k_sb_3seg_1dqpsk[8] = {
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300177 (-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 -0300178 (-848 << 5) | 0x13
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300179};
180
Olivier Grenie4c70e072011-01-03 15:33:37 -0300181static const s16 coeff_4k_sb_3seg[8] = {
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300182 (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 -0300183 (-869 << 5) | 0x13
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300184};
185
Olivier Grenie4c70e072011-01-03 15:33:37 -0300186static const s16 coeff_8k_sb_1seg_dqpsk[8] = {
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300187 (-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 -0300188 (-598 << 5) | 0x10
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300189};
190
Olivier Grenie4c70e072011-01-03 15:33:37 -0300191static const s16 coeff_8k_sb_1seg[8] = {
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300192 (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 -0300193 (585 << 5) | 0x0f
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300194};
195
Olivier Grenie4c70e072011-01-03 15:33:37 -0300196static const s16 coeff_8k_sb_3seg_0dqpsk_1dqpsk[8] = {
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300197 (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 -0300198 (0 << 5) | 0x14
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300199};
200
Olivier Grenie4c70e072011-01-03 15:33:37 -0300201static const s16 coeff_8k_sb_3seg_0dqpsk[8] = {
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300202 (-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 -0300203 (-877 << 5) | 0x15
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300204};
205
Olivier Grenie4c70e072011-01-03 15:33:37 -0300206static const s16 coeff_8k_sb_3seg_1dqpsk[8] = {
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300207 (-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 -0300208 (-921 << 5) | 0x14
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300209};
210
Olivier Grenie4c70e072011-01-03 15:33:37 -0300211static const s16 coeff_8k_sb_3seg[8] = {
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300212 (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 -0300213 (690 << 5) | 0x14
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300214};
215
Olivier Grenie4c70e072011-01-03 15:33:37 -0300216static const s16 ana_fe_coeff_3seg[24] = {
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300217 81, 80, 78, 74, 68, 61, 54, 45, 37, 28, 19, 11, 4, 1022, 1017, 1013, 1010, 1008, 1008, 1008, 1008, 1010, 1014, 1017
218};
219
Olivier Grenie4c70e072011-01-03 15:33:37 -0300220static const s16 ana_fe_coeff_1seg[24] = {
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300221 249, 226, 164, 82, 5, 981, 970, 988, 1018, 20, 31, 26, 8, 1012, 1000, 1018, 1012, 8, 15, 14, 9, 3, 1017, 1003
222};
223
Olivier Grenie4c70e072011-01-03 15:33:37 -0300224static const s16 ana_fe_coeff_13seg[24] = {
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300225 396, 305, 105, -51, -77, -12, 41, 31, -11, -30, -11, 14, 15, -2, -13, -7, 5, 8, 1, -6, -7, -3, 0, 1
226};
227
228static u16 fft_to_mode(struct dib8000_state *state)
229{
230 u16 mode;
Olivier Grenie4c70e072011-01-03 15:33:37 -0300231 switch (state->fe[0]->dtv_property_cache.transmission_mode) {
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300232 case TRANSMISSION_MODE_2K:
233 mode = 1;
234 break;
235 case TRANSMISSION_MODE_4K:
236 mode = 2;
237 break;
238 default:
239 case TRANSMISSION_MODE_AUTO:
240 case TRANSMISSION_MODE_8K:
241 mode = 3;
242 break;
243 }
244 return mode;
245}
246
247static void dib8000_set_acquisition_mode(struct dib8000_state *state)
248{
249 u16 nud = dib8000_read_word(state, 298);
250 nud |= (1 << 3) | (1 << 0);
251 dprintk("acquisition mode activated");
252 dib8000_write_word(state, 298, nud);
253}
Olivier Grenie4c70e072011-01-03 15:33:37 -0300254static int dib8000_set_output_mode(struct dvb_frontend *fe, int mode)
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300255{
Olivier Grenie4c70e072011-01-03 15:33:37 -0300256 struct dib8000_state *state = fe->demodulator_priv;
257
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300258 u16 outreg, fifo_threshold, smo_mode, sram = 0x0205; /* by default SDRAM deintlv is enabled */
259
260 outreg = 0;
261 fifo_threshold = 1792;
262 smo_mode = (dib8000_read_word(state, 299) & 0x0050) | (1 << 1);
263
Olivier Grenie4c70e072011-01-03 15:33:37 -0300264 dprintk("-I- Setting output mode for demod %p to %d", &state->fe[0], mode);
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300265
266 switch (mode) {
267 case OUTMODE_MPEG2_PAR_GATED_CLK: // STBs with parallel gated clock
268 outreg = (1 << 10); /* 0x0400 */
269 break;
270 case OUTMODE_MPEG2_PAR_CONT_CLK: // STBs with parallel continues clock
271 outreg = (1 << 10) | (1 << 6); /* 0x0440 */
272 break;
273 case OUTMODE_MPEG2_SERIAL: // STBs with serial input
274 outreg = (1 << 10) | (2 << 6) | (0 << 1); /* 0x0482 */
275 break;
276 case OUTMODE_DIVERSITY:
277 if (state->cfg.hostbus_diversity) {
278 outreg = (1 << 10) | (4 << 6); /* 0x0500 */
279 sram &= 0xfdff;
280 } else
281 sram |= 0x0c00;
282 break;
283 case OUTMODE_MPEG2_FIFO: // e.g. USB feeding
284 smo_mode |= (3 << 1);
285 fifo_threshold = 512;
286 outreg = (1 << 10) | (5 << 6);
287 break;
288 case OUTMODE_HIGH_Z: // disable
289 outreg = 0;
290 break;
291
292 case OUTMODE_ANALOG_ADC:
293 outreg = (1 << 10) | (3 << 6);
294 dib8000_set_acquisition_mode(state);
295 break;
296
297 default:
Olivier Grenie4c70e072011-01-03 15:33:37 -0300298 dprintk("Unhandled output_mode passed to be set for demod %p", &state->fe[0]);
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300299 return -EINVAL;
300 }
301
302 if (state->cfg.output_mpeg2_in_188_bytes)
303 smo_mode |= (1 << 5);
304
305 dib8000_write_word(state, 299, smo_mode);
306 dib8000_write_word(state, 300, fifo_threshold); /* synchronous fread */
307 dib8000_write_word(state, 1286, outreg);
308 dib8000_write_word(state, 1291, sram);
309
310 return 0;
311}
312
313static int dib8000_set_diversity_in(struct dvb_frontend *fe, int onoff)
314{
315 struct dib8000_state *state = fe->demodulator_priv;
316 u16 sync_wait = dib8000_read_word(state, 273) & 0xfff0;
317
318 if (!state->differential_constellation) {
319 dib8000_write_word(state, 272, 1 << 9); //dvsy_off_lmod4 = 1
320 dib8000_write_word(state, 273, sync_wait | (1 << 2) | 2); // sync_enable = 1; comb_mode = 2
321 } else {
322 dib8000_write_word(state, 272, 0); //dvsy_off_lmod4 = 0
323 dib8000_write_word(state, 273, sync_wait); // sync_enable = 0; comb_mode = 0
324 }
325 state->diversity_onoff = onoff;
326
327 switch (onoff) {
328 case 0: /* only use the internal way - not the diversity input */
329 dib8000_write_word(state, 270, 1);
330 dib8000_write_word(state, 271, 0);
331 break;
332 case 1: /* both ways */
333 dib8000_write_word(state, 270, 6);
334 dib8000_write_word(state, 271, 6);
335 break;
336 case 2: /* only the diversity input */
337 dib8000_write_word(state, 270, 0);
338 dib8000_write_word(state, 271, 1);
339 break;
340 }
341 return 0;
342}
343
344static void dib8000_set_power_mode(struct dib8000_state *state, enum dib8000_power_mode mode)
345{
346 /* by default everything is going to be powered off */
347 u16 reg_774 = 0x3fff, reg_775 = 0xffff, reg_776 = 0xffff,
Olivier Grenie4c70e072011-01-03 15:33:37 -0300348 reg_900 = (dib8000_read_word(state, 900) & 0xfffc) | 0x3, reg_1280 = (dib8000_read_word(state, 1280) & 0x00ff) | 0xff00;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300349
350 /* now, depending on the requested mode, we power on */
351 switch (mode) {
352 /* power up everything in the demod */
353 case DIB8000M_POWER_ALL:
354 reg_774 = 0x0000;
355 reg_775 = 0x0000;
356 reg_776 = 0x0000;
357 reg_900 &= 0xfffc;
358 reg_1280 &= 0x00ff;
359 break;
360 case DIB8000M_POWER_INTERFACE_ONLY:
361 reg_1280 &= 0x00ff;
362 break;
363 }
364
365 dprintk("powermode : 774 : %x ; 775 : %x; 776 : %x ; 900 : %x; 1280 : %x", reg_774, reg_775, reg_776, reg_900, reg_1280);
366 dib8000_write_word(state, 774, reg_774);
367 dib8000_write_word(state, 775, reg_775);
368 dib8000_write_word(state, 776, reg_776);
369 dib8000_write_word(state, 900, reg_900);
370 dib8000_write_word(state, 1280, reg_1280);
371}
372
373static int dib8000_set_adc_state(struct dib8000_state *state, enum dibx000_adc_states no)
374{
375 int ret = 0;
376 u16 reg_907 = dib8000_read_word(state, 907), reg_908 = dib8000_read_word(state, 908);
377
378 switch (no) {
379 case DIBX000_SLOW_ADC_ON:
380 reg_908 |= (1 << 1) | (1 << 0);
381 ret |= dib8000_write_word(state, 908, reg_908);
382 reg_908 &= ~(1 << 1);
383 break;
384
385 case DIBX000_SLOW_ADC_OFF:
386 reg_908 |= (1 << 1) | (1 << 0);
387 break;
388
389 case DIBX000_ADC_ON:
390 reg_907 &= 0x0fff;
391 reg_908 &= 0x0003;
392 break;
393
394 case DIBX000_ADC_OFF: // leave the VBG voltage on
395 reg_907 |= (1 << 14) | (1 << 13) | (1 << 12);
396 reg_908 |= (1 << 5) | (1 << 4) | (1 << 3) | (1 << 2);
397 break;
398
399 case DIBX000_VBG_ENABLE:
400 reg_907 &= ~(1 << 15);
401 break;
402
403 case DIBX000_VBG_DISABLE:
404 reg_907 |= (1 << 15);
405 break;
406
407 default:
408 break;
409 }
410
411 ret |= dib8000_write_word(state, 907, reg_907);
412 ret |= dib8000_write_word(state, 908, reg_908);
413
414 return ret;
415}
416
Olivier Grenie4c70e072011-01-03 15:33:37 -0300417static int dib8000_set_bandwidth(struct dvb_frontend *fe, u32 bw)
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300418{
Olivier Grenie4c70e072011-01-03 15:33:37 -0300419 struct dib8000_state *state = fe->demodulator_priv;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300420 u32 timf;
421
422 if (bw == 0)
423 bw = 6000;
424
425 if (state->timf == 0) {
426 dprintk("using default timf");
427 timf = state->timf_default;
428 } else {
429 dprintk("using updated timf");
430 timf = state->timf;
431 }
432
433 dib8000_write_word(state, 29, (u16) ((timf >> 16) & 0xffff));
434 dib8000_write_word(state, 30, (u16) ((timf) & 0xffff));
435
436 return 0;
437}
438
439static int dib8000_sad_calib(struct dib8000_state *state)
440{
441/* internal */
442 dib8000_write_word(state, 923, (0 << 1) | (0 << 0));
443 dib8000_write_word(state, 924, 776); // 0.625*3.3 / 4096
444
445 /* do the calibration */
446 dib8000_write_word(state, 923, (1 << 0));
447 dib8000_write_word(state, 923, (0 << 0));
448
449 msleep(1);
450 return 0;
451}
452
453int dib8000_set_wbd_ref(struct dvb_frontend *fe, u16 value)
454{
455 struct dib8000_state *state = fe->demodulator_priv;
456 if (value > 4095)
457 value = 4095;
458 state->wbd_ref = value;
459 return dib8000_write_word(state, 106, value);
460}
461
462EXPORT_SYMBOL(dib8000_set_wbd_ref);
463static void dib8000_reset_pll_common(struct dib8000_state *state, const struct dibx000_bandwidth_config *bw)
464{
465 dprintk("ifreq: %d %x, inversion: %d", bw->ifreq, bw->ifreq, bw->ifreq >> 25);
466 dib8000_write_word(state, 23, (u16) (((bw->internal * 1000) >> 16) & 0xffff)); /* P_sec_len */
467 dib8000_write_word(state, 24, (u16) ((bw->internal * 1000) & 0xffff));
468 dib8000_write_word(state, 27, (u16) ((bw->ifreq >> 16) & 0x01ff));
469 dib8000_write_word(state, 28, (u16) (bw->ifreq & 0xffff));
470 dib8000_write_word(state, 26, (u16) ((bw->ifreq >> 25) & 0x0003));
471
472 dib8000_write_word(state, 922, bw->sad_cfg);
473}
474
475static void dib8000_reset_pll(struct dib8000_state *state)
476{
477 const struct dibx000_bandwidth_config *pll = state->cfg.pll;
478 u16 clk_cfg1;
479
480 // clk_cfg0
481 dib8000_write_word(state, 901, (pll->pll_prediv << 8) | (pll->pll_ratio << 0));
482
483 // clk_cfg1
484 clk_cfg1 = (1 << 10) | (0 << 9) | (pll->IO_CLK_en_core << 8) |
Olivier Grenie4c70e072011-01-03 15:33:37 -0300485 (pll->bypclk_div << 5) | (pll->enable_refdiv << 4) | (1 << 3) | (pll->pll_range << 1) | (pll->pll_reset << 0);
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300486
487 dib8000_write_word(state, 902, clk_cfg1);
488 clk_cfg1 = (clk_cfg1 & 0xfff7) | (pll->pll_bypass << 3);
489 dib8000_write_word(state, 902, clk_cfg1);
490
491 dprintk("clk_cfg1: 0x%04x", clk_cfg1); /* 0x507 1 0 1 000 0 0 11 1 */
492
493 /* smpl_cfg: P_refclksel=2, P_ensmplsel=1 nodivsmpl=1 */
494 if (state->cfg.pll->ADClkSrc == 0)
495 dib8000_write_word(state, 904, (0 << 15) | (0 << 12) | (0 << 10) | (pll->modulo << 8) | (pll->ADClkSrc << 7) | (0 << 1));
496 else if (state->cfg.refclksel != 0)
497 dib8000_write_word(state, 904,
Olivier Grenie4c70e072011-01-03 15:33:37 -0300498 (0 << 15) | (1 << 12) | ((state->cfg.refclksel & 0x3) << 10) | (pll->modulo << 8) | (pll->
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300499 ADClkSrc << 7) | (0 << 1));
500 else
501 dib8000_write_word(state, 904, (0 << 15) | (1 << 12) | (3 << 10) | (pll->modulo << 8) | (pll->ADClkSrc << 7) | (0 << 1));
502
503 dib8000_reset_pll_common(state, pll);
504}
505
506static int dib8000_reset_gpio(struct dib8000_state *st)
507{
508 /* reset the GPIOs */
509 dib8000_write_word(st, 1029, st->cfg.gpio_dir);
510 dib8000_write_word(st, 1030, st->cfg.gpio_val);
511
512 /* TODO 782 is P_gpio_od */
513
514 dib8000_write_word(st, 1032, st->cfg.gpio_pwm_pos);
515
516 dib8000_write_word(st, 1037, st->cfg.pwm_freq_div);
517 return 0;
518}
519
520static int dib8000_cfg_gpio(struct dib8000_state *st, u8 num, u8 dir, u8 val)
521{
522 st->cfg.gpio_dir = dib8000_read_word(st, 1029);
523 st->cfg.gpio_dir &= ~(1 << num); /* reset the direction bit */
524 st->cfg.gpio_dir |= (dir & 0x1) << num; /* set the new direction */
525 dib8000_write_word(st, 1029, st->cfg.gpio_dir);
526
527 st->cfg.gpio_val = dib8000_read_word(st, 1030);
528 st->cfg.gpio_val &= ~(1 << num); /* reset the direction bit */
529 st->cfg.gpio_val |= (val & 0x01) << num; /* set the new value */
530 dib8000_write_word(st, 1030, st->cfg.gpio_val);
531
532 dprintk("gpio dir: %x: gpio val: %x", st->cfg.gpio_dir, st->cfg.gpio_val);
533
534 return 0;
535}
536
537int dib8000_set_gpio(struct dvb_frontend *fe, u8 num, u8 dir, u8 val)
538{
539 struct dib8000_state *state = fe->demodulator_priv;
540 return dib8000_cfg_gpio(state, num, dir, val);
541}
542
543EXPORT_SYMBOL(dib8000_set_gpio);
544static const u16 dib8000_defaults[] = {
545 /* auto search configuration - lock0 by default waiting
546 * for cpil_lock; lock1 cpil_lock; lock2 tmcc_sync_lock */
547 3, 7,
548 0x0004,
549 0x0400,
550 0x0814,
551
552 12, 11,
553 0x001b,
554 0x7740,
555 0x005b,
556 0x8d80,
557 0x01c9,
558 0xc380,
559 0x0000,
560 0x0080,
561 0x0000,
562 0x0090,
563 0x0001,
564 0xd4c0,
565
566 /*1, 32,
Olivier Grenie4c70e072011-01-03 15:33:37 -0300567 0x6680 // P_corm_thres Lock algorithms configuration */
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300568
569 11, 80, /* set ADC level to -16 */
570 (1 << 13) - 825 - 117,
571 (1 << 13) - 837 - 117,
572 (1 << 13) - 811 - 117,
573 (1 << 13) - 766 - 117,
574 (1 << 13) - 737 - 117,
575 (1 << 13) - 693 - 117,
576 (1 << 13) - 648 - 117,
577 (1 << 13) - 619 - 117,
578 (1 << 13) - 575 - 117,
579 (1 << 13) - 531 - 117,
580 (1 << 13) - 501 - 117,
581
582 4, 108,
583 0,
584 0,
585 0,
586 0,
587
588 1, 175,
589 0x0410,
590 1, 179,
591 8192, // P_fft_nb_to_cut
592
593 6, 181,
594 0x2800, // P_coff_corthres_ ( 2k 4k 8k ) 0x2800
595 0x2800,
596 0x2800,
597 0x2800, // P_coff_cpilthres_ ( 2k 4k 8k ) 0x2800
598 0x2800,
599 0x2800,
600
601 2, 193,
602 0x0666, // P_pha3_thres
603 0x0000, // P_cti_use_cpe, P_cti_use_prog
604
605 2, 205,
606 0x200f, // P_cspu_regul, P_cspu_win_cut
607 0x000f, // P_des_shift_work
608
609 5, 215,
610 0x023d, // P_adp_regul_cnt
611 0x00a4, // P_adp_noise_cnt
612 0x00a4, // P_adp_regul_ext
613 0x7ff0, // P_adp_noise_ext
614 0x3ccc, // P_adp_fil
615
616 1, 230,
617 0x0000, // P_2d_byp_ti_num
618
619 1, 263,
620 0x800, //P_equal_thres_wgn
621
622 1, 268,
623 (2 << 9) | 39, // P_equal_ctrl_synchro, P_equal_speedmode
624
625 1, 270,
626 0x0001, // P_div_lock0_wait
627 1, 285,
628 0x0020, //p_fec_
629 1, 299,
630 0x0062, // P_smo_mode, P_smo_rs_discard, P_smo_fifo_flush, P_smo_pid_parse, P_smo_error_discard
631
632 1, 338,
633 (1 << 12) | // P_ctrl_corm_thres4pre_freq_inh=1
Olivier Grenie4c70e072011-01-03 15:33:37 -0300634 (1 << 10) | // P_ctrl_pre_freq_mode_sat=1
635 (0 << 9) | // P_ctrl_pre_freq_inh=0
636 (3 << 5) | // P_ctrl_pre_freq_step=3
637 (1 << 0), // P_pre_freq_win_len=1
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300638
639 1, 903,
640 (0 << 4) | 2, // P_divclksel=0 P_divbitsel=2 (was clk=3,bit=1 for MPW)
641
642 0,
643};
644
645static u16 dib8000_identify(struct i2c_device *client)
646{
647 u16 value;
648
649 //because of glitches sometimes
650 value = dib8000_i2c_read16(client, 896);
651
652 if ((value = dib8000_i2c_read16(client, 896)) != 0x01b3) {
653 dprintk("wrong Vendor ID (read=0x%x)", value);
654 return 0;
655 }
656
657 value = dib8000_i2c_read16(client, 897);
658 if (value != 0x8000 && value != 0x8001 && value != 0x8002) {
659 dprintk("wrong Device ID (%x)", value);
660 return 0;
661 }
662
663 switch (value) {
664 case 0x8000:
665 dprintk("found DiB8000A");
666 break;
667 case 0x8001:
668 dprintk("found DiB8000B");
669 break;
670 case 0x8002:
671 dprintk("found DiB8000C");
672 break;
673 }
674 return value;
675}
676
677static int dib8000_reset(struct dvb_frontend *fe)
678{
679 struct dib8000_state *state = fe->demodulator_priv;
680
681 dib8000_write_word(state, 1287, 0x0003); /* sram lead in, rdy */
682
683 if ((state->revision = dib8000_identify(&state->i2c)) == 0)
684 return -EINVAL;
685
686 if (state->revision == 0x8000)
687 dprintk("error : dib8000 MA not supported");
688
689 dibx000_reset_i2c_master(&state->i2c_master);
690
691 dib8000_set_power_mode(state, DIB8000M_POWER_ALL);
692
693 /* always leave the VBG voltage on - it consumes almost nothing but takes a long time to start */
694 dib8000_set_adc_state(state, DIBX000_VBG_ENABLE);
695
696 /* restart all parts */
697 dib8000_write_word(state, 770, 0xffff);
698 dib8000_write_word(state, 771, 0xffff);
699 dib8000_write_word(state, 772, 0xfffc);
700 dib8000_write_word(state, 898, 0x000c); // sad
701 dib8000_write_word(state, 1280, 0x004d);
702 dib8000_write_word(state, 1281, 0x000c);
703
704 dib8000_write_word(state, 770, 0x0000);
705 dib8000_write_word(state, 771, 0x0000);
706 dib8000_write_word(state, 772, 0x0000);
707 dib8000_write_word(state, 898, 0x0004); // sad
708 dib8000_write_word(state, 1280, 0x0000);
709 dib8000_write_word(state, 1281, 0x0000);
710
711 /* drives */
712 if (state->cfg.drives)
713 dib8000_write_word(state, 906, state->cfg.drives);
714 else {
715 dprintk("using standard PAD-drive-settings, please adjust settings in config-struct to be optimal.");
716 dib8000_write_word(state, 906, 0x2d98); // min drive SDRAM - not optimal - adjust
717 }
718
719 dib8000_reset_pll(state);
720
721 if (dib8000_reset_gpio(state) != 0)
722 dprintk("GPIO reset was not successful.");
723
Olivier Grenie4c70e072011-01-03 15:33:37 -0300724 if (dib8000_set_output_mode(fe, OUTMODE_HIGH_Z) != 0)
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300725 dprintk("OUTPUT_MODE could not be resetted.");
726
727 state->current_agc = NULL;
728
729 // P_iqc_alpha_pha, P_iqc_alpha_amp, P_iqc_dcc_alpha, ...
730 /* P_iqc_ca2 = 0; P_iqc_impnc_on = 0; P_iqc_mode = 0; */
731 if (state->cfg.pll->ifreq == 0)
732 dib8000_write_word(state, 40, 0x0755); /* P_iqc_corr_inh = 0 enable IQcorr block */
733 else
734 dib8000_write_word(state, 40, 0x1f55); /* P_iqc_corr_inh = 1 disable IQcorr block */
735
736 {
737 u16 l = 0, r;
738 const u16 *n;
739 n = dib8000_defaults;
740 l = *n++;
741 while (l) {
742 r = *n++;
743 do {
744 dib8000_write_word(state, r, *n++);
745 r++;
746 } while (--l);
747 l = *n++;
748 }
749 }
750 state->isdbt_cfg_loaded = 0;
751
752 //div_cfg override for special configs
753 if (state->cfg.div_cfg != 0)
754 dib8000_write_word(state, 903, state->cfg.div_cfg);
755
756 /* unforce divstr regardless whether i2c enumeration was done or not */
757 dib8000_write_word(state, 1285, dib8000_read_word(state, 1285) & ~(1 << 1));
758
Olivier Grenie4c70e072011-01-03 15:33:37 -0300759 dib8000_set_bandwidth(fe, 6000);
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300760
761 dib8000_set_adc_state(state, DIBX000_SLOW_ADC_ON);
762 dib8000_sad_calib(state);
763 dib8000_set_adc_state(state, DIBX000_SLOW_ADC_OFF);
764
765 dib8000_set_power_mode(state, DIB8000M_POWER_INTERFACE_ONLY);
766
767 return 0;
768}
769
770static void dib8000_restart_agc(struct dib8000_state *state)
771{
772 // P_restart_iqc & P_restart_agc
773 dib8000_write_word(state, 770, 0x0a00);
774 dib8000_write_word(state, 770, 0x0000);
775}
776
777static int dib8000_update_lna(struct dib8000_state *state)
778{
779 u16 dyn_gain;
780
781 if (state->cfg.update_lna) {
782 // read dyn_gain here (because it is demod-dependent and not tuner)
783 dyn_gain = dib8000_read_word(state, 390);
784
Olivier Grenie4c70e072011-01-03 15:33:37 -0300785 if (state->cfg.update_lna(state->fe[0], dyn_gain)) { // LNA has changed
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300786 dib8000_restart_agc(state);
787 return 1;
788 }
789 }
790 return 0;
791}
792
793static int dib8000_set_agc_config(struct dib8000_state *state, u8 band)
794{
795 struct dibx000_agc_config *agc = NULL;
796 int i;
797 if (state->current_band == band && state->current_agc != NULL)
798 return 0;
799 state->current_band = band;
800
801 for (i = 0; i < state->cfg.agc_config_count; i++)
802 if (state->cfg.agc[i].band_caps & band) {
803 agc = &state->cfg.agc[i];
804 break;
805 }
806
807 if (agc == NULL) {
808 dprintk("no valid AGC configuration found for band 0x%02x", band);
809 return -EINVAL;
810 }
811
812 state->current_agc = agc;
813
814 /* AGC */
815 dib8000_write_word(state, 76, agc->setup);
816 dib8000_write_word(state, 77, agc->inv_gain);
817 dib8000_write_word(state, 78, agc->time_stabiliz);
818 dib8000_write_word(state, 101, (agc->alpha_level << 12) | agc->thlock);
819
820 // Demod AGC loop configuration
821 dib8000_write_word(state, 102, (agc->alpha_mant << 5) | agc->alpha_exp);
822 dib8000_write_word(state, 103, (agc->beta_mant << 6) | agc->beta_exp);
823
824 dprintk("WBD: ref: %d, sel: %d, active: %d, alpha: %d",
825 state->wbd_ref != 0 ? state->wbd_ref : agc->wbd_ref, agc->wbd_sel, !agc->perform_agc_softsplit, agc->wbd_sel);
826
827 /* AGC continued */
828 if (state->wbd_ref != 0)
829 dib8000_write_word(state, 106, state->wbd_ref);
830 else // use default
831 dib8000_write_word(state, 106, agc->wbd_ref);
832 dib8000_write_word(state, 107, (agc->wbd_alpha << 9) | (agc->perform_agc_softsplit << 8));
833 dib8000_write_word(state, 108, agc->agc1_max);
834 dib8000_write_word(state, 109, agc->agc1_min);
835 dib8000_write_word(state, 110, agc->agc2_max);
836 dib8000_write_word(state, 111, agc->agc2_min);
837 dib8000_write_word(state, 112, (agc->agc1_pt1 << 8) | agc->agc1_pt2);
838 dib8000_write_word(state, 113, (agc->agc1_slope1 << 8) | agc->agc1_slope2);
839 dib8000_write_word(state, 114, (agc->agc2_pt1 << 8) | agc->agc2_pt2);
840 dib8000_write_word(state, 115, (agc->agc2_slope1 << 8) | agc->agc2_slope2);
841
842 dib8000_write_word(state, 75, agc->agc1_pt3);
843 dib8000_write_word(state, 923, (dib8000_read_word(state, 923) & 0xffe3) | (agc->wbd_inv << 4) | (agc->wbd_sel << 2)); /*LB : 929 -> 923 */
844
845 return 0;
846}
847
Olivier Grenie03245a52009-12-04 13:27:57 -0300848void dib8000_pwm_agc_reset(struct dvb_frontend *fe)
849{
850 struct dib8000_state *state = fe->demodulator_priv;
851 dib8000_set_adc_state(state, DIBX000_ADC_ON);
852 dib8000_set_agc_config(state, (unsigned char)(BAND_OF_FREQUENCY(fe->dtv_property_cache.frequency / 1000)));
853}
854EXPORT_SYMBOL(dib8000_pwm_agc_reset);
855
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300856static int dib8000_agc_soft_split(struct dib8000_state *state)
857{
858 u16 agc, split_offset;
859
860 if (!state->current_agc || !state->current_agc->perform_agc_softsplit || state->current_agc->split.max == 0)
861 return FE_CALLBACK_TIME_NEVER;
862
863 // n_agc_global
864 agc = dib8000_read_word(state, 390);
865
866 if (agc > state->current_agc->split.min_thres)
867 split_offset = state->current_agc->split.min;
868 else if (agc < state->current_agc->split.max_thres)
869 split_offset = state->current_agc->split.max;
870 else
871 split_offset = state->current_agc->split.max *
Olivier Grenie4c70e072011-01-03 15:33:37 -0300872 (agc - state->current_agc->split.min_thres) / (state->current_agc->split.max_thres - state->current_agc->split.min_thres);
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300873
874 dprintk("AGC split_offset: %d", split_offset);
875
876 // P_agc_force_split and P_agc_split_offset
877 dib8000_write_word(state, 107, (dib8000_read_word(state, 107) & 0xff00) | split_offset);
878 return 5000;
879}
880
881static int dib8000_agc_startup(struct dvb_frontend *fe)
882{
883 struct dib8000_state *state = fe->demodulator_priv;
884 enum frontend_tune_state *tune_state = &state->tune_state;
885
886 int ret = 0;
887
888 switch (*tune_state) {
889 case CT_AGC_START:
890 // set power-up level: interf+analog+AGC
891
892 dib8000_set_adc_state(state, DIBX000_ADC_ON);
893
894 if (dib8000_set_agc_config(state, (unsigned char)(BAND_OF_FREQUENCY(fe->dtv_property_cache.frequency / 1000))) != 0) {
895 *tune_state = CT_AGC_STOP;
896 state->status = FE_STATUS_TUNE_FAILED;
897 break;
898 }
899
900 ret = 70;
901 *tune_state = CT_AGC_STEP_0;
902 break;
903
904 case CT_AGC_STEP_0:
905 //AGC initialization
906 if (state->cfg.agc_control)
Olivier Grenie4c70e072011-01-03 15:33:37 -0300907 state->cfg.agc_control(fe, 1);
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300908
909 dib8000_restart_agc(state);
910
911 // wait AGC rough lock time
912 ret = 50;
913 *tune_state = CT_AGC_STEP_1;
914 break;
915
916 case CT_AGC_STEP_1:
917 // wait AGC accurate lock time
918 ret = 70;
919
920 if (dib8000_update_lna(state))
921 // wait only AGC rough lock time
922 ret = 50;
923 else
924 *tune_state = CT_AGC_STEP_2;
925 break;
926
927 case CT_AGC_STEP_2:
928 dib8000_agc_soft_split(state);
929
930 if (state->cfg.agc_control)
Olivier Grenie4c70e072011-01-03 15:33:37 -0300931 state->cfg.agc_control(fe, 0);
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300932
933 *tune_state = CT_AGC_STOP;
934 break;
935 default:
936 ret = dib8000_agc_soft_split(state);
937 break;
938 }
939 return ret;
940
941}
942
Olivier Grenie4c70e072011-01-03 15:33:37 -0300943static const s32 lut_1000ln_mant[] =
Olivier Grenie03245a52009-12-04 13:27:57 -0300944{
Olivier Grenie9c783032009-12-07 07:49:40 -0300945 908, 7003, 7090, 7170, 7244, 7313, 7377, 7438, 7495, 7549, 7600
Olivier Grenie03245a52009-12-04 13:27:57 -0300946};
947
Olivier Grenie4c70e072011-01-03 15:33:37 -0300948s32 dib8000_get_adc_power(struct dvb_frontend *fe, u8 mode)
Olivier Grenie03245a52009-12-04 13:27:57 -0300949{
Olivier Grenie4c70e072011-01-03 15:33:37 -0300950 struct dib8000_state *state = fe->demodulator_priv;
951 u32 ix = 0, tmp_val = 0, exp = 0, mant = 0;
952 s32 val;
Olivier Grenie03245a52009-12-04 13:27:57 -0300953
Olivier Grenie4c70e072011-01-03 15:33:37 -0300954 val = dib8000_read32(state, 384);
955 /* mode = 1 : ln_agcpower calc using mant-exp conversion and mantis look up table */
956 if (mode) {
957 tmp_val = val;
958 while (tmp_val >>= 1)
959 exp++;
960 mant = (val * 1000 / (1<<exp));
961 ix = (u8)((mant-1000)/100); /* index of the LUT */
962 val = (lut_1000ln_mant[ix] + 693*(exp-20) - 6908); /* 1000 * ln(adcpower_real) ; 693 = 1000ln(2) ; 6908 = 1000*ln(1000) ; 20 comes from adc_real = adc_pow_int / 2**20 */
963 val = (val*256)/1000;
964 }
965 return val;
Olivier Grenie03245a52009-12-04 13:27:57 -0300966}
967EXPORT_SYMBOL(dib8000_get_adc_power);
968
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300969static void dib8000_update_timf(struct dib8000_state *state)
970{
971 u32 timf = state->timf = dib8000_read32(state, 435);
972
973 dib8000_write_word(state, 29, (u16) (timf >> 16));
974 dib8000_write_word(state, 30, (u16) (timf & 0xffff));
975 dprintk("Updated timing frequency: %d (default: %d)", state->timf, state->timf_default);
976}
977
978static void dib8000_set_channel(struct dib8000_state *state, u8 seq, u8 autosearching)
979{
980 u16 mode, max_constellation, seg_diff_mask = 0, nbseg_diff = 0;
981 u8 guard, crate, constellation, timeI;
982 u8 permu_seg[] = { 6, 5, 7, 4, 8, 3, 9, 2, 10, 1, 11, 0, 12 };
983 u16 i, coeff[4], P_cfr_left_edge = 0, P_cfr_right_edge = 0, seg_mask13 = 0x1fff; // All 13 segments enabled
Hans Verkuil516e24d2009-11-25 18:39:31 -0300984 const s16 *ncoeff = NULL, *ana_fe;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300985 u16 tmcc_pow = 0;
986 u16 coff_pow = 0x2800;
987 u16 init_prbs = 0xfff;
988 u16 ana_gain = 0;
989 u16 adc_target_16dB[11] = {
990 (1 << 13) - 825 - 117,
991 (1 << 13) - 837 - 117,
992 (1 << 13) - 811 - 117,
993 (1 << 13) - 766 - 117,
994 (1 << 13) - 737 - 117,
995 (1 << 13) - 693 - 117,
996 (1 << 13) - 648 - 117,
997 (1 << 13) - 619 - 117,
998 (1 << 13) - 575 - 117,
999 (1 << 13) - 531 - 117,
1000 (1 << 13) - 501 - 117
1001 };
1002
1003 if (state->ber_monitored_layer != LAYER_ALL)
1004 dib8000_write_word(state, 285, (dib8000_read_word(state, 285) & 0x60) | state->ber_monitored_layer);
1005 else
1006 dib8000_write_word(state, 285, dib8000_read_word(state, 285) & 0x60);
1007
1008 i = dib8000_read_word(state, 26) & 1; // P_dds_invspec
Olivier Grenie4c70e072011-01-03 15:33:37 -03001009 dib8000_write_word(state, 26, state->fe[0]->dtv_property_cache.inversion ^ i);
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001010
Olivier Grenie4c70e072011-01-03 15:33:37 -03001011 if (state->fe[0]->dtv_property_cache.isdbt_sb_mode) {
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001012 //compute new dds_freq for the seg and adjust prbs
1013 int seg_offset =
Olivier Grenie4c70e072011-01-03 15:33:37 -03001014 state->fe[0]->dtv_property_cache.isdbt_sb_segment_idx - (state->fe[0]->dtv_property_cache.isdbt_sb_segment_count / 2) -
1015 (state->fe[0]->dtv_property_cache.isdbt_sb_segment_count % 2);
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001016 int clk = state->cfg.pll->internal;
1017 u32 segtodds = ((u32) (430 << 23) / clk) << 3; // segtodds = SegBW / Fclk * pow(2,26)
1018 int dds_offset = seg_offset * segtodds;
1019 int new_dds, sub_channel;
Olivier Grenie4c70e072011-01-03 15:33:37 -03001020 if ((state->fe[0]->dtv_property_cache.isdbt_sb_segment_count % 2) == 0) // if even
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001021 dds_offset -= (int)(segtodds / 2);
1022
1023 if (state->cfg.pll->ifreq == 0) {
Olivier Grenie4c70e072011-01-03 15:33:37 -03001024 if ((state->fe[0]->dtv_property_cache.inversion ^ i) == 0) {
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001025 dib8000_write_word(state, 26, dib8000_read_word(state, 26) | 1);
1026 new_dds = dds_offset;
1027 } else
1028 new_dds = dds_offset;
1029
1030 // We shift tuning frequency if the wanted segment is :
1031 // - the segment of center frequency with an odd total number of segments
1032 // - the segment to the left of center frequency with an even total number of segments
1033 // - the segment to the right of center frequency with an even total number of segments
Olivier Grenie4c70e072011-01-03 15:33:37 -03001034 if ((state->fe[0]->dtv_property_cache.delivery_system == SYS_ISDBT) && (state->fe[0]->dtv_property_cache.isdbt_sb_mode == 1)
1035 && (((state->fe[0]->dtv_property_cache.isdbt_sb_segment_count % 2)
1036 && (state->fe[0]->dtv_property_cache.isdbt_sb_segment_idx ==
1037 ((state->fe[0]->dtv_property_cache.isdbt_sb_segment_count / 2) + 1)))
1038 || (((state->fe[0]->dtv_property_cache.isdbt_sb_segment_count % 2) == 0)
1039 && (state->fe[0]->dtv_property_cache.isdbt_sb_segment_idx == (state->fe[0]->dtv_property_cache.isdbt_sb_segment_count / 2)))
1040 || (((state->fe[0]->dtv_property_cache.isdbt_sb_segment_count % 2) == 0)
1041 && (state->fe[0]->dtv_property_cache.isdbt_sb_segment_idx ==
1042 ((state->fe[0]->dtv_property_cache.isdbt_sb_segment_count / 2) + 1)))
1043 )) {
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001044 new_dds -= ((u32) (850 << 22) / clk) << 4; // new_dds = 850 (freq shift in KHz) / Fclk * pow(2,26)
1045 }
1046 } else {
Olivier Grenie4c70e072011-01-03 15:33:37 -03001047 if ((state->fe[0]->dtv_property_cache.inversion ^ i) == 0)
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001048 new_dds = state->cfg.pll->ifreq - dds_offset;
1049 else
1050 new_dds = state->cfg.pll->ifreq + dds_offset;
1051 }
1052 dib8000_write_word(state, 27, (u16) ((new_dds >> 16) & 0x01ff));
1053 dib8000_write_word(state, 28, (u16) (new_dds & 0xffff));
Olivier Grenie4c70e072011-01-03 15:33:37 -03001054 if (state->fe[0]->dtv_property_cache.isdbt_sb_segment_count % 2) // if odd
1055 sub_channel = ((state->fe[0]->dtv_property_cache.isdbt_sb_subchannel + (3 * seg_offset) + 1) % 41) / 3;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001056 else // if even
Olivier Grenie4c70e072011-01-03 15:33:37 -03001057 sub_channel = ((state->fe[0]->dtv_property_cache.isdbt_sb_subchannel + (3 * seg_offset)) % 41) / 3;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001058 sub_channel -= 6;
1059
Olivier Grenie4c70e072011-01-03 15:33:37 -03001060 if (state->fe[0]->dtv_property_cache.transmission_mode == TRANSMISSION_MODE_2K
1061 || state->fe[0]->dtv_property_cache.transmission_mode == TRANSMISSION_MODE_4K) {
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001062 dib8000_write_word(state, 219, dib8000_read_word(state, 219) | 0x1); //adp_pass =1
1063 dib8000_write_word(state, 190, dib8000_read_word(state, 190) | (0x1 << 14)); //pha3_force_pha_shift = 1
1064 } else {
1065 dib8000_write_word(state, 219, dib8000_read_word(state, 219) & 0xfffe); //adp_pass =0
1066 dib8000_write_word(state, 190, dib8000_read_word(state, 190) & 0xbfff); //pha3_force_pha_shift = 0
1067 }
1068
Olivier Grenie4c70e072011-01-03 15:33:37 -03001069 switch (state->fe[0]->dtv_property_cache.transmission_mode) {
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001070 case TRANSMISSION_MODE_2K:
1071 switch (sub_channel) {
1072 case -6:
1073 init_prbs = 0x0;
1074 break; // 41, 0, 1
1075 case -5:
1076 init_prbs = 0x423;
1077 break; // 02~04
1078 case -4:
1079 init_prbs = 0x9;
1080 break; // 05~07
1081 case -3:
1082 init_prbs = 0x5C7;
1083 break; // 08~10
1084 case -2:
1085 init_prbs = 0x7A6;
1086 break; // 11~13
1087 case -1:
1088 init_prbs = 0x3D8;
1089 break; // 14~16
1090 case 0:
1091 init_prbs = 0x527;
1092 break; // 17~19
1093 case 1:
1094 init_prbs = 0x7FF;
1095 break; // 20~22
1096 case 2:
1097 init_prbs = 0x79B;
1098 break; // 23~25
1099 case 3:
1100 init_prbs = 0x3D6;
1101 break; // 26~28
1102 case 4:
1103 init_prbs = 0x3A2;
1104 break; // 29~31
1105 case 5:
1106 init_prbs = 0x53B;
1107 break; // 32~34
1108 case 6:
1109 init_prbs = 0x2F4;
1110 break; // 35~37
1111 default:
1112 case 7:
1113 init_prbs = 0x213;
1114 break; // 38~40
1115 }
1116 break;
1117
1118 case TRANSMISSION_MODE_4K:
1119 switch (sub_channel) {
1120 case -6:
1121 init_prbs = 0x0;
1122 break; // 41, 0, 1
1123 case -5:
1124 init_prbs = 0x208;
1125 break; // 02~04
1126 case -4:
1127 init_prbs = 0xC3;
1128 break; // 05~07
1129 case -3:
1130 init_prbs = 0x7B9;
1131 break; // 08~10
1132 case -2:
1133 init_prbs = 0x423;
1134 break; // 11~13
1135 case -1:
1136 init_prbs = 0x5C7;
1137 break; // 14~16
1138 case 0:
1139 init_prbs = 0x3D8;
1140 break; // 17~19
1141 case 1:
1142 init_prbs = 0x7FF;
1143 break; // 20~22
1144 case 2:
1145 init_prbs = 0x3D6;
1146 break; // 23~25
1147 case 3:
1148 init_prbs = 0x53B;
1149 break; // 26~28
1150 case 4:
1151 init_prbs = 0x213;
1152 break; // 29~31
1153 case 5:
1154 init_prbs = 0x29;
1155 break; // 32~34
1156 case 6:
1157 init_prbs = 0xD0;
1158 break; // 35~37
1159 default:
1160 case 7:
1161 init_prbs = 0x48E;
1162 break; // 38~40
1163 }
1164 break;
1165
1166 default:
1167 case TRANSMISSION_MODE_8K:
1168 switch (sub_channel) {
1169 case -6:
1170 init_prbs = 0x0;
1171 break; // 41, 0, 1
1172 case -5:
1173 init_prbs = 0x740;
1174 break; // 02~04
1175 case -4:
1176 init_prbs = 0x069;
1177 break; // 05~07
1178 case -3:
1179 init_prbs = 0x7DD;
1180 break; // 08~10
1181 case -2:
1182 init_prbs = 0x208;
1183 break; // 11~13
1184 case -1:
1185 init_prbs = 0x7B9;
1186 break; // 14~16
1187 case 0:
1188 init_prbs = 0x5C7;
1189 break; // 17~19
1190 case 1:
1191 init_prbs = 0x7FF;
1192 break; // 20~22
1193 case 2:
1194 init_prbs = 0x53B;
1195 break; // 23~25
1196 case 3:
1197 init_prbs = 0x29;
1198 break; // 26~28
1199 case 4:
1200 init_prbs = 0x48E;
1201 break; // 29~31
1202 case 5:
1203 init_prbs = 0x4C4;
1204 break; // 32~34
1205 case 6:
1206 init_prbs = 0x367;
1207 break; // 33~37
1208 default:
1209 case 7:
1210 init_prbs = 0x684;
1211 break; // 38~40
1212 }
1213 break;
1214 }
Olivier Grenie4c70e072011-01-03 15:33:37 -03001215 } else { // if not state->fe[0]->dtv_property_cache.isdbt_sb_mode
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001216 dib8000_write_word(state, 27, (u16) ((state->cfg.pll->ifreq >> 16) & 0x01ff));
1217 dib8000_write_word(state, 28, (u16) (state->cfg.pll->ifreq & 0xffff));
1218 dib8000_write_word(state, 26, (u16) ((state->cfg.pll->ifreq >> 25) & 0x0003));
1219 }
1220 /*P_mode == ?? */
1221 dib8000_write_word(state, 10, (seq << 4));
1222 // dib8000_write_word(state, 287, (dib8000_read_word(state, 287) & 0xe000) | 0x1000);
1223
Olivier Grenie4c70e072011-01-03 15:33:37 -03001224 switch (state->fe[0]->dtv_property_cache.guard_interval) {
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001225 case GUARD_INTERVAL_1_32:
1226 guard = 0;
1227 break;
1228 case GUARD_INTERVAL_1_16:
1229 guard = 1;
1230 break;
1231 case GUARD_INTERVAL_1_8:
1232 guard = 2;
1233 break;
1234 case GUARD_INTERVAL_1_4:
1235 default:
1236 guard = 3;
1237 break;
1238 }
1239
1240 dib8000_write_word(state, 1, (init_prbs << 2) | (guard & 0x3)); // ADDR 1
1241
1242 max_constellation = DQPSK;
1243 for (i = 0; i < 3; i++) {
Olivier Grenie4c70e072011-01-03 15:33:37 -03001244 switch (state->fe[0]->dtv_property_cache.layer[i].modulation) {
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001245 case DQPSK:
1246 constellation = 0;
1247 break;
1248 case QPSK:
1249 constellation = 1;
1250 break;
1251 case QAM_16:
1252 constellation = 2;
1253 break;
1254 case QAM_64:
1255 default:
1256 constellation = 3;
1257 break;
1258 }
1259
Olivier Grenie4c70e072011-01-03 15:33:37 -03001260 switch (state->fe[0]->dtv_property_cache.layer[i].fec) {
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001261 case FEC_1_2:
1262 crate = 1;
1263 break;
1264 case FEC_2_3:
1265 crate = 2;
1266 break;
1267 case FEC_3_4:
1268 crate = 3;
1269 break;
1270 case FEC_5_6:
1271 crate = 5;
1272 break;
1273 case FEC_7_8:
1274 default:
1275 crate = 7;
1276 break;
1277 }
1278
Olivier Grenie4c70e072011-01-03 15:33:37 -03001279 if ((state->fe[0]->dtv_property_cache.layer[i].interleaving > 0) &&
1280 ((state->fe[0]->dtv_property_cache.layer[i].interleaving <= 3) ||
1281 (state->fe[0]->dtv_property_cache.layer[i].interleaving == 4 && state->fe[0]->dtv_property_cache.isdbt_sb_mode == 1))
1282 )
1283 timeI = state->fe[0]->dtv_property_cache.layer[i].interleaving;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001284 else
1285 timeI = 0;
Olivier Grenie4c70e072011-01-03 15:33:37 -03001286 dib8000_write_word(state, 2 + i, (constellation << 10) | ((state->fe[0]->dtv_property_cache.layer[i].segment_count & 0xf) << 6) |
1287 (crate << 3) | timeI);
1288 if (state->fe[0]->dtv_property_cache.layer[i].segment_count > 0) {
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001289 switch (max_constellation) {
1290 case DQPSK:
1291 case QPSK:
Olivier Grenie4c70e072011-01-03 15:33:37 -03001292 if (state->fe[0]->dtv_property_cache.layer[i].modulation == QAM_16 ||
1293 state->fe[0]->dtv_property_cache.layer[i].modulation == QAM_64)
1294 max_constellation = state->fe[0]->dtv_property_cache.layer[i].modulation;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001295 break;
1296 case QAM_16:
Olivier Grenie4c70e072011-01-03 15:33:37 -03001297 if (state->fe[0]->dtv_property_cache.layer[i].modulation == QAM_64)
1298 max_constellation = state->fe[0]->dtv_property_cache.layer[i].modulation;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001299 break;
1300 }
1301 }
1302 }
1303
1304 mode = fft_to_mode(state);
1305
1306 //dib8000_write_word(state, 5, 13); /*p_last_seg = 13*/
1307
1308 dib8000_write_word(state, 274, (dib8000_read_word(state, 274) & 0xffcf) |
Olivier Grenie4c70e072011-01-03 15:33:37 -03001309 ((state->fe[0]->dtv_property_cache.isdbt_partial_reception & 1) << 5) | ((state->fe[0]->dtv_property_cache.
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001310 isdbt_sb_mode & 1) << 4));
1311
Olivier Grenie4c70e072011-01-03 15:33:37 -03001312 dprintk("mode = %d ; guard = %d", mode, state->fe[0]->dtv_property_cache.guard_interval);
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001313
1314 /* signal optimization parameter */
1315
Olivier Grenie4c70e072011-01-03 15:33:37 -03001316 if (state->fe[0]->dtv_property_cache.isdbt_partial_reception) {
1317 seg_diff_mask = (state->fe[0]->dtv_property_cache.layer[0].modulation == DQPSK) << permu_seg[0];
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001318 for (i = 1; i < 3; i++)
1319 nbseg_diff +=
Olivier Grenie4c70e072011-01-03 15:33:37 -03001320 (state->fe[0]->dtv_property_cache.layer[i].modulation == DQPSK) * state->fe[0]->dtv_property_cache.layer[i].segment_count;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001321 for (i = 0; i < nbseg_diff; i++)
1322 seg_diff_mask |= 1 << permu_seg[i + 1];
1323 } else {
1324 for (i = 0; i < 3; i++)
1325 nbseg_diff +=
Olivier Grenie4c70e072011-01-03 15:33:37 -03001326 (state->fe[0]->dtv_property_cache.layer[i].modulation == DQPSK) * state->fe[0]->dtv_property_cache.layer[i].segment_count;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001327 for (i = 0; i < nbseg_diff; i++)
1328 seg_diff_mask |= 1 << permu_seg[i];
1329 }
1330 dprintk("nbseg_diff = %X (%d)", seg_diff_mask, seg_diff_mask);
1331
1332 state->differential_constellation = (seg_diff_mask != 0);
Olivier Grenie4c70e072011-01-03 15:33:37 -03001333 dib8000_set_diversity_in(state->fe[0], state->diversity_onoff);
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001334
Olivier Grenie4c70e072011-01-03 15:33:37 -03001335 if (state->fe[0]->dtv_property_cache.isdbt_sb_mode == 1) { // ISDB-Tsb
1336 if (state->fe[0]->dtv_property_cache.isdbt_partial_reception == 1) // 3-segments
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001337 seg_mask13 = 0x00E0;
1338 else // 1-segment
1339 seg_mask13 = 0x0040;
1340 } else
1341 seg_mask13 = 0x1fff;
1342
1343 // WRITE: Mode & Diff mask
1344 dib8000_write_word(state, 0, (mode << 13) | seg_diff_mask);
1345
Olivier Grenie4c70e072011-01-03 15:33:37 -03001346 if ((seg_diff_mask) || (state->fe[0]->dtv_property_cache.isdbt_sb_mode))
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001347 dib8000_write_word(state, 268, (dib8000_read_word(state, 268) & 0xF9FF) | 0x0200);
1348 else
1349 dib8000_write_word(state, 268, (2 << 9) | 39); //init value
1350
1351 // ---- SMALL ----
1352 // P_small_seg_diff
1353 dib8000_write_word(state, 352, seg_diff_mask); // ADDR 352
1354
1355 dib8000_write_word(state, 353, seg_mask13); // ADDR 353
1356
Olivier Grenie4c70e072011-01-03 15:33:37 -03001357/* // P_small_narrow_band=0, P_small_last_seg=13, P_small_offset_num_car=5 */
1358 // dib8000_write_word(state, 351, (state->fe[0]->dtv_property_cache.isdbt_sb_mode << 8) | (13 << 4) | 5 );
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001359
1360 // ---- SMALL ----
Olivier Grenie4c70e072011-01-03 15:33:37 -03001361 if (state->fe[0]->dtv_property_cache.isdbt_sb_mode == 1) {
1362 switch (state->fe[0]->dtv_property_cache.transmission_mode) {
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001363 case TRANSMISSION_MODE_2K:
Olivier Grenie4c70e072011-01-03 15:33:37 -03001364 if (state->fe[0]->dtv_property_cache.isdbt_partial_reception == 0) { // 1-seg
1365 if (state->fe[0]->dtv_property_cache.layer[0].modulation == DQPSK) // DQPSK
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001366 ncoeff = coeff_2k_sb_1seg_dqpsk;
1367 else // QPSK or QAM
1368 ncoeff = coeff_2k_sb_1seg;
1369 } else { // 3-segments
Olivier Grenie4c70e072011-01-03 15:33:37 -03001370 if (state->fe[0]->dtv_property_cache.layer[0].modulation == DQPSK) { // DQPSK on central segment
1371 if (state->fe[0]->dtv_property_cache.layer[1].modulation == DQPSK) // DQPSK on external segments
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001372 ncoeff = coeff_2k_sb_3seg_0dqpsk_1dqpsk;
1373 else // QPSK or QAM on external segments
1374 ncoeff = coeff_2k_sb_3seg_0dqpsk;
1375 } else { // QPSK or QAM on central segment
Olivier Grenie4c70e072011-01-03 15:33:37 -03001376 if (state->fe[0]->dtv_property_cache.layer[1].modulation == DQPSK) // DQPSK on external segments
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001377 ncoeff = coeff_2k_sb_3seg_1dqpsk;
1378 else // QPSK or QAM on external segments
1379 ncoeff = coeff_2k_sb_3seg;
1380 }
1381 }
1382 break;
1383
1384 case TRANSMISSION_MODE_4K:
Olivier Grenie4c70e072011-01-03 15:33:37 -03001385 if (state->fe[0]->dtv_property_cache.isdbt_partial_reception == 0) { // 1-seg
1386 if (state->fe[0]->dtv_property_cache.layer[0].modulation == DQPSK) // DQPSK
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001387 ncoeff = coeff_4k_sb_1seg_dqpsk;
1388 else // QPSK or QAM
1389 ncoeff = coeff_4k_sb_1seg;
1390 } else { // 3-segments
Olivier Grenie4c70e072011-01-03 15:33:37 -03001391 if (state->fe[0]->dtv_property_cache.layer[0].modulation == DQPSK) { // DQPSK on central segment
1392 if (state->fe[0]->dtv_property_cache.layer[1].modulation == DQPSK) { // DQPSK on external segments
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001393 ncoeff = coeff_4k_sb_3seg_0dqpsk_1dqpsk;
1394 } else { // QPSK or QAM on external segments
1395 ncoeff = coeff_4k_sb_3seg_0dqpsk;
1396 }
1397 } else { // QPSK or QAM on central segment
Olivier Grenie4c70e072011-01-03 15:33:37 -03001398 if (state->fe[0]->dtv_property_cache.layer[1].modulation == DQPSK) { // DQPSK on external segments
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001399 ncoeff = coeff_4k_sb_3seg_1dqpsk;
1400 } else // QPSK or QAM on external segments
1401 ncoeff = coeff_4k_sb_3seg;
1402 }
1403 }
1404 break;
1405
1406 case TRANSMISSION_MODE_AUTO:
1407 case TRANSMISSION_MODE_8K:
1408 default:
Olivier Grenie4c70e072011-01-03 15:33:37 -03001409 if (state->fe[0]->dtv_property_cache.isdbt_partial_reception == 0) { // 1-seg
1410 if (state->fe[0]->dtv_property_cache.layer[0].modulation == DQPSK) // DQPSK
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001411 ncoeff = coeff_8k_sb_1seg_dqpsk;
1412 else // QPSK or QAM
1413 ncoeff = coeff_8k_sb_1seg;
1414 } else { // 3-segments
Olivier Grenie4c70e072011-01-03 15:33:37 -03001415 if (state->fe[0]->dtv_property_cache.layer[0].modulation == DQPSK) { // DQPSK on central segment
1416 if (state->fe[0]->dtv_property_cache.layer[1].modulation == DQPSK) { // DQPSK on external segments
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001417 ncoeff = coeff_8k_sb_3seg_0dqpsk_1dqpsk;
1418 } else { // QPSK or QAM on external segments
1419 ncoeff = coeff_8k_sb_3seg_0dqpsk;
1420 }
1421 } else { // QPSK or QAM on central segment
Olivier Grenie4c70e072011-01-03 15:33:37 -03001422 if (state->fe[0]->dtv_property_cache.layer[1].modulation == DQPSK) { // DQPSK on external segments
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001423 ncoeff = coeff_8k_sb_3seg_1dqpsk;
1424 } else // QPSK or QAM on external segments
1425 ncoeff = coeff_8k_sb_3seg;
1426 }
1427 }
1428 break;
1429 }
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001430 for (i = 0; i < 8; i++)
1431 dib8000_write_word(state, 343 + i, ncoeff[i]);
Márton Németh6e8fdbd2009-11-22 18:52:37 -03001432 }
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001433
1434 // P_small_coef_ext_enable=ISDB-Tsb, P_small_narrow_band=ISDB-Tsb, P_small_last_seg=13, P_small_offset_num_car=5
1435 dib8000_write_word(state, 351,
Olivier Grenie4c70e072011-01-03 15:33:37 -03001436 (state->fe[0]->dtv_property_cache.isdbt_sb_mode << 9) | (state->fe[0]->dtv_property_cache.isdbt_sb_mode << 8) | (13 << 4) | 5);
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001437
1438 // ---- COFF ----
1439 // Carloff, the most robust
Olivier Grenie4c70e072011-01-03 15:33:37 -03001440 if (state->fe[0]->dtv_property_cache.isdbt_sb_mode == 1) { // Sound Broadcasting mode - use both TMCC and AC pilots
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001441
1442 // P_coff_cpil_alpha=4, P_coff_inh=0, P_coff_cpil_winlen=64
1443 // 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
1444 dib8000_write_word(state, 187,
Olivier Grenie4c70e072011-01-03 15:33:37 -03001445 (4 << 12) | (0 << 11) | (63 << 5) | (0x3 << 3) | ((~state->fe[0]->dtv_property_cache.isdbt_partial_reception & 1) << 2)
1446 | 0x3);
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001447
Olivier Grenie4c70e072011-01-03 15:33:37 -03001448/* // P_small_coef_ext_enable = 1 */
1449/* dib8000_write_word(state, 351, dib8000_read_word(state, 351) | 0x200); */
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001450
Olivier Grenie4c70e072011-01-03 15:33:37 -03001451 if (state->fe[0]->dtv_property_cache.isdbt_partial_reception == 0) { // Sound Broadcasting mode 1 seg
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001452
1453 // 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)
1454 if (mode == 3)
1455 dib8000_write_word(state, 180, 0x1fcf | ((mode - 1) << 14));
1456 else
1457 dib8000_write_word(state, 180, 0x0fcf | ((mode - 1) << 14));
1458 // P_ctrl_corm_thres4pre_freq_inh=1,P_ctrl_pre_freq_mode_sat=1,
1459 // P_ctrl_pre_freq_inh=0, P_ctrl_pre_freq_step = 5, P_pre_freq_win_len=4
1460 dib8000_write_word(state, 338, (1 << 12) | (1 << 10) | (0 << 9) | (5 << 5) | 4);
1461 // P_ctrl_pre_freq_win_len=16, P_ctrl_pre_freq_thres_lockin=8
1462 dib8000_write_word(state, 340, (16 << 6) | (8 << 0));
1463 // P_ctrl_pre_freq_thres_lockout=6, P_small_use_tmcc/ac/cp=1
1464 dib8000_write_word(state, 341, (6 << 3) | (1 << 2) | (1 << 1) | (1 << 0));
1465
1466 // P_coff_corthres_8k, 4k, 2k and P_coff_cpilthres_8k, 4k, 2k
1467 dib8000_write_word(state, 181, 300);
1468 dib8000_write_word(state, 182, 150);
1469 dib8000_write_word(state, 183, 80);
1470 dib8000_write_word(state, 184, 300);
1471 dib8000_write_word(state, 185, 150);
1472 dib8000_write_word(state, 186, 80);
1473 } else { // Sound Broadcasting mode 3 seg
1474 // P_coff_one_seg_sym= 1, P_coff_one_seg_width= 1, P_coff_winlen=63, P_coff_thres_lock=15
Olivier Grenie4c70e072011-01-03 15:33:37 -03001475 /* if (mode == 3) */
1476 /* dib8000_write_word(state, 180, 0x2fca | ((0) << 14)); */
1477 /* else */
1478 /* dib8000_write_word(state, 180, 0x2fca | ((1) << 14)); */
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001479 dib8000_write_word(state, 180, 0x1fcf | (1 << 14));
1480
1481 // P_ctrl_corm_thres4pre_freq_inh = 1, P_ctrl_pre_freq_mode_sat=1,
1482 // P_ctrl_pre_freq_inh=0, P_ctrl_pre_freq_step = 4, P_pre_freq_win_len=4
1483 dib8000_write_word(state, 338, (1 << 12) | (1 << 10) | (0 << 9) | (4 << 5) | 4);
1484 // P_ctrl_pre_freq_win_len=16, P_ctrl_pre_freq_thres_lockin=8
1485 dib8000_write_word(state, 340, (16 << 6) | (8 << 0));
1486 //P_ctrl_pre_freq_thres_lockout=6, P_small_use_tmcc/ac/cp=1
1487 dib8000_write_word(state, 341, (6 << 3) | (1 << 2) | (1 << 1) | (1 << 0));
1488
1489 // P_coff_corthres_8k, 4k, 2k and P_coff_cpilthres_8k, 4k, 2k
1490 dib8000_write_word(state, 181, 350);
1491 dib8000_write_word(state, 182, 300);
1492 dib8000_write_word(state, 183, 250);
1493 dib8000_write_word(state, 184, 350);
1494 dib8000_write_word(state, 185, 300);
1495 dib8000_write_word(state, 186, 250);
1496 }
1497
1498 } else if (state->isdbt_cfg_loaded == 0) { // if not Sound Broadcasting mode : put default values for 13 segments
1499 dib8000_write_word(state, 180, (16 << 6) | 9);
1500 dib8000_write_word(state, 187, (4 << 12) | (8 << 5) | 0x2);
1501 coff_pow = 0x2800;
1502 for (i = 0; i < 6; i++)
1503 dib8000_write_word(state, 181 + i, coff_pow);
1504
1505 // P_ctrl_corm_thres4pre_freq_inh=1, P_ctrl_pre_freq_mode_sat=1,
1506 // 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
1507 dib8000_write_word(state, 338, (1 << 12) | (1 << 10) | (0 << 9) | (3 << 5) | 1);
1508
1509 // P_ctrl_pre_freq_win_len=8, P_ctrl_pre_freq_thres_lockin=6
1510 dib8000_write_word(state, 340, (8 << 6) | (6 << 0));
1511 // P_ctrl_pre_freq_thres_lockout=4, P_small_use_tmcc/ac/cp=1
1512 dib8000_write_word(state, 341, (4 << 3) | (1 << 2) | (1 << 1) | (1 << 0));
1513 }
1514 // ---- FFT ----
Olivier Grenie4c70e072011-01-03 15:33:37 -03001515 if (state->fe[0]->dtv_property_cache.isdbt_sb_mode == 1 && state->fe[0]->dtv_property_cache.isdbt_partial_reception == 0) // 1-seg
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001516 dib8000_write_word(state, 178, 64); // P_fft_powrange=64
1517 else
1518 dib8000_write_word(state, 178, 32); // P_fft_powrange=32
1519
1520 /* make the cpil_coff_lock more robust but slower p_coff_winlen
1521 * 6bits; p_coff_thres_lock 6bits (for coff lock if needed)
1522 */
1523 /* if ( ( nbseg_diff>0)&&(nbseg_diff<13))
Olivier Grenie4c70e072011-01-03 15:33:37 -03001524 dib8000_write_word(state, 187, (dib8000_read_word(state, 187) & 0xfffb) | (1 << 3)); */
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001525
1526 dib8000_write_word(state, 189, ~seg_mask13 | seg_diff_mask); /* P_lmod4_seg_inh */
1527 dib8000_write_word(state, 192, ~seg_mask13 | seg_diff_mask); /* P_pha3_seg_inh */
1528 dib8000_write_word(state, 225, ~seg_mask13 | seg_diff_mask); /* P_tac_seg_inh */
Olivier Grenie4c70e072011-01-03 15:33:37 -03001529 if ((!state->fe[0]->dtv_property_cache.isdbt_sb_mode) && (state->cfg.pll->ifreq == 0))
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001530 dib8000_write_word(state, 266, ~seg_mask13 | seg_diff_mask | 0x40); /* P_equal_noise_seg_inh */
1531 else
1532 dib8000_write_word(state, 266, ~seg_mask13 | seg_diff_mask); /* P_equal_noise_seg_inh */
1533 dib8000_write_word(state, 287, ~seg_mask13 | 0x1000); /* P_tmcc_seg_inh */
1534 //dib8000_write_word(state, 288, ~seg_mask13 | seg_diff_mask); /* P_tmcc_seg_eq_inh */
1535 if (!autosearching)
1536 dib8000_write_word(state, 288, (~seg_mask13 | seg_diff_mask) & 0x1fff); /* P_tmcc_seg_eq_inh */
1537 else
1538 dib8000_write_word(state, 288, 0x1fff); //disable equalisation of the tmcc when autosearch to be able to find the DQPSK channels.
1539 dprintk("287 = %X (%d)", ~seg_mask13 | 0x1000, ~seg_mask13 | 0x1000);
1540
1541 dib8000_write_word(state, 211, seg_mask13 & (~seg_diff_mask)); /* P_des_seg_enabled */
1542
1543 /* offset loop parameters */
Olivier Grenie4c70e072011-01-03 15:33:37 -03001544 if (state->fe[0]->dtv_property_cache.isdbt_sb_mode == 1) {
1545 if (state->fe[0]->dtv_property_cache.isdbt_partial_reception == 0) // Sound Broadcasting mode 1 seg
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001546 /* P_timf_alpha = (11-P_mode), P_corm_alpha=6, P_corm_thres=0x80 */
1547 dib8000_write_word(state, 32, ((11 - mode) << 12) | (6 << 8) | 0x40);
1548
1549 else // Sound Broadcasting mode 3 seg
1550 /* P_timf_alpha = (10-P_mode), P_corm_alpha=6, P_corm_thres=0x80 */
1551 dib8000_write_word(state, 32, ((10 - mode) << 12) | (6 << 8) | 0x60);
1552 } else
1553 // TODO in 13 seg, timf_alpha can always be the same or not ?
1554 /* P_timf_alpha = (9-P_mode, P_corm_alpha=6, P_corm_thres=0x80 */
1555 dib8000_write_word(state, 32, ((9 - mode) << 12) | (6 << 8) | 0x80);
1556
Olivier Grenie4c70e072011-01-03 15:33:37 -03001557 if (state->fe[0]->dtv_property_cache.isdbt_sb_mode == 1) {
1558 if (state->fe[0]->dtv_property_cache.isdbt_partial_reception == 0) // Sound Broadcasting mode 1 seg
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001559 /* P_ctrl_pha_off_max=3 P_ctrl_sfreq_inh =0 P_ctrl_sfreq_step = (11-P_mode) */
1560 dib8000_write_word(state, 37, (3 << 5) | (0 << 4) | (10 - mode));
1561
1562 else // Sound Broadcasting mode 3 seg
1563 /* P_ctrl_pha_off_max=3 P_ctrl_sfreq_inh =0 P_ctrl_sfreq_step = (10-P_mode) */
1564 dib8000_write_word(state, 37, (3 << 5) | (0 << 4) | (9 - mode));
1565 } else
1566 /* P_ctrl_pha_off_max=3 P_ctrl_sfreq_inh =0 P_ctrl_sfreq_step = 9 */
1567 dib8000_write_word(state, 37, (3 << 5) | (0 << 4) | (8 - mode));
1568
1569 /* P_dvsy_sync_wait - reuse mode */
Olivier Grenie4c70e072011-01-03 15:33:37 -03001570 switch (state->fe[0]->dtv_property_cache.transmission_mode) {
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001571 case TRANSMISSION_MODE_8K:
1572 mode = 256;
1573 break;
1574 case TRANSMISSION_MODE_4K:
1575 mode = 128;
1576 break;
1577 default:
1578 case TRANSMISSION_MODE_2K:
1579 mode = 64;
1580 break;
1581 }
1582 if (state->cfg.diversity_delay == 0)
1583 mode = (mode * (1 << (guard)) * 3) / 2 + 48; // add 50% SFN margin + compensate for one DVSY-fifo
1584 else
1585 mode = (mode * (1 << (guard)) * 3) / 2 + state->cfg.diversity_delay; // add 50% SFN margin + compensate for DVSY-fifo
1586 mode <<= 4;
1587 dib8000_write_word(state, 273, (dib8000_read_word(state, 273) & 0x000f) | mode);
1588
1589 /* channel estimation fine configuration */
1590 switch (max_constellation) {
1591 case QAM_64:
1592 ana_gain = 0x7; // -1 : avoid def_est saturation when ADC target is -16dB
1593 coeff[0] = 0x0148; /* P_adp_regul_cnt 0.04 */
1594 coeff[1] = 0xfff0; /* P_adp_noise_cnt -0.002 */
1595 coeff[2] = 0x00a4; /* P_adp_regul_ext 0.02 */
1596 coeff[3] = 0xfff8; /* P_adp_noise_ext -0.001 */
1597 //if (!state->cfg.hostbus_diversity) //if diversity, we should prehaps use the configuration of the max_constallation -1
1598 break;
1599 case QAM_16:
1600 ana_gain = 0x7; // -1 : avoid def_est saturation when ADC target is -16dB
1601 coeff[0] = 0x023d; /* P_adp_regul_cnt 0.07 */
1602 coeff[1] = 0xffdf; /* P_adp_noise_cnt -0.004 */
1603 coeff[2] = 0x00a4; /* P_adp_regul_ext 0.02 */
1604 coeff[3] = 0xfff0; /* P_adp_noise_ext -0.002 */
1605 //if (!((state->cfg.hostbus_diversity) && (max_constellation == QAM_16)))
1606 break;
1607 default:
1608 ana_gain = 0; // 0 : goes along with ADC target at -22dB to keep good mobile performance and lock at sensitivity level
1609 coeff[0] = 0x099a; /* P_adp_regul_cnt 0.3 */
1610 coeff[1] = 0xffae; /* P_adp_noise_cnt -0.01 */
1611 coeff[2] = 0x0333; /* P_adp_regul_ext 0.1 */
1612 coeff[3] = 0xfff8; /* P_adp_noise_ext -0.002 */
1613 break;
1614 }
1615 for (mode = 0; mode < 4; mode++)
1616 dib8000_write_word(state, 215 + mode, coeff[mode]);
1617
1618 // update ana_gain depending on max constellation
1619 dib8000_write_word(state, 116, ana_gain);
1620 // update ADC target depending on ana_gain
1621 if (ana_gain) { // set -16dB ADC target for ana_gain=-1
1622 for (i = 0; i < 10; i++)
1623 dib8000_write_word(state, 80 + i, adc_target_16dB[i]);
1624 } else { // set -22dB ADC target for ana_gain=0
1625 for (i = 0; i < 10; i++)
1626 dib8000_write_word(state, 80 + i, adc_target_16dB[i] - 355);
1627 }
1628
1629 // ---- ANA_FE ----
Olivier Grenie4c70e072011-01-03 15:33:37 -03001630 if (state->fe[0]->dtv_property_cache.isdbt_sb_mode) {
1631 if (state->fe[0]->dtv_property_cache.isdbt_partial_reception == 1) // 3-segments
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001632 ana_fe = ana_fe_coeff_3seg;
1633 else // 1-segment
1634 ana_fe = ana_fe_coeff_1seg;
1635 } else
1636 ana_fe = ana_fe_coeff_13seg;
1637
Olivier Grenie4c70e072011-01-03 15:33:37 -03001638 if (state->fe[0]->dtv_property_cache.isdbt_sb_mode == 1 || state->isdbt_cfg_loaded == 0)
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001639 for (mode = 0; mode < 24; mode++)
1640 dib8000_write_word(state, 117 + mode, ana_fe[mode]);
1641
1642 // ---- CHAN_BLK ----
1643 for (i = 0; i < 13; i++) {
1644 if ((((~seg_diff_mask) >> i) & 1) == 1) {
1645 P_cfr_left_edge += (1 << i) * ((i == 0) || ((((seg_mask13 & (~seg_diff_mask)) >> (i - 1)) & 1) == 0));
1646 P_cfr_right_edge += (1 << i) * ((i == 12) || ((((seg_mask13 & (~seg_diff_mask)) >> (i + 1)) & 1) == 0));
1647 }
1648 }
1649 dib8000_write_word(state, 222, P_cfr_left_edge); // P_cfr_left_edge
1650 dib8000_write_word(state, 223, P_cfr_right_edge); // P_cfr_right_edge
1651 // "P_cspu_left_edge" not used => do not care
1652 // "P_cspu_right_edge" not used => do not care
1653
Olivier Grenie4c70e072011-01-03 15:33:37 -03001654 if (state->fe[0]->dtv_property_cache.isdbt_sb_mode == 1) { // ISDB-Tsb
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001655 dib8000_write_word(state, 228, 1); // P_2d_mode_byp=1
1656 dib8000_write_word(state, 205, dib8000_read_word(state, 205) & 0xfff0); // P_cspu_win_cut = 0
Olivier Grenie4c70e072011-01-03 15:33:37 -03001657 if (state->fe[0]->dtv_property_cache.isdbt_partial_reception == 0 // 1-segment
1658 && state->fe[0]->dtv_property_cache.transmission_mode == TRANSMISSION_MODE_2K) {
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001659 //dib8000_write_word(state, 219, dib8000_read_word(state, 219) & 0xfffe); // P_adp_pass = 0
1660 dib8000_write_word(state, 265, 15); // P_equal_noise_sel = 15
1661 }
1662 } else if (state->isdbt_cfg_loaded == 0) {
1663 dib8000_write_word(state, 228, 0); // default value
1664 dib8000_write_word(state, 265, 31); // default value
1665 dib8000_write_word(state, 205, 0x200f); // init value
1666 }
1667 // ---- TMCC ----
1668 for (i = 0; i < 3; i++)
1669 tmcc_pow +=
Olivier Grenie4c70e072011-01-03 15:33:37 -03001670 (((state->fe[0]->dtv_property_cache.layer[i].modulation == DQPSK) * 4 + 1) * state->fe[0]->dtv_property_cache.layer[i].segment_count);
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001671 // Quantif of "P_tmcc_dec_thres_?k" is (0, 5+mode, 9);
1672 // Threshold is set at 1/4 of max power.
1673 tmcc_pow *= (1 << (9 - 2));
1674
1675 dib8000_write_word(state, 290, tmcc_pow); // P_tmcc_dec_thres_2k
1676 dib8000_write_word(state, 291, tmcc_pow); // P_tmcc_dec_thres_4k
1677 dib8000_write_word(state, 292, tmcc_pow); // P_tmcc_dec_thres_8k
1678 //dib8000_write_word(state, 287, (1 << 13) | 0x1000 );
1679 // ---- PHA3 ----
1680
1681 if (state->isdbt_cfg_loaded == 0)
1682 dib8000_write_word(state, 250, 3285); /*p_2d_hspeed_thr0 */
1683
Olivier Grenie4c70e072011-01-03 15:33:37 -03001684 if (state->fe[0]->dtv_property_cache.isdbt_sb_mode == 1)
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001685 state->isdbt_cfg_loaded = 0;
1686 else
1687 state->isdbt_cfg_loaded = 1;
1688
1689}
1690
1691static int dib8000_autosearch_start(struct dvb_frontend *fe)
1692{
1693 u8 factor;
1694 u32 value;
1695 struct dib8000_state *state = fe->demodulator_priv;
1696
1697 int slist = 0;
1698
Olivier Grenie4c70e072011-01-03 15:33:37 -03001699 state->fe[0]->dtv_property_cache.inversion = 0;
1700 if (!state->fe[0]->dtv_property_cache.isdbt_sb_mode)
1701 state->fe[0]->dtv_property_cache.layer[0].segment_count = 13;
1702 state->fe[0]->dtv_property_cache.layer[0].modulation = QAM_64;
1703 state->fe[0]->dtv_property_cache.layer[0].fec = FEC_2_3;
1704 state->fe[0]->dtv_property_cache.layer[0].interleaving = 0;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001705
1706 //choose the right list, in sb, always do everything
Olivier Grenie4c70e072011-01-03 15:33:37 -03001707 if (state->fe[0]->dtv_property_cache.isdbt_sb_mode) {
1708 state->fe[0]->dtv_property_cache.transmission_mode = TRANSMISSION_MODE_8K;
1709 state->fe[0]->dtv_property_cache.guard_interval = GUARD_INTERVAL_1_8;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001710 slist = 7;
1711 dib8000_write_word(state, 0, (dib8000_read_word(state, 0) & 0x9fff) | (1 << 13));
1712 } else {
Olivier Grenie4c70e072011-01-03 15:33:37 -03001713 if (state->fe[0]->dtv_property_cache.guard_interval == GUARD_INTERVAL_AUTO) {
1714 if (state->fe[0]->dtv_property_cache.transmission_mode == TRANSMISSION_MODE_AUTO) {
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001715 slist = 7;
1716 dib8000_write_word(state, 0, (dib8000_read_word(state, 0) & 0x9fff) | (1 << 13)); // P_mode = 1 to have autosearch start ok with mode2
Patrick Boettcher78f3bc62009-08-17 12:53:51 -03001717 } else
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001718 slist = 3;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001719 } else {
Olivier Grenie4c70e072011-01-03 15:33:37 -03001720 if (state->fe[0]->dtv_property_cache.transmission_mode == TRANSMISSION_MODE_AUTO) {
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001721 slist = 2;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001722 dib8000_write_word(state, 0, (dib8000_read_word(state, 0) & 0x9fff) | (1 << 13)); // P_mode = 1
Patrick Boettcher78f3bc62009-08-17 12:53:51 -03001723 } else
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001724 slist = 0;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001725 }
1726
Olivier Grenie4c70e072011-01-03 15:33:37 -03001727 if (state->fe[0]->dtv_property_cache.transmission_mode == TRANSMISSION_MODE_AUTO)
1728 state->fe[0]->dtv_property_cache.transmission_mode = TRANSMISSION_MODE_8K;
1729 if (state->fe[0]->dtv_property_cache.guard_interval == GUARD_INTERVAL_AUTO)
1730 state->fe[0]->dtv_property_cache.guard_interval = GUARD_INTERVAL_1_8;
Patrick Boettcher78f3bc62009-08-17 12:53:51 -03001731
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001732 dprintk("using list for autosearch : %d", slist);
1733 dib8000_set_channel(state, (unsigned char)slist, 1);
1734 //dib8000_write_word(state, 0, (dib8000_read_word(state, 0) & 0x9fff) | (1 << 13)); // P_mode = 1
1735
1736 factor = 1;
1737
1738 //set lock_mask values
1739 dib8000_write_word(state, 6, 0x4);
1740 dib8000_write_word(state, 7, 0x8);
1741 dib8000_write_word(state, 8, 0x1000);
1742
1743 //set lock_mask wait time values
1744 value = 50 * state->cfg.pll->internal * factor;
1745 dib8000_write_word(state, 11, (u16) ((value >> 16) & 0xffff)); // lock0 wait time
1746 dib8000_write_word(state, 12, (u16) (value & 0xffff)); // lock0 wait time
1747 value = 100 * state->cfg.pll->internal * factor;
1748 dib8000_write_word(state, 13, (u16) ((value >> 16) & 0xffff)); // lock1 wait time
1749 dib8000_write_word(state, 14, (u16) (value & 0xffff)); // lock1 wait time
1750 value = 1000 * state->cfg.pll->internal * factor;
1751 dib8000_write_word(state, 15, (u16) ((value >> 16) & 0xffff)); // lock2 wait time
1752 dib8000_write_word(state, 16, (u16) (value & 0xffff)); // lock2 wait time
1753
1754 value = dib8000_read_word(state, 0);
1755 dib8000_write_word(state, 0, (u16) ((1 << 15) | value));
1756 dib8000_read_word(state, 1284); // reset the INT. n_irq_pending
1757 dib8000_write_word(state, 0, (u16) value);
Patrick Boettcher78f3bc62009-08-17 12:53:51 -03001758
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001759 }
1760
1761 return 0;
1762}
1763
1764static int dib8000_autosearch_irq(struct dvb_frontend *fe)
1765{
1766 struct dib8000_state *state = fe->demodulator_priv;
1767 u16 irq_pending = dib8000_read_word(state, 1284);
1768
1769 if (irq_pending & 0x1) { // failed
1770 dprintk("dib8000_autosearch_irq failed");
1771 return 1;
1772 }
1773
1774 if (irq_pending & 0x2) { // succeeded
1775 dprintk("dib8000_autosearch_irq succeeded");
1776 return 2;
1777 }
1778
1779 return 0; // still pending
1780}
1781
1782static int dib8000_tune(struct dvb_frontend *fe)
1783{
1784 struct dib8000_state *state = fe->demodulator_priv;
1785 int ret = 0;
1786 u16 value, mode = fft_to_mode(state);
1787
1788 // we are already tuned - just resuming from suspend
1789 if (state == NULL)
1790 return -EINVAL;
1791
Olivier Grenie4c70e072011-01-03 15:33:37 -03001792 dib8000_set_bandwidth(fe, state->fe[0]->dtv_property_cache.bandwidth_hz / 1000);
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001793 dib8000_set_channel(state, 0, 0);
1794
1795 // restart demod
1796 ret |= dib8000_write_word(state, 770, 0x4000);
1797 ret |= dib8000_write_word(state, 770, 0x0000);
1798 msleep(45);
1799
1800 /* P_ctrl_inh_cor=0, P_ctrl_alpha_cor=4, P_ctrl_inh_isi=0, P_ctrl_alpha_isi=3 */
1801 /* ret |= dib8000_write_word(state, 29, (0 << 9) | (4 << 5) | (0 << 4) | (3 << 0) ); workaround inh_isi stays at 1 */
1802
1803 // never achieved a lock before - wait for timfreq to update
1804 if (state->timf == 0) {
Olivier Grenie4c70e072011-01-03 15:33:37 -03001805 if (state->fe[0]->dtv_property_cache.isdbt_sb_mode == 1) {
1806 if (state->fe[0]->dtv_property_cache.isdbt_partial_reception == 0) // Sound Broadcasting mode 1 seg
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001807 msleep(300);
1808 else // Sound Broadcasting mode 3 seg
1809 msleep(500);
1810 } else // 13 seg
1811 msleep(200);
1812 }
Olivier Grenie4c70e072011-01-03 15:33:37 -03001813 if (state->fe[0]->dtv_property_cache.isdbt_sb_mode == 1) {
1814 if (state->fe[0]->dtv_property_cache.isdbt_partial_reception == 0) { // Sound Broadcasting mode 1 seg
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001815
1816 /* P_timf_alpha = (13-P_mode) , P_corm_alpha=6, P_corm_thres=0x40 alpha to check on board */
1817 dib8000_write_word(state, 32, ((13 - mode) << 12) | (6 << 8) | 0x40);
1818 //dib8000_write_word(state, 32, (8 << 12) | (6 << 8) | 0x80);
1819
1820 /* P_ctrl_sfreq_step= (12-P_mode) P_ctrl_sfreq_inh =0 P_ctrl_pha_off_max */
1821 ret |= dib8000_write_word(state, 37, (12 - mode) | ((5 + mode) << 5));
1822
1823 } else { // Sound Broadcasting mode 3 seg
1824
1825 /* P_timf_alpha = (12-P_mode) , P_corm_alpha=6, P_corm_thres=0x60 alpha to check on board */
1826 dib8000_write_word(state, 32, ((12 - mode) << 12) | (6 << 8) | 0x60);
1827
1828 ret |= dib8000_write_word(state, 37, (11 - mode) | ((5 + mode) << 5));
1829 }
1830
1831 } else { // 13 seg
1832 /* P_timf_alpha = 8 , P_corm_alpha=6, P_corm_thres=0x80 alpha to check on board */
1833 dib8000_write_word(state, 32, ((11 - mode) << 12) | (6 << 8) | 0x80);
1834
1835 ret |= dib8000_write_word(state, 37, (10 - mode) | ((5 + mode) << 5));
1836
1837 }
1838
1839 // we achieved a coff_cpil_lock - it's time to update the timf
1840 if ((dib8000_read_word(state, 568) >> 11) & 0x1)
1841 dib8000_update_timf(state);
1842
1843 //now that tune is finished, lock0 should lock on fec_mpeg to output this lock on MP_LOCK. It's changed in autosearch start
1844 dib8000_write_word(state, 6, 0x200);
1845
1846 if (state->revision == 0x8002) {
1847 value = dib8000_read_word(state, 903);
1848 dib8000_write_word(state, 903, value & ~(1 << 3));
1849 msleep(1);
1850 dib8000_write_word(state, 903, value | (1 << 3));
1851 }
1852
1853 return ret;
1854}
1855
1856static int dib8000_wakeup(struct dvb_frontend *fe)
1857{
1858 struct dib8000_state *state = fe->demodulator_priv;
Olivier Grenie4c70e072011-01-03 15:33:37 -03001859 u8 index_frontend;
1860 int ret;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001861
1862 dib8000_set_power_mode(state, DIB8000M_POWER_ALL);
1863 dib8000_set_adc_state(state, DIBX000_ADC_ON);
1864 if (dib8000_set_adc_state(state, DIBX000_SLOW_ADC_ON) != 0)
1865 dprintk("could not start Slow ADC");
1866
Olivier Grenie4c70e072011-01-03 15:33:37 -03001867 for (index_frontend=1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
1868 ret = state->fe[index_frontend]->ops.init(state->fe[index_frontend]);
1869 if (ret<0)
1870 return ret;
1871 }
1872
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001873 return 0;
1874}
1875
1876static int dib8000_sleep(struct dvb_frontend *fe)
1877{
Olivier Grenie4c70e072011-01-03 15:33:37 -03001878 struct dib8000_state *state = fe->demodulator_priv;
1879 u8 index_frontend;
1880 int ret;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001881
Olivier Grenie4c70e072011-01-03 15:33:37 -03001882 for (index_frontend=1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
1883 ret = state->fe[index_frontend]->ops.sleep(state->fe[index_frontend]);
1884 if (ret < 0)
1885 return ret;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001886 }
Olivier Grenie4c70e072011-01-03 15:33:37 -03001887
1888 dib8000_set_output_mode(fe, OUTMODE_HIGH_Z);
1889 dib8000_set_power_mode(state, DIB8000M_POWER_INTERFACE_ONLY);
1890 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 -03001891}
1892
Olivier Grenie9c783032009-12-07 07:49:40 -03001893enum frontend_tune_state dib8000_get_tune_state(struct dvb_frontend *fe)
Olivier Grenie03245a52009-12-04 13:27:57 -03001894{
1895 struct dib8000_state *state = fe->demodulator_priv;
1896 return state->tune_state;
1897}
1898EXPORT_SYMBOL(dib8000_get_tune_state);
1899
Olivier Grenie9c783032009-12-07 07:49:40 -03001900int dib8000_set_tune_state(struct dvb_frontend *fe, enum frontend_tune_state tune_state)
Olivier Grenie03245a52009-12-04 13:27:57 -03001901{
1902 struct dib8000_state *state = fe->demodulator_priv;
1903 state->tune_state = tune_state;
1904 return 0;
1905}
1906EXPORT_SYMBOL(dib8000_set_tune_state);
1907
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001908static int dib8000_get_frontend(struct dvb_frontend *fe, struct dvb_frontend_parameters *fep)
1909{
1910 struct dib8000_state *state = fe->demodulator_priv;
1911 u16 i, val = 0;
Olivier Grenie4c70e072011-01-03 15:33:37 -03001912 fe_status_t stat;
1913 u8 index_frontend, sub_index_frontend;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001914
1915 fe->dtv_property_cache.bandwidth_hz = 6000000;
1916
Olivier Grenie4c70e072011-01-03 15:33:37 -03001917 for (index_frontend=1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
1918 state->fe[index_frontend]->ops.read_status(state->fe[index_frontend], &stat);
1919 if (stat&FE_HAS_SYNC) {
1920 dprintk("TMCC lock on the slave%i", index_frontend);
1921 /* synchronize the cache with the other frontends */
1922 state->fe[index_frontend]->ops.get_frontend(state->fe[index_frontend], fep);
1923 for (sub_index_frontend=0; (sub_index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[sub_index_frontend] != NULL); sub_index_frontend++) {
1924 if (sub_index_frontend != index_frontend) {
1925 state->fe[sub_index_frontend]->dtv_property_cache.isdbt_sb_mode = state->fe[index_frontend]->dtv_property_cache.isdbt_sb_mode;
1926 state->fe[sub_index_frontend]->dtv_property_cache.inversion = state->fe[index_frontend]->dtv_property_cache.inversion;
1927 state->fe[sub_index_frontend]->dtv_property_cache.transmission_mode = state->fe[index_frontend]->dtv_property_cache.transmission_mode;
1928 state->fe[sub_index_frontend]->dtv_property_cache.guard_interval = state->fe[index_frontend]->dtv_property_cache.guard_interval;
1929 state->fe[sub_index_frontend]->dtv_property_cache.isdbt_partial_reception = state->fe[index_frontend]->dtv_property_cache.isdbt_partial_reception;
1930 for (i = 0; i < 3; i++) {
1931 state->fe[sub_index_frontend]->dtv_property_cache.layer[i].segment_count = state->fe[index_frontend]->dtv_property_cache.layer[i].segment_count;
1932 state->fe[sub_index_frontend]->dtv_property_cache.layer[i].interleaving = state->fe[index_frontend]->dtv_property_cache.layer[i].interleaving;
1933 state->fe[sub_index_frontend]->dtv_property_cache.layer[i].fec = state->fe[index_frontend]->dtv_property_cache.layer[i].fec;
1934 state->fe[sub_index_frontend]->dtv_property_cache.layer[i].modulation = state->fe[index_frontend]->dtv_property_cache.layer[i].modulation;
1935 }
1936 }
1937 }
1938 return 0;
1939 }
1940 }
1941
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001942 fe->dtv_property_cache.isdbt_sb_mode = dib8000_read_word(state, 508) & 0x1;
1943
1944 val = dib8000_read_word(state, 570);
1945 fe->dtv_property_cache.inversion = (val & 0x40) >> 6;
1946 switch ((val & 0x30) >> 4) {
1947 case 1:
1948 fe->dtv_property_cache.transmission_mode = TRANSMISSION_MODE_2K;
1949 break;
1950 case 3:
1951 default:
1952 fe->dtv_property_cache.transmission_mode = TRANSMISSION_MODE_8K;
1953 break;
1954 }
1955
1956 switch (val & 0x3) {
1957 case 0:
1958 fe->dtv_property_cache.guard_interval = GUARD_INTERVAL_1_32;
1959 dprintk("dib8000_get_frontend GI = 1/32 ");
1960 break;
1961 case 1:
1962 fe->dtv_property_cache.guard_interval = GUARD_INTERVAL_1_16;
1963 dprintk("dib8000_get_frontend GI = 1/16 ");
1964 break;
1965 case 2:
1966 dprintk("dib8000_get_frontend GI = 1/8 ");
1967 fe->dtv_property_cache.guard_interval = GUARD_INTERVAL_1_8;
1968 break;
1969 case 3:
1970 dprintk("dib8000_get_frontend GI = 1/4 ");
1971 fe->dtv_property_cache.guard_interval = GUARD_INTERVAL_1_4;
1972 break;
1973 }
1974
1975 val = dib8000_read_word(state, 505);
1976 fe->dtv_property_cache.isdbt_partial_reception = val & 1;
1977 dprintk("dib8000_get_frontend : partial_reception = %d ", fe->dtv_property_cache.isdbt_partial_reception);
1978
1979 for (i = 0; i < 3; i++) {
1980 val = dib8000_read_word(state, 493 + i);
1981 fe->dtv_property_cache.layer[i].segment_count = val & 0x0F;
1982 dprintk("dib8000_get_frontend : Layer %d segments = %d ", i, fe->dtv_property_cache.layer[i].segment_count);
1983
1984 val = dib8000_read_word(state, 499 + i);
1985 fe->dtv_property_cache.layer[i].interleaving = val & 0x3;
1986 dprintk("dib8000_get_frontend : Layer %d time_intlv = %d ", i, fe->dtv_property_cache.layer[i].interleaving);
1987
1988 val = dib8000_read_word(state, 481 + i);
1989 switch (val & 0x7) {
1990 case 1:
1991 fe->dtv_property_cache.layer[i].fec = FEC_1_2;
1992 dprintk("dib8000_get_frontend : Layer %d Code Rate = 1/2 ", i);
1993 break;
1994 case 2:
1995 fe->dtv_property_cache.layer[i].fec = FEC_2_3;
1996 dprintk("dib8000_get_frontend : Layer %d Code Rate = 2/3 ", i);
1997 break;
1998 case 3:
1999 fe->dtv_property_cache.layer[i].fec = FEC_3_4;
2000 dprintk("dib8000_get_frontend : Layer %d Code Rate = 3/4 ", i);
2001 break;
2002 case 5:
2003 fe->dtv_property_cache.layer[i].fec = FEC_5_6;
2004 dprintk("dib8000_get_frontend : Layer %d Code Rate = 5/6 ", i);
2005 break;
2006 default:
2007 fe->dtv_property_cache.layer[i].fec = FEC_7_8;
2008 dprintk("dib8000_get_frontend : Layer %d Code Rate = 7/8 ", i);
2009 break;
2010 }
2011
2012 val = dib8000_read_word(state, 487 + i);
2013 switch (val & 0x3) {
2014 case 0:
2015 dprintk("dib8000_get_frontend : Layer %d DQPSK ", i);
2016 fe->dtv_property_cache.layer[i].modulation = DQPSK;
2017 break;
2018 case 1:
2019 fe->dtv_property_cache.layer[i].modulation = QPSK;
2020 dprintk("dib8000_get_frontend : Layer %d QPSK ", i);
2021 break;
2022 case 2:
2023 fe->dtv_property_cache.layer[i].modulation = QAM_16;
2024 dprintk("dib8000_get_frontend : Layer %d QAM16 ", i);
2025 break;
2026 case 3:
2027 default:
2028 dprintk("dib8000_get_frontend : Layer %d QAM64 ", i);
2029 fe->dtv_property_cache.layer[i].modulation = QAM_64;
2030 break;
2031 }
2032 }
Olivier Grenie4c70e072011-01-03 15:33:37 -03002033
2034 /* synchronize the cache with the other frontends */
2035 for (index_frontend=1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
2036 state->fe[index_frontend]->dtv_property_cache.isdbt_sb_mode = fe->dtv_property_cache.isdbt_sb_mode;
2037 state->fe[index_frontend]->dtv_property_cache.inversion = fe->dtv_property_cache.inversion;
2038 state->fe[index_frontend]->dtv_property_cache.transmission_mode = fe->dtv_property_cache.transmission_mode;
2039 state->fe[index_frontend]->dtv_property_cache.guard_interval = fe->dtv_property_cache.guard_interval;
2040 state->fe[index_frontend]->dtv_property_cache.isdbt_partial_reception = fe->dtv_property_cache.isdbt_partial_reception;
2041 for (i = 0; i < 3; i++) {
2042 state->fe[index_frontend]->dtv_property_cache.layer[i].segment_count = fe->dtv_property_cache.layer[i].segment_count;
2043 state->fe[index_frontend]->dtv_property_cache.layer[i].interleaving = fe->dtv_property_cache.layer[i].interleaving;
2044 state->fe[index_frontend]->dtv_property_cache.layer[i].fec = fe->dtv_property_cache.layer[i].fec;
2045 state->fe[index_frontend]->dtv_property_cache.layer[i].modulation = fe->dtv_property_cache.layer[i].modulation;
2046 }
2047 }
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002048 return 0;
2049}
2050
2051static int dib8000_set_frontend(struct dvb_frontend *fe, struct dvb_frontend_parameters *fep)
2052{
2053 struct dib8000_state *state = fe->demodulator_priv;
Olivier Grenie4c70e072011-01-03 15:33:37 -03002054 u8 nbr_pending, exit_condition, index_frontend;
2055 s8 index_frontend_success = -1;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002056 int time, ret;
Olivier Grenie4c70e072011-01-03 15:33:37 -03002057 int time_slave = FE_CALLBACK_TIME_NEVER;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002058
Olivier Grenie4c70e072011-01-03 15:33:37 -03002059 if (state->fe[0]->dtv_property_cache.frequency == 0) {
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002060 dprintk("dib8000: must at least specify frequency ");
2061 return 0;
2062 }
2063
Olivier Grenie4c70e072011-01-03 15:33:37 -03002064 if (state->fe[0]->dtv_property_cache.bandwidth_hz == 0) {
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002065 dprintk("dib8000: no bandwidth specified, set to default ");
Olivier Grenie4c70e072011-01-03 15:33:37 -03002066 state->fe[0]->dtv_property_cache.bandwidth_hz = 6000000;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002067 }
2068
Olivier Grenie4c70e072011-01-03 15:33:37 -03002069 for (index_frontend=0; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
2070 /* synchronization of the cache */
2071 state->fe[index_frontend]->dtv_property_cache.delivery_system = SYS_ISDBT;
2072 memcpy(&state->fe[index_frontend]->dtv_property_cache, &fe->dtv_property_cache, sizeof(struct dtv_frontend_properties));
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002073
Olivier Grenie4c70e072011-01-03 15:33:37 -03002074 dib8000_set_output_mode(state->fe[index_frontend], OUTMODE_HIGH_Z);
2075 if (state->fe[index_frontend]->ops.tuner_ops.set_params)
2076 state->fe[index_frontend]->ops.tuner_ops.set_params(state->fe[index_frontend], fep);
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002077
Olivier Grenie4c70e072011-01-03 15:33:37 -03002078 dib8000_set_tune_state(state->fe[index_frontend], CT_AGC_START);
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002079 }
2080
Olivier Grenie4c70e072011-01-03 15:33:37 -03002081 /* start up the AGC */
2082 do {
2083 time = dib8000_agc_startup(state->fe[0]);
2084 for (index_frontend=1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
2085 time_slave = dib8000_agc_startup(state->fe[index_frontend]);
2086 if (time == FE_CALLBACK_TIME_NEVER)
2087 time = time_slave;
2088 else if ((time_slave != FE_CALLBACK_TIME_NEVER) && (time_slave > time))
2089 time = time_slave;
2090 }
2091 if (time != FE_CALLBACK_TIME_NEVER)
2092 msleep(time / 10);
2093 else
2094 break;
2095 exit_condition = 1;
2096 for (index_frontend=0; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
2097 if (dib8000_get_tune_state(state->fe[index_frontend]) != CT_AGC_STOP) {
2098 exit_condition = 0;
2099 break;
2100 }
2101 }
2102 } while (exit_condition == 0);
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002103
Olivier Grenie4c70e072011-01-03 15:33:37 -03002104 for (index_frontend=0; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++)
2105 dib8000_set_tune_state(state->fe[index_frontend], CT_DEMOD_START);
2106
2107 if ((state->fe[0]->dtv_property_cache.delivery_system != SYS_ISDBT) ||
2108 (state->fe[0]->dtv_property_cache.inversion == INVERSION_AUTO) ||
2109 (state->fe[0]->dtv_property_cache.transmission_mode == TRANSMISSION_MODE_AUTO) ||
2110 (state->fe[0]->dtv_property_cache.guard_interval == GUARD_INTERVAL_AUTO) ||
2111 (((state->fe[0]->dtv_property_cache.isdbt_layer_enabled & (1 << 0)) != 0) &&
2112 (state->fe[0]->dtv_property_cache.layer[0].segment_count != 0xff) &&
2113 (state->fe[0]->dtv_property_cache.layer[0].segment_count != 0) &&
2114 ((state->fe[0]->dtv_property_cache.layer[0].modulation == QAM_AUTO) ||
2115 (state->fe[0]->dtv_property_cache.layer[0].fec == FEC_AUTO))) ||
2116 (((state->fe[0]->dtv_property_cache.isdbt_layer_enabled & (1 << 1)) != 0) &&
2117 (state->fe[0]->dtv_property_cache.layer[1].segment_count != 0xff) &&
2118 (state->fe[0]->dtv_property_cache.layer[1].segment_count != 0) &&
2119 ((state->fe[0]->dtv_property_cache.layer[1].modulation == QAM_AUTO) ||
2120 (state->fe[0]->dtv_property_cache.layer[1].fec == FEC_AUTO))) ||
2121 (((state->fe[0]->dtv_property_cache.isdbt_layer_enabled & (1 << 2)) != 0) &&
2122 (state->fe[0]->dtv_property_cache.layer[2].segment_count != 0xff) &&
2123 (state->fe[0]->dtv_property_cache.layer[2].segment_count != 0) &&
2124 ((state->fe[0]->dtv_property_cache.layer[2].modulation == QAM_AUTO) ||
2125 (state->fe[0]->dtv_property_cache.layer[2].fec == FEC_AUTO))) ||
2126 (((state->fe[0]->dtv_property_cache.layer[0].segment_count == 0) ||
2127 ((state->fe[0]->dtv_property_cache.isdbt_layer_enabled & (1 << 0)) == 0)) &&
2128 ((state->fe[0]->dtv_property_cache.layer[1].segment_count == 0) ||
2129 ((state->fe[0]->dtv_property_cache.isdbt_layer_enabled & (2 << 0)) == 0)) &&
2130 ((state->fe[0]->dtv_property_cache.layer[2].segment_count == 0) || ((state->fe[0]->dtv_property_cache.isdbt_layer_enabled & (3 << 0)) == 0)))) {
2131 int i = 80000;
2132 u8 found = 0;
2133 u8 tune_failed = 0;
2134
2135 for (index_frontend=0; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
2136 dib8000_set_bandwidth(state->fe[index_frontend], fe->dtv_property_cache.bandwidth_hz / 1000);
2137 dib8000_autosearch_start(state->fe[index_frontend]);
2138 }
2139
2140 do {
2141 msleep(10);
2142 nbr_pending = 0;
2143 exit_condition = 0; /* 0: tune pending; 1: tune failed; 2:tune success */
2144 for (index_frontend=0; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
2145 if (((tune_failed >> index_frontend) & 0x1) == 0) {
2146 found = dib8000_autosearch_irq(state->fe[index_frontend]);
2147 switch (found) {
2148 case 0: /* tune pending */
2149 nbr_pending++;
2150 break;
2151 case 2:
2152 dprintk("autosearch succeed on the frontend%i", index_frontend);
2153 exit_condition = 2;
2154 index_frontend_success = index_frontend;
2155 break;
2156 default:
2157 dprintk("unhandled autosearch result");
2158 case 1:
2159 tune_failed |= (1 << index_frontend);
2160 dprintk("autosearch failed for the frontend%i", index_frontend);
2161 break;
2162 }
2163 }
2164 }
2165
2166 /* if all tune are done and no success, exit: tune failed */
2167 if ((nbr_pending == 0) && (exit_condition == 0))
2168 exit_condition = 1;
2169 } while ((exit_condition == 0) && i--);
2170
2171 if (exit_condition == 1) { /* tune failed */
2172 dprintk("tune failed");
2173 return 0;
2174 }
2175
2176 dprintk("tune success on frontend%i", index_frontend_success);
2177
2178 dib8000_get_frontend(fe, fep);
2179 }
2180
2181 for (index_frontend=0, ret=0; (ret >= 0) && (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
2182 ret = dib8000_tune(state->fe[index_frontend]);
2183 }
2184
2185 /* set output mode and diversity input */
2186 dib8000_set_output_mode(state->fe[0], state->cfg.output_mode);
2187 for (index_frontend=1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
2188 dib8000_set_output_mode(state->fe[index_frontend], OUTMODE_DIVERSITY);
2189 dib8000_set_diversity_in(state->fe[index_frontend-1], 1);
2190 }
2191
2192 /* turn off the diversity of the last chip */
2193 dib8000_set_diversity_in(state->fe[index_frontend-1], 0);
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002194
2195 return ret;
2196}
2197
Olivier Grenie4c70e072011-01-03 15:33:37 -03002198static u16 dib8000_read_lock(struct dvb_frontend *fe) {
2199 struct dib8000_state *state = fe->demodulator_priv;
2200
2201 return dib8000_read_word(state, 568);
2202}
2203
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002204static int dib8000_read_status(struct dvb_frontend *fe, fe_status_t * stat)
2205{
2206 struct dib8000_state *state = fe->demodulator_priv;
Olivier Grenie4c70e072011-01-03 15:33:37 -03002207 u16 lock_slave = 0, lock = dib8000_read_word(state, 568);
2208 u8 index_frontend;
2209
2210 for (index_frontend=1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++)
2211 lock_slave |= dib8000_read_lock(state->fe[index_frontend]);
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002212
2213 *stat = 0;
2214
Olivier Grenie4c70e072011-01-03 15:33:37 -03002215 if (((lock >> 13) & 1) || ((lock_slave >> 13) & 1))
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002216 *stat |= FE_HAS_SIGNAL;
2217
Olivier Grenie4c70e072011-01-03 15:33:37 -03002218 if (((lock >> 8) & 1) || ((lock_slave >> 8) & 1)) /* Equal */
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002219 *stat |= FE_HAS_CARRIER;
2220
Olivier Grenie4c70e072011-01-03 15:33:37 -03002221 if ((((lock >> 1) & 0xf) == 0xf) || (((lock_slave >> 1) & 0xf) == 0xf)) /* TMCC_SYNC */
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002222 *stat |= FE_HAS_SYNC;
2223
Olivier Grenie4c70e072011-01-03 15:33:37 -03002224 if ((((lock >> 12) & 1) || ((lock_slave >> 12) & 1)) && ((lock >> 5) & 7)) /* FEC MPEG */
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002225 *stat |= FE_HAS_LOCK;
2226
Olivier Grenie4c70e072011-01-03 15:33:37 -03002227 if (((lock >> 12) & 1) || ((lock_slave >> 12) & 1)) {
Olivier Grenie89dfc552009-11-30 06:38:49 -03002228 lock = dib8000_read_word(state, 554); /* Viterbi Layer A */
2229 if (lock & 0x01)
2230 *stat |= FE_HAS_VITERBI;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002231
Olivier Grenie89dfc552009-11-30 06:38:49 -03002232 lock = dib8000_read_word(state, 555); /* Viterbi Layer B */
2233 if (lock & 0x01)
2234 *stat |= FE_HAS_VITERBI;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002235
Olivier Grenie89dfc552009-11-30 06:38:49 -03002236 lock = dib8000_read_word(state, 556); /* Viterbi Layer C */
2237 if (lock & 0x01)
2238 *stat |= FE_HAS_VITERBI;
2239 }
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002240
2241 return 0;
2242}
2243
2244static int dib8000_read_ber(struct dvb_frontend *fe, u32 * ber)
2245{
2246 struct dib8000_state *state = fe->demodulator_priv;
2247 *ber = (dib8000_read_word(state, 560) << 16) | dib8000_read_word(state, 561); // 13 segments
2248 return 0;
2249}
2250
2251static int dib8000_read_unc_blocks(struct dvb_frontend *fe, u32 * unc)
2252{
2253 struct dib8000_state *state = fe->demodulator_priv;
2254 *unc = dib8000_read_word(state, 565); // packet error on 13 seg
2255 return 0;
2256}
2257
2258static int dib8000_read_signal_strength(struct dvb_frontend *fe, u16 * strength)
2259{
2260 struct dib8000_state *state = fe->demodulator_priv;
Olivier Grenie4c70e072011-01-03 15:33:37 -03002261 u8 index_frontend;
2262 u16 val;
2263
2264 *strength = 0;
2265 for (index_frontend=1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
2266 state->fe[index_frontend]->ops.read_signal_strength(state->fe[index_frontend], &val);
2267 if (val > 65535 - *strength)
2268 *strength = 65535;
2269 else
2270 *strength += val;
2271 }
2272
2273 val = 65535 - dib8000_read_word(state, 390);
2274 if (val > 65535 - *strength)
2275 *strength = 65535;
2276 else
2277 *strength += val;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002278 return 0;
2279}
2280
Olivier Grenie4c70e072011-01-03 15:33:37 -03002281static u32 dib8000_get_snr(struct dvb_frontend *fe)
2282{
2283 struct dib8000_state *state = fe->demodulator_priv;
2284 u32 n, s, exp;
2285 u16 val;
2286
2287 val = dib8000_read_word(state, 542);
2288 n = (val >> 6) & 0xff;
2289 exp = (val & 0x3f);
2290 if ((exp & 0x20) != 0)
2291 exp -= 0x40;
2292 n <<= exp+16;
2293
2294 val = dib8000_read_word(state, 543);
2295 s = (val >> 6) & 0xff;
2296 exp = (val & 0x3f);
2297 if ((exp & 0x20) != 0)
2298 exp -= 0x40;
2299 s <<= exp+16;
2300
2301 if (n > 0) {
2302 u32 t = (s/n) << 16;
2303 return t + ((s << 16) - n*t) / n;
2304 }
2305 return 0xffffffff;
2306}
2307
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002308static int dib8000_read_snr(struct dvb_frontend *fe, u16 * snr)
2309{
2310 struct dib8000_state *state = fe->demodulator_priv;
Olivier Grenie4c70e072011-01-03 15:33:37 -03002311 u8 index_frontend;
2312 u32 snr_master;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002313
Olivier Grenie4c70e072011-01-03 15:33:37 -03002314 snr_master = dib8000_get_snr(fe);
2315 for (index_frontend=1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++)
2316 snr_master += dib8000_get_snr(state->fe[index_frontend]);
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002317
Olivier Grenie4c70e072011-01-03 15:33:37 -03002318 if (snr_master != 0) {
2319 snr_master = 10*intlog10(snr_master>>16);
2320 *snr = snr_master / ((1 << 24) / 10);
2321 }
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002322 else
Olivier Grenie4c70e072011-01-03 15:33:37 -03002323 *snr = 0;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002324
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002325 return 0;
2326}
2327
Olivier Grenie4c70e072011-01-03 15:33:37 -03002328int dib8000_set_slave_frontend(struct dvb_frontend *fe, struct dvb_frontend *fe_slave)
2329{
2330 struct dib8000_state *state = fe->demodulator_priv;
2331 u8 index_frontend = 1;
2332
2333 while ((index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL))
2334 index_frontend++;
2335 if (index_frontend < MAX_NUMBER_OF_FRONTENDS) {
2336 dprintk("set slave fe %p to index %i", fe_slave, index_frontend);
2337 state->fe[index_frontend] = fe_slave;
2338 return 0;
2339 }
2340
2341 dprintk("too many slave frontend");
2342 return -ENOMEM;
2343}
2344EXPORT_SYMBOL(dib8000_set_slave_frontend);
2345
2346int dib8000_remove_slave_frontend(struct dvb_frontend *fe)
2347{
2348 struct dib8000_state *state = fe->demodulator_priv;
2349 u8 index_frontend = 1;
2350
2351 while ((index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL))
2352 index_frontend++;
2353 if (index_frontend != 1) {
2354 dprintk("remove slave fe %p (index %i)", state->fe[index_frontend-1], index_frontend-1);
2355 state->fe[index_frontend] = NULL;
2356 return 0;
2357 }
2358
2359 dprintk("no frontend to be removed");
2360 return -ENODEV;
2361}
2362EXPORT_SYMBOL(dib8000_remove_slave_frontend);
2363
2364struct dvb_frontend * dib8000_get_slave_frontend(struct dvb_frontend *fe, int slave_index)
2365{
2366 struct dib8000_state *state = fe->demodulator_priv;
2367
2368 if (slave_index >= MAX_NUMBER_OF_FRONTENDS)
2369 return NULL;
2370 return state->fe[slave_index];
2371}
2372EXPORT_SYMBOL(dib8000_get_slave_frontend);
2373
2374
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002375int dib8000_i2c_enumeration(struct i2c_adapter *host, int no_of_demods, u8 default_addr, u8 first_addr)
2376{
2377 int k = 0;
2378 u8 new_addr = 0;
2379 struct i2c_device client = {.adap = host };
2380
2381 for (k = no_of_demods - 1; k >= 0; k--) {
2382 /* designated i2c address */
2383 new_addr = first_addr + (k << 1);
2384
2385 client.addr = new_addr;
2386 dib8000_i2c_write16(&client, 1287, 0x0003); /* sram lead in, rdy */
2387 if (dib8000_identify(&client) == 0) {
2388 dib8000_i2c_write16(&client, 1287, 0x0003); /* sram lead in, rdy */
2389 client.addr = default_addr;
2390 if (dib8000_identify(&client) == 0) {
2391 dprintk("#%d: not identified", k);
2392 return -EINVAL;
2393 }
2394 }
2395
2396 /* start diversity to pull_down div_str - just for i2c-enumeration */
2397 dib8000_i2c_write16(&client, 1286, (1 << 10) | (4 << 6));
2398
2399 /* set new i2c address and force divstart */
2400 dib8000_i2c_write16(&client, 1285, (new_addr << 2) | 0x2);
2401 client.addr = new_addr;
2402 dib8000_identify(&client);
2403
2404 dprintk("IC %d initialized (to i2c_address 0x%x)", k, new_addr);
2405 }
2406
2407 for (k = 0; k < no_of_demods; k++) {
2408 new_addr = first_addr | (k << 1);
2409 client.addr = new_addr;
2410
2411 // unforce divstr
2412 dib8000_i2c_write16(&client, 1285, new_addr << 2);
2413
2414 /* deactivate div - it was just for i2c-enumeration */
2415 dib8000_i2c_write16(&client, 1286, 0);
2416 }
2417
2418 return 0;
2419}
2420
2421EXPORT_SYMBOL(dib8000_i2c_enumeration);
2422static int dib8000_fe_get_tune_settings(struct dvb_frontend *fe, struct dvb_frontend_tune_settings *tune)
2423{
2424 tune->min_delay_ms = 1000;
2425 tune->step_size = 0;
2426 tune->max_drift = 0;
2427 return 0;
2428}
2429
2430static void dib8000_release(struct dvb_frontend *fe)
2431{
2432 struct dib8000_state *st = fe->demodulator_priv;
Olivier Grenie4c70e072011-01-03 15:33:37 -03002433 u8 index_frontend;
2434
2435 for (index_frontend=1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (st->fe[index_frontend] != NULL); index_frontend++)
2436 dvb_frontend_detach(st->fe[index_frontend]);
2437
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002438 dibx000_exit_i2c_master(&st->i2c_master);
Olivier Grenie4c70e072011-01-03 15:33:37 -03002439 kfree(st->fe[0]);
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002440 kfree(st);
2441}
2442
2443struct i2c_adapter *dib8000_get_i2c_master(struct dvb_frontend *fe, enum dibx000_i2c_interface intf, int gating)
2444{
2445 struct dib8000_state *st = fe->demodulator_priv;
2446 return dibx000_get_i2c_adapter(&st->i2c_master, intf, gating);
2447}
2448
2449EXPORT_SYMBOL(dib8000_get_i2c_master);
2450
Olivier Grenief8731f42009-09-18 04:08:43 -03002451int dib8000_pid_filter_ctrl(struct dvb_frontend *fe, u8 onoff)
2452{
2453 struct dib8000_state *st = fe->demodulator_priv;
Olivier Grenie4c70e072011-01-03 15:33:37 -03002454 u16 val = dib8000_read_word(st, 299) & 0xffef;
2455 val |= (onoff & 0x1) << 4;
Olivier Grenief8731f42009-09-18 04:08:43 -03002456
Olivier Grenie4c70e072011-01-03 15:33:37 -03002457 dprintk("pid filter enabled %d", onoff);
2458 return dib8000_write_word(st, 299, val);
Olivier Grenief8731f42009-09-18 04:08:43 -03002459}
2460EXPORT_SYMBOL(dib8000_pid_filter_ctrl);
2461
2462int dib8000_pid_filter(struct dvb_frontend *fe, u8 id, u16 pid, u8 onoff)
2463{
2464 struct dib8000_state *st = fe->demodulator_priv;
Olivier Grenie4c70e072011-01-03 15:33:37 -03002465 dprintk("Index %x, PID %d, OnOff %d", id, pid, onoff);
2466 return dib8000_write_word(st, 305 + id, onoff ? (1 << 13) | pid : 0);
Olivier Grenief8731f42009-09-18 04:08:43 -03002467}
2468EXPORT_SYMBOL(dib8000_pid_filter);
2469
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002470static const struct dvb_frontend_ops dib8000_ops = {
2471 .info = {
2472 .name = "DiBcom 8000 ISDB-T",
2473 .type = FE_OFDM,
2474 .frequency_min = 44250000,
2475 .frequency_max = 867250000,
2476 .frequency_stepsize = 62500,
2477 .caps = FE_CAN_INVERSION_AUTO |
2478 FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
2479 FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
2480 FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO |
2481 FE_CAN_TRANSMISSION_MODE_AUTO | FE_CAN_GUARD_INTERVAL_AUTO | FE_CAN_RECOVER | FE_CAN_HIERARCHY_AUTO,
2482 },
2483
2484 .release = dib8000_release,
2485
2486 .init = dib8000_wakeup,
2487 .sleep = dib8000_sleep,
2488
2489 .set_frontend = dib8000_set_frontend,
2490 .get_tune_settings = dib8000_fe_get_tune_settings,
2491 .get_frontend = dib8000_get_frontend,
2492
2493 .read_status = dib8000_read_status,
2494 .read_ber = dib8000_read_ber,
2495 .read_signal_strength = dib8000_read_signal_strength,
2496 .read_snr = dib8000_read_snr,
2497 .read_ucblocks = dib8000_read_unc_blocks,
2498};
2499
2500struct dvb_frontend *dib8000_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr, struct dib8000_config *cfg)
2501{
2502 struct dvb_frontend *fe;
2503 struct dib8000_state *state;
2504
2505 dprintk("dib8000_attach");
2506
2507 state = kzalloc(sizeof(struct dib8000_state), GFP_KERNEL);
2508 if (state == NULL)
2509 return NULL;
Olivier Grenie4c70e072011-01-03 15:33:37 -03002510 fe = kzalloc(sizeof(struct dvb_frontend), GFP_KERNEL);
2511 if (fe == NULL)
2512 return NULL;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002513
2514 memcpy(&state->cfg, cfg, sizeof(struct dib8000_config));
2515 state->i2c.adap = i2c_adap;
2516 state->i2c.addr = i2c_addr;
2517 state->gpio_val = cfg->gpio_val;
2518 state->gpio_dir = cfg->gpio_dir;
2519
2520 /* Ensure the output mode remains at the previous default if it's
2521 * not specifically set by the caller.
2522 */
2523 if ((state->cfg.output_mode != OUTMODE_MPEG2_SERIAL) && (state->cfg.output_mode != OUTMODE_MPEG2_PAR_GATED_CLK))
2524 state->cfg.output_mode = OUTMODE_MPEG2_FIFO;
2525
Olivier Grenie4c70e072011-01-03 15:33:37 -03002526 state->fe[0] = fe;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002527 fe->demodulator_priv = state;
Olivier Grenie4c70e072011-01-03 15:33:37 -03002528 memcpy(&state->fe[0]->ops, &dib8000_ops, sizeof(struct dvb_frontend_ops));
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002529
2530 state->timf_default = cfg->pll->timf;
2531
2532 if (dib8000_identify(&state->i2c) == 0)
2533 goto error;
2534
2535 dibx000_init_i2c_master(&state->i2c_master, DIB8000, state->i2c.adap, state->i2c.addr);
2536
2537 dib8000_reset(fe);
2538
2539 dib8000_write_word(state, 285, (dib8000_read_word(state, 285) & ~0x60) | (3 << 5)); /* ber_rs_len = 3 */
2540
2541 return fe;
2542
2543 error:
2544 kfree(state);
2545 return NULL;
2546}
2547
2548EXPORT_SYMBOL(dib8000_attach);
2549
2550MODULE_AUTHOR("Olivier Grenie <Olivier.Grenie@dibcom.fr, " "Patrick Boettcher <pboettcher@dibcom.fr>");
2551MODULE_DESCRIPTION("Driver for the DiBcom 8000 ISDB-T demodulator");
2552MODULE_LICENSE("GPL");