blob: c1c3e26906e2843b7893fa666c4929cf8442e7e4 [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 Grenieb4d6046e2011-01-04 13:08:14 -0300264 dprintk("-I- Setting output mode for demod %p to %d",
265 &state->fe[0], mode);
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300266
267 switch (mode) {
268 case OUTMODE_MPEG2_PAR_GATED_CLK: // STBs with parallel gated clock
269 outreg = (1 << 10); /* 0x0400 */
270 break;
271 case OUTMODE_MPEG2_PAR_CONT_CLK: // STBs with parallel continues clock
272 outreg = (1 << 10) | (1 << 6); /* 0x0440 */
273 break;
274 case OUTMODE_MPEG2_SERIAL: // STBs with serial input
275 outreg = (1 << 10) | (2 << 6) | (0 << 1); /* 0x0482 */
276 break;
277 case OUTMODE_DIVERSITY:
278 if (state->cfg.hostbus_diversity) {
279 outreg = (1 << 10) | (4 << 6); /* 0x0500 */
280 sram &= 0xfdff;
281 } else
282 sram |= 0x0c00;
283 break;
284 case OUTMODE_MPEG2_FIFO: // e.g. USB feeding
285 smo_mode |= (3 << 1);
286 fifo_threshold = 512;
287 outreg = (1 << 10) | (5 << 6);
288 break;
289 case OUTMODE_HIGH_Z: // disable
290 outreg = 0;
291 break;
292
293 case OUTMODE_ANALOG_ADC:
294 outreg = (1 << 10) | (3 << 6);
295 dib8000_set_acquisition_mode(state);
296 break;
297
298 default:
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300299 dprintk("Unhandled output_mode passed to be set for demod %p",
300 &state->fe[0]);
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300301 return -EINVAL;
302 }
303
304 if (state->cfg.output_mpeg2_in_188_bytes)
305 smo_mode |= (1 << 5);
306
307 dib8000_write_word(state, 299, smo_mode);
308 dib8000_write_word(state, 300, fifo_threshold); /* synchronous fread */
309 dib8000_write_word(state, 1286, outreg);
310 dib8000_write_word(state, 1291, sram);
311
312 return 0;
313}
314
315static int dib8000_set_diversity_in(struct dvb_frontend *fe, int onoff)
316{
317 struct dib8000_state *state = fe->demodulator_priv;
318 u16 sync_wait = dib8000_read_word(state, 273) & 0xfff0;
319
320 if (!state->differential_constellation) {
321 dib8000_write_word(state, 272, 1 << 9); //dvsy_off_lmod4 = 1
322 dib8000_write_word(state, 273, sync_wait | (1 << 2) | 2); // sync_enable = 1; comb_mode = 2
323 } else {
324 dib8000_write_word(state, 272, 0); //dvsy_off_lmod4 = 0
325 dib8000_write_word(state, 273, sync_wait); // sync_enable = 0; comb_mode = 0
326 }
327 state->diversity_onoff = onoff;
328
329 switch (onoff) {
330 case 0: /* only use the internal way - not the diversity input */
331 dib8000_write_word(state, 270, 1);
332 dib8000_write_word(state, 271, 0);
333 break;
334 case 1: /* both ways */
335 dib8000_write_word(state, 270, 6);
336 dib8000_write_word(state, 271, 6);
337 break;
338 case 2: /* only the diversity input */
339 dib8000_write_word(state, 270, 0);
340 dib8000_write_word(state, 271, 1);
341 break;
342 }
343 return 0;
344}
345
346static void dib8000_set_power_mode(struct dib8000_state *state, enum dib8000_power_mode mode)
347{
348 /* by default everything is going to be powered off */
349 u16 reg_774 = 0x3fff, reg_775 = 0xffff, reg_776 = 0xffff,
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300350 reg_900 = (dib8000_read_word(state, 900) & 0xfffc) | 0x3,
351 reg_1280 = (dib8000_read_word(state, 1280) & 0x00ff) | 0xff00;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300352
353 /* now, depending on the requested mode, we power on */
354 switch (mode) {
355 /* power up everything in the demod */
356 case DIB8000M_POWER_ALL:
357 reg_774 = 0x0000;
358 reg_775 = 0x0000;
359 reg_776 = 0x0000;
360 reg_900 &= 0xfffc;
361 reg_1280 &= 0x00ff;
362 break;
363 case DIB8000M_POWER_INTERFACE_ONLY:
364 reg_1280 &= 0x00ff;
365 break;
366 }
367
368 dprintk("powermode : 774 : %x ; 775 : %x; 776 : %x ; 900 : %x; 1280 : %x", reg_774, reg_775, reg_776, reg_900, reg_1280);
369 dib8000_write_word(state, 774, reg_774);
370 dib8000_write_word(state, 775, reg_775);
371 dib8000_write_word(state, 776, reg_776);
372 dib8000_write_word(state, 900, reg_900);
373 dib8000_write_word(state, 1280, reg_1280);
374}
375
376static int dib8000_set_adc_state(struct dib8000_state *state, enum dibx000_adc_states no)
377{
378 int ret = 0;
379 u16 reg_907 = dib8000_read_word(state, 907), reg_908 = dib8000_read_word(state, 908);
380
381 switch (no) {
382 case DIBX000_SLOW_ADC_ON:
383 reg_908 |= (1 << 1) | (1 << 0);
384 ret |= dib8000_write_word(state, 908, reg_908);
385 reg_908 &= ~(1 << 1);
386 break;
387
388 case DIBX000_SLOW_ADC_OFF:
389 reg_908 |= (1 << 1) | (1 << 0);
390 break;
391
392 case DIBX000_ADC_ON:
393 reg_907 &= 0x0fff;
394 reg_908 &= 0x0003;
395 break;
396
397 case DIBX000_ADC_OFF: // leave the VBG voltage on
398 reg_907 |= (1 << 14) | (1 << 13) | (1 << 12);
399 reg_908 |= (1 << 5) | (1 << 4) | (1 << 3) | (1 << 2);
400 break;
401
402 case DIBX000_VBG_ENABLE:
403 reg_907 &= ~(1 << 15);
404 break;
405
406 case DIBX000_VBG_DISABLE:
407 reg_907 |= (1 << 15);
408 break;
409
410 default:
411 break;
412 }
413
414 ret |= dib8000_write_word(state, 907, reg_907);
415 ret |= dib8000_write_word(state, 908, reg_908);
416
417 return ret;
418}
419
Olivier Grenie4c70e072011-01-03 15:33:37 -0300420static int dib8000_set_bandwidth(struct dvb_frontend *fe, u32 bw)
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300421{
Olivier Grenie4c70e072011-01-03 15:33:37 -0300422 struct dib8000_state *state = fe->demodulator_priv;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300423 u32 timf;
424
425 if (bw == 0)
426 bw = 6000;
427
428 if (state->timf == 0) {
429 dprintk("using default timf");
430 timf = state->timf_default;
431 } else {
432 dprintk("using updated timf");
433 timf = state->timf;
434 }
435
436 dib8000_write_word(state, 29, (u16) ((timf >> 16) & 0xffff));
437 dib8000_write_word(state, 30, (u16) ((timf) & 0xffff));
438
439 return 0;
440}
441
442static int dib8000_sad_calib(struct dib8000_state *state)
443{
444/* internal */
445 dib8000_write_word(state, 923, (0 << 1) | (0 << 0));
446 dib8000_write_word(state, 924, 776); // 0.625*3.3 / 4096
447
448 /* do the calibration */
449 dib8000_write_word(state, 923, (1 << 0));
450 dib8000_write_word(state, 923, (0 << 0));
451
452 msleep(1);
453 return 0;
454}
455
456int dib8000_set_wbd_ref(struct dvb_frontend *fe, u16 value)
457{
458 struct dib8000_state *state = fe->demodulator_priv;
459 if (value > 4095)
460 value = 4095;
461 state->wbd_ref = value;
462 return dib8000_write_word(state, 106, value);
463}
464
465EXPORT_SYMBOL(dib8000_set_wbd_ref);
466static void dib8000_reset_pll_common(struct dib8000_state *state, const struct dibx000_bandwidth_config *bw)
467{
468 dprintk("ifreq: %d %x, inversion: %d", bw->ifreq, bw->ifreq, bw->ifreq >> 25);
469 dib8000_write_word(state, 23, (u16) (((bw->internal * 1000) >> 16) & 0xffff)); /* P_sec_len */
470 dib8000_write_word(state, 24, (u16) ((bw->internal * 1000) & 0xffff));
471 dib8000_write_word(state, 27, (u16) ((bw->ifreq >> 16) & 0x01ff));
472 dib8000_write_word(state, 28, (u16) (bw->ifreq & 0xffff));
473 dib8000_write_word(state, 26, (u16) ((bw->ifreq >> 25) & 0x0003));
474
475 dib8000_write_word(state, 922, bw->sad_cfg);
476}
477
478static void dib8000_reset_pll(struct dib8000_state *state)
479{
480 const struct dibx000_bandwidth_config *pll = state->cfg.pll;
481 u16 clk_cfg1;
482
483 // clk_cfg0
484 dib8000_write_word(state, 901, (pll->pll_prediv << 8) | (pll->pll_ratio << 0));
485
486 // clk_cfg1
487 clk_cfg1 = (1 << 10) | (0 << 9) | (pll->IO_CLK_en_core << 8) |
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300488 (pll->bypclk_div << 5) | (pll->enable_refdiv << 4) | (1 << 3) |
489 (pll->pll_range << 1) | (pll->pll_reset << 0);
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300490
491 dib8000_write_word(state, 902, clk_cfg1);
492 clk_cfg1 = (clk_cfg1 & 0xfff7) | (pll->pll_bypass << 3);
493 dib8000_write_word(state, 902, clk_cfg1);
494
495 dprintk("clk_cfg1: 0x%04x", clk_cfg1); /* 0x507 1 0 1 000 0 0 11 1 */
496
497 /* smpl_cfg: P_refclksel=2, P_ensmplsel=1 nodivsmpl=1 */
498 if (state->cfg.pll->ADClkSrc == 0)
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300499 dib8000_write_word(state, 904, (0 << 15) | (0 << 12) | (0 << 10) |
500 (pll->modulo << 8) | (pll->ADClkSrc << 7) | (0 << 1));
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300501 else if (state->cfg.refclksel != 0)
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300502 dib8000_write_word(state, 904, (0 << 15) | (1 << 12) |
503 ((state->cfg.refclksel & 0x3) << 10) | (pll->modulo << 8) |
504 (pll->ADClkSrc << 7) | (0 << 1));
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300505 else
506 dib8000_write_word(state, 904, (0 << 15) | (1 << 12) | (3 << 10) | (pll->modulo << 8) | (pll->ADClkSrc << 7) | (0 << 1));
507
508 dib8000_reset_pll_common(state, pll);
509}
510
511static int dib8000_reset_gpio(struct dib8000_state *st)
512{
513 /* reset the GPIOs */
514 dib8000_write_word(st, 1029, st->cfg.gpio_dir);
515 dib8000_write_word(st, 1030, st->cfg.gpio_val);
516
517 /* TODO 782 is P_gpio_od */
518
519 dib8000_write_word(st, 1032, st->cfg.gpio_pwm_pos);
520
521 dib8000_write_word(st, 1037, st->cfg.pwm_freq_div);
522 return 0;
523}
524
525static int dib8000_cfg_gpio(struct dib8000_state *st, u8 num, u8 dir, u8 val)
526{
527 st->cfg.gpio_dir = dib8000_read_word(st, 1029);
528 st->cfg.gpio_dir &= ~(1 << num); /* reset the direction bit */
529 st->cfg.gpio_dir |= (dir & 0x1) << num; /* set the new direction */
530 dib8000_write_word(st, 1029, st->cfg.gpio_dir);
531
532 st->cfg.gpio_val = dib8000_read_word(st, 1030);
533 st->cfg.gpio_val &= ~(1 << num); /* reset the direction bit */
534 st->cfg.gpio_val |= (val & 0x01) << num; /* set the new value */
535 dib8000_write_word(st, 1030, st->cfg.gpio_val);
536
537 dprintk("gpio dir: %x: gpio val: %x", st->cfg.gpio_dir, st->cfg.gpio_val);
538
539 return 0;
540}
541
542int dib8000_set_gpio(struct dvb_frontend *fe, u8 num, u8 dir, u8 val)
543{
544 struct dib8000_state *state = fe->demodulator_priv;
545 return dib8000_cfg_gpio(state, num, dir, val);
546}
547
548EXPORT_SYMBOL(dib8000_set_gpio);
549static const u16 dib8000_defaults[] = {
550 /* auto search configuration - lock0 by default waiting
551 * for cpil_lock; lock1 cpil_lock; lock2 tmcc_sync_lock */
552 3, 7,
553 0x0004,
554 0x0400,
555 0x0814,
556
557 12, 11,
558 0x001b,
559 0x7740,
560 0x005b,
561 0x8d80,
562 0x01c9,
563 0xc380,
564 0x0000,
565 0x0080,
566 0x0000,
567 0x0090,
568 0x0001,
569 0xd4c0,
570
571 /*1, 32,
Olivier Grenie4c70e072011-01-03 15:33:37 -0300572 0x6680 // P_corm_thres Lock algorithms configuration */
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300573
574 11, 80, /* set ADC level to -16 */
575 (1 << 13) - 825 - 117,
576 (1 << 13) - 837 - 117,
577 (1 << 13) - 811 - 117,
578 (1 << 13) - 766 - 117,
579 (1 << 13) - 737 - 117,
580 (1 << 13) - 693 - 117,
581 (1 << 13) - 648 - 117,
582 (1 << 13) - 619 - 117,
583 (1 << 13) - 575 - 117,
584 (1 << 13) - 531 - 117,
585 (1 << 13) - 501 - 117,
586
587 4, 108,
588 0,
589 0,
590 0,
591 0,
592
593 1, 175,
594 0x0410,
595 1, 179,
596 8192, // P_fft_nb_to_cut
597
598 6, 181,
599 0x2800, // P_coff_corthres_ ( 2k 4k 8k ) 0x2800
600 0x2800,
601 0x2800,
602 0x2800, // P_coff_cpilthres_ ( 2k 4k 8k ) 0x2800
603 0x2800,
604 0x2800,
605
606 2, 193,
607 0x0666, // P_pha3_thres
608 0x0000, // P_cti_use_cpe, P_cti_use_prog
609
610 2, 205,
611 0x200f, // P_cspu_regul, P_cspu_win_cut
612 0x000f, // P_des_shift_work
613
614 5, 215,
615 0x023d, // P_adp_regul_cnt
616 0x00a4, // P_adp_noise_cnt
617 0x00a4, // P_adp_regul_ext
618 0x7ff0, // P_adp_noise_ext
619 0x3ccc, // P_adp_fil
620
621 1, 230,
622 0x0000, // P_2d_byp_ti_num
623
624 1, 263,
625 0x800, //P_equal_thres_wgn
626
627 1, 268,
628 (2 << 9) | 39, // P_equal_ctrl_synchro, P_equal_speedmode
629
630 1, 270,
631 0x0001, // P_div_lock0_wait
632 1, 285,
633 0x0020, //p_fec_
634 1, 299,
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300635 0x0062, /* P_smo_mode, P_smo_rs_discard, P_smo_fifo_flush, P_smo_pid_parse, P_smo_error_discard */
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300636
637 1, 338,
638 (1 << 12) | // P_ctrl_corm_thres4pre_freq_inh=1
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300639 (1 << 10) |
640 (0 << 9) | /* P_ctrl_pre_freq_inh=0 */
641 (3 << 5) | /* P_ctrl_pre_freq_step=3 */
642 (1 << 0), /* P_pre_freq_win_len=1 */
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300643
644 1, 903,
645 (0 << 4) | 2, // P_divclksel=0 P_divbitsel=2 (was clk=3,bit=1 for MPW)
646
647 0,
648};
649
650static u16 dib8000_identify(struct i2c_device *client)
651{
652 u16 value;
653
654 //because of glitches sometimes
655 value = dib8000_i2c_read16(client, 896);
656
657 if ((value = dib8000_i2c_read16(client, 896)) != 0x01b3) {
658 dprintk("wrong Vendor ID (read=0x%x)", value);
659 return 0;
660 }
661
662 value = dib8000_i2c_read16(client, 897);
663 if (value != 0x8000 && value != 0x8001 && value != 0x8002) {
664 dprintk("wrong Device ID (%x)", value);
665 return 0;
666 }
667
668 switch (value) {
669 case 0x8000:
670 dprintk("found DiB8000A");
671 break;
672 case 0x8001:
673 dprintk("found DiB8000B");
674 break;
675 case 0x8002:
676 dprintk("found DiB8000C");
677 break;
678 }
679 return value;
680}
681
682static int dib8000_reset(struct dvb_frontend *fe)
683{
684 struct dib8000_state *state = fe->demodulator_priv;
685
686 dib8000_write_word(state, 1287, 0x0003); /* sram lead in, rdy */
687
688 if ((state->revision = dib8000_identify(&state->i2c)) == 0)
689 return -EINVAL;
690
691 if (state->revision == 0x8000)
692 dprintk("error : dib8000 MA not supported");
693
694 dibx000_reset_i2c_master(&state->i2c_master);
695
696 dib8000_set_power_mode(state, DIB8000M_POWER_ALL);
697
698 /* always leave the VBG voltage on - it consumes almost nothing but takes a long time to start */
699 dib8000_set_adc_state(state, DIBX000_VBG_ENABLE);
700
701 /* restart all parts */
702 dib8000_write_word(state, 770, 0xffff);
703 dib8000_write_word(state, 771, 0xffff);
704 dib8000_write_word(state, 772, 0xfffc);
705 dib8000_write_word(state, 898, 0x000c); // sad
706 dib8000_write_word(state, 1280, 0x004d);
707 dib8000_write_word(state, 1281, 0x000c);
708
709 dib8000_write_word(state, 770, 0x0000);
710 dib8000_write_word(state, 771, 0x0000);
711 dib8000_write_word(state, 772, 0x0000);
712 dib8000_write_word(state, 898, 0x0004); // sad
713 dib8000_write_word(state, 1280, 0x0000);
714 dib8000_write_word(state, 1281, 0x0000);
715
716 /* drives */
717 if (state->cfg.drives)
718 dib8000_write_word(state, 906, state->cfg.drives);
719 else {
720 dprintk("using standard PAD-drive-settings, please adjust settings in config-struct to be optimal.");
721 dib8000_write_word(state, 906, 0x2d98); // min drive SDRAM - not optimal - adjust
722 }
723
724 dib8000_reset_pll(state);
725
726 if (dib8000_reset_gpio(state) != 0)
727 dprintk("GPIO reset was not successful.");
728
Olivier Grenie4c70e072011-01-03 15:33:37 -0300729 if (dib8000_set_output_mode(fe, OUTMODE_HIGH_Z) != 0)
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300730 dprintk("OUTPUT_MODE could not be resetted.");
731
732 state->current_agc = NULL;
733
734 // P_iqc_alpha_pha, P_iqc_alpha_amp, P_iqc_dcc_alpha, ...
735 /* P_iqc_ca2 = 0; P_iqc_impnc_on = 0; P_iqc_mode = 0; */
736 if (state->cfg.pll->ifreq == 0)
737 dib8000_write_word(state, 40, 0x0755); /* P_iqc_corr_inh = 0 enable IQcorr block */
738 else
739 dib8000_write_word(state, 40, 0x1f55); /* P_iqc_corr_inh = 1 disable IQcorr block */
740
741 {
742 u16 l = 0, r;
743 const u16 *n;
744 n = dib8000_defaults;
745 l = *n++;
746 while (l) {
747 r = *n++;
748 do {
749 dib8000_write_word(state, r, *n++);
750 r++;
751 } while (--l);
752 l = *n++;
753 }
754 }
755 state->isdbt_cfg_loaded = 0;
756
757 //div_cfg override for special configs
758 if (state->cfg.div_cfg != 0)
759 dib8000_write_word(state, 903, state->cfg.div_cfg);
760
761 /* unforce divstr regardless whether i2c enumeration was done or not */
762 dib8000_write_word(state, 1285, dib8000_read_word(state, 1285) & ~(1 << 1));
763
Olivier Grenie4c70e072011-01-03 15:33:37 -0300764 dib8000_set_bandwidth(fe, 6000);
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300765
766 dib8000_set_adc_state(state, DIBX000_SLOW_ADC_ON);
767 dib8000_sad_calib(state);
768 dib8000_set_adc_state(state, DIBX000_SLOW_ADC_OFF);
769
770 dib8000_set_power_mode(state, DIB8000M_POWER_INTERFACE_ONLY);
771
772 return 0;
773}
774
775static void dib8000_restart_agc(struct dib8000_state *state)
776{
777 // P_restart_iqc & P_restart_agc
778 dib8000_write_word(state, 770, 0x0a00);
779 dib8000_write_word(state, 770, 0x0000);
780}
781
782static int dib8000_update_lna(struct dib8000_state *state)
783{
784 u16 dyn_gain;
785
786 if (state->cfg.update_lna) {
787 // read dyn_gain here (because it is demod-dependent and not tuner)
788 dyn_gain = dib8000_read_word(state, 390);
789
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300790 if (state->cfg.update_lna(state->fe[0], dyn_gain)) {
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300791 dib8000_restart_agc(state);
792 return 1;
793 }
794 }
795 return 0;
796}
797
798static int dib8000_set_agc_config(struct dib8000_state *state, u8 band)
799{
800 struct dibx000_agc_config *agc = NULL;
801 int i;
802 if (state->current_band == band && state->current_agc != NULL)
803 return 0;
804 state->current_band = band;
805
806 for (i = 0; i < state->cfg.agc_config_count; i++)
807 if (state->cfg.agc[i].band_caps & band) {
808 agc = &state->cfg.agc[i];
809 break;
810 }
811
812 if (agc == NULL) {
813 dprintk("no valid AGC configuration found for band 0x%02x", band);
814 return -EINVAL;
815 }
816
817 state->current_agc = agc;
818
819 /* AGC */
820 dib8000_write_word(state, 76, agc->setup);
821 dib8000_write_word(state, 77, agc->inv_gain);
822 dib8000_write_word(state, 78, agc->time_stabiliz);
823 dib8000_write_word(state, 101, (agc->alpha_level << 12) | agc->thlock);
824
825 // Demod AGC loop configuration
826 dib8000_write_word(state, 102, (agc->alpha_mant << 5) | agc->alpha_exp);
827 dib8000_write_word(state, 103, (agc->beta_mant << 6) | agc->beta_exp);
828
829 dprintk("WBD: ref: %d, sel: %d, active: %d, alpha: %d",
830 state->wbd_ref != 0 ? state->wbd_ref : agc->wbd_ref, agc->wbd_sel, !agc->perform_agc_softsplit, agc->wbd_sel);
831
832 /* AGC continued */
833 if (state->wbd_ref != 0)
834 dib8000_write_word(state, 106, state->wbd_ref);
835 else // use default
836 dib8000_write_word(state, 106, agc->wbd_ref);
837 dib8000_write_word(state, 107, (agc->wbd_alpha << 9) | (agc->perform_agc_softsplit << 8));
838 dib8000_write_word(state, 108, agc->agc1_max);
839 dib8000_write_word(state, 109, agc->agc1_min);
840 dib8000_write_word(state, 110, agc->agc2_max);
841 dib8000_write_word(state, 111, agc->agc2_min);
842 dib8000_write_word(state, 112, (agc->agc1_pt1 << 8) | agc->agc1_pt2);
843 dib8000_write_word(state, 113, (agc->agc1_slope1 << 8) | agc->agc1_slope2);
844 dib8000_write_word(state, 114, (agc->agc2_pt1 << 8) | agc->agc2_pt2);
845 dib8000_write_word(state, 115, (agc->agc2_slope1 << 8) | agc->agc2_slope2);
846
847 dib8000_write_word(state, 75, agc->agc1_pt3);
848 dib8000_write_word(state, 923, (dib8000_read_word(state, 923) & 0xffe3) | (agc->wbd_inv << 4) | (agc->wbd_sel << 2)); /*LB : 929 -> 923 */
849
850 return 0;
851}
852
Olivier Grenie03245a52009-12-04 13:27:57 -0300853void dib8000_pwm_agc_reset(struct dvb_frontend *fe)
854{
855 struct dib8000_state *state = fe->demodulator_priv;
856 dib8000_set_adc_state(state, DIBX000_ADC_ON);
857 dib8000_set_agc_config(state, (unsigned char)(BAND_OF_FREQUENCY(fe->dtv_property_cache.frequency / 1000)));
858}
859EXPORT_SYMBOL(dib8000_pwm_agc_reset);
860
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300861static int dib8000_agc_soft_split(struct dib8000_state *state)
862{
863 u16 agc, split_offset;
864
865 if (!state->current_agc || !state->current_agc->perform_agc_softsplit || state->current_agc->split.max == 0)
866 return FE_CALLBACK_TIME_NEVER;
867
868 // n_agc_global
869 agc = dib8000_read_word(state, 390);
870
871 if (agc > state->current_agc->split.min_thres)
872 split_offset = state->current_agc->split.min;
873 else if (agc < state->current_agc->split.max_thres)
874 split_offset = state->current_agc->split.max;
875 else
876 split_offset = state->current_agc->split.max *
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300877 (agc - state->current_agc->split.min_thres) /
878 (state->current_agc->split.max_thres - state->current_agc->split.min_thres);
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300879
880 dprintk("AGC split_offset: %d", split_offset);
881
882 // P_agc_force_split and P_agc_split_offset
883 dib8000_write_word(state, 107, (dib8000_read_word(state, 107) & 0xff00) | split_offset);
884 return 5000;
885}
886
887static int dib8000_agc_startup(struct dvb_frontend *fe)
888{
889 struct dib8000_state *state = fe->demodulator_priv;
890 enum frontend_tune_state *tune_state = &state->tune_state;
891
892 int ret = 0;
893
894 switch (*tune_state) {
895 case CT_AGC_START:
896 // set power-up level: interf+analog+AGC
897
898 dib8000_set_adc_state(state, DIBX000_ADC_ON);
899
900 if (dib8000_set_agc_config(state, (unsigned char)(BAND_OF_FREQUENCY(fe->dtv_property_cache.frequency / 1000))) != 0) {
901 *tune_state = CT_AGC_STOP;
902 state->status = FE_STATUS_TUNE_FAILED;
903 break;
904 }
905
906 ret = 70;
907 *tune_state = CT_AGC_STEP_0;
908 break;
909
910 case CT_AGC_STEP_0:
911 //AGC initialization
912 if (state->cfg.agc_control)
Olivier Grenie4c70e072011-01-03 15:33:37 -0300913 state->cfg.agc_control(fe, 1);
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300914
915 dib8000_restart_agc(state);
916
917 // wait AGC rough lock time
918 ret = 50;
919 *tune_state = CT_AGC_STEP_1;
920 break;
921
922 case CT_AGC_STEP_1:
923 // wait AGC accurate lock time
924 ret = 70;
925
926 if (dib8000_update_lna(state))
927 // wait only AGC rough lock time
928 ret = 50;
929 else
930 *tune_state = CT_AGC_STEP_2;
931 break;
932
933 case CT_AGC_STEP_2:
934 dib8000_agc_soft_split(state);
935
936 if (state->cfg.agc_control)
Olivier Grenie4c70e072011-01-03 15:33:37 -0300937 state->cfg.agc_control(fe, 0);
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300938
939 *tune_state = CT_AGC_STOP;
940 break;
941 default:
942 ret = dib8000_agc_soft_split(state);
943 break;
944 }
945 return ret;
946
947}
948
Olivier Grenie4c70e072011-01-03 15:33:37 -0300949static const s32 lut_1000ln_mant[] =
Olivier Grenie03245a52009-12-04 13:27:57 -0300950{
Olivier Grenie9c783032009-12-07 07:49:40 -0300951 908, 7003, 7090, 7170, 7244, 7313, 7377, 7438, 7495, 7549, 7600
Olivier Grenie03245a52009-12-04 13:27:57 -0300952};
953
Olivier Grenie4c70e072011-01-03 15:33:37 -0300954s32 dib8000_get_adc_power(struct dvb_frontend *fe, u8 mode)
Olivier Grenie03245a52009-12-04 13:27:57 -0300955{
Olivier Grenie4c70e072011-01-03 15:33:37 -0300956 struct dib8000_state *state = fe->demodulator_priv;
957 u32 ix = 0, tmp_val = 0, exp = 0, mant = 0;
958 s32 val;
Olivier Grenie03245a52009-12-04 13:27:57 -0300959
Olivier Grenie4c70e072011-01-03 15:33:37 -0300960 val = dib8000_read32(state, 384);
Olivier Grenie4c70e072011-01-03 15:33:37 -0300961 if (mode) {
962 tmp_val = val;
963 while (tmp_val >>= 1)
964 exp++;
965 mant = (val * 1000 / (1<<exp));
966 ix = (u8)((mant-1000)/100); /* index of the LUT */
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300967 val = (lut_1000ln_mant[ix] + 693*(exp-20) - 6908);
Olivier Grenie4c70e072011-01-03 15:33:37 -0300968 val = (val*256)/1000;
969 }
970 return val;
Olivier Grenie03245a52009-12-04 13:27:57 -0300971}
972EXPORT_SYMBOL(dib8000_get_adc_power);
973
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300974static void dib8000_update_timf(struct dib8000_state *state)
975{
976 u32 timf = state->timf = dib8000_read32(state, 435);
977
978 dib8000_write_word(state, 29, (u16) (timf >> 16));
979 dib8000_write_word(state, 30, (u16) (timf & 0xffff));
980 dprintk("Updated timing frequency: %d (default: %d)", state->timf, state->timf_default);
981}
982
983static void dib8000_set_channel(struct dib8000_state *state, u8 seq, u8 autosearching)
984{
985 u16 mode, max_constellation, seg_diff_mask = 0, nbseg_diff = 0;
986 u8 guard, crate, constellation, timeI;
987 u8 permu_seg[] = { 6, 5, 7, 4, 8, 3, 9, 2, 10, 1, 11, 0, 12 };
988 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 -0300989 const s16 *ncoeff = NULL, *ana_fe;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300990 u16 tmcc_pow = 0;
991 u16 coff_pow = 0x2800;
992 u16 init_prbs = 0xfff;
993 u16 ana_gain = 0;
994 u16 adc_target_16dB[11] = {
995 (1 << 13) - 825 - 117,
996 (1 << 13) - 837 - 117,
997 (1 << 13) - 811 - 117,
998 (1 << 13) - 766 - 117,
999 (1 << 13) - 737 - 117,
1000 (1 << 13) - 693 - 117,
1001 (1 << 13) - 648 - 117,
1002 (1 << 13) - 619 - 117,
1003 (1 << 13) - 575 - 117,
1004 (1 << 13) - 531 - 117,
1005 (1 << 13) - 501 - 117
1006 };
1007
1008 if (state->ber_monitored_layer != LAYER_ALL)
1009 dib8000_write_word(state, 285, (dib8000_read_word(state, 285) & 0x60) | state->ber_monitored_layer);
1010 else
1011 dib8000_write_word(state, 285, dib8000_read_word(state, 285) & 0x60);
1012
1013 i = dib8000_read_word(state, 26) & 1; // P_dds_invspec
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001014 dib8000_write_word(state, 26, state->fe[0]->dtv_property_cache.inversion^i);
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001015
Olivier Grenie4c70e072011-01-03 15:33:37 -03001016 if (state->fe[0]->dtv_property_cache.isdbt_sb_mode) {
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001017 //compute new dds_freq for the seg and adjust prbs
1018 int seg_offset =
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001019 state->fe[0]->dtv_property_cache.isdbt_sb_segment_idx -
1020 (state->fe[0]->dtv_property_cache.isdbt_sb_segment_count / 2) -
Olivier Grenie4c70e072011-01-03 15:33:37 -03001021 (state->fe[0]->dtv_property_cache.isdbt_sb_segment_count % 2);
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001022 int clk = state->cfg.pll->internal;
1023 u32 segtodds = ((u32) (430 << 23) / clk) << 3; // segtodds = SegBW / Fclk * pow(2,26)
1024 int dds_offset = seg_offset * segtodds;
1025 int new_dds, sub_channel;
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001026 if ((state->fe[0]->dtv_property_cache.isdbt_sb_segment_count % 2) == 0)
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001027 dds_offset -= (int)(segtodds / 2);
1028
1029 if (state->cfg.pll->ifreq == 0) {
Olivier Grenie4c70e072011-01-03 15:33:37 -03001030 if ((state->fe[0]->dtv_property_cache.inversion ^ i) == 0) {
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001031 dib8000_write_word(state, 26, dib8000_read_word(state, 26) | 1);
1032 new_dds = dds_offset;
1033 } else
1034 new_dds = dds_offset;
1035
1036 // We shift tuning frequency if the wanted segment is :
1037 // - the segment of center frequency with an odd total number of segments
1038 // - the segment to the left of center frequency with an even total number of segments
1039 // - the segment to the right of center frequency with an even total number of segments
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001040 if ((state->fe[0]->dtv_property_cache.delivery_system == SYS_ISDBT)
1041 && (state->fe[0]->dtv_property_cache.isdbt_sb_mode == 1)
Olivier Grenie4c70e072011-01-03 15:33:37 -03001042 && (((state->fe[0]->dtv_property_cache.isdbt_sb_segment_count % 2)
1043 && (state->fe[0]->dtv_property_cache.isdbt_sb_segment_idx ==
1044 ((state->fe[0]->dtv_property_cache.isdbt_sb_segment_count / 2) + 1)))
1045 || (((state->fe[0]->dtv_property_cache.isdbt_sb_segment_count % 2) == 0)
1046 && (state->fe[0]->dtv_property_cache.isdbt_sb_segment_idx == (state->fe[0]->dtv_property_cache.isdbt_sb_segment_count / 2)))
1047 || (((state->fe[0]->dtv_property_cache.isdbt_sb_segment_count % 2) == 0)
1048 && (state->fe[0]->dtv_property_cache.isdbt_sb_segment_idx ==
1049 ((state->fe[0]->dtv_property_cache.isdbt_sb_segment_count / 2) + 1)))
1050 )) {
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001051 new_dds -= ((u32) (850 << 22) / clk) << 4; // new_dds = 850 (freq shift in KHz) / Fclk * pow(2,26)
1052 }
1053 } else {
Olivier Grenie4c70e072011-01-03 15:33:37 -03001054 if ((state->fe[0]->dtv_property_cache.inversion ^ i) == 0)
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001055 new_dds = state->cfg.pll->ifreq - dds_offset;
1056 else
1057 new_dds = state->cfg.pll->ifreq + dds_offset;
1058 }
1059 dib8000_write_word(state, 27, (u16) ((new_dds >> 16) & 0x01ff));
1060 dib8000_write_word(state, 28, (u16) (new_dds & 0xffff));
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001061 if (state->fe[0]->dtv_property_cache.isdbt_sb_segment_count % 2)
Olivier Grenie4c70e072011-01-03 15:33:37 -03001062 sub_channel = ((state->fe[0]->dtv_property_cache.isdbt_sb_subchannel + (3 * seg_offset) + 1) % 41) / 3;
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001063 else
Olivier Grenie4c70e072011-01-03 15:33:37 -03001064 sub_channel = ((state->fe[0]->dtv_property_cache.isdbt_sb_subchannel + (3 * seg_offset)) % 41) / 3;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001065 sub_channel -= 6;
1066
Olivier Grenie4c70e072011-01-03 15:33:37 -03001067 if (state->fe[0]->dtv_property_cache.transmission_mode == TRANSMISSION_MODE_2K
1068 || state->fe[0]->dtv_property_cache.transmission_mode == TRANSMISSION_MODE_4K) {
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001069 dib8000_write_word(state, 219, dib8000_read_word(state, 219) | 0x1); //adp_pass =1
1070 dib8000_write_word(state, 190, dib8000_read_word(state, 190) | (0x1 << 14)); //pha3_force_pha_shift = 1
1071 } else {
1072 dib8000_write_word(state, 219, dib8000_read_word(state, 219) & 0xfffe); //adp_pass =0
1073 dib8000_write_word(state, 190, dib8000_read_word(state, 190) & 0xbfff); //pha3_force_pha_shift = 0
1074 }
1075
Olivier Grenie4c70e072011-01-03 15:33:37 -03001076 switch (state->fe[0]->dtv_property_cache.transmission_mode) {
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001077 case TRANSMISSION_MODE_2K:
1078 switch (sub_channel) {
1079 case -6:
1080 init_prbs = 0x0;
1081 break; // 41, 0, 1
1082 case -5:
1083 init_prbs = 0x423;
1084 break; // 02~04
1085 case -4:
1086 init_prbs = 0x9;
1087 break; // 05~07
1088 case -3:
1089 init_prbs = 0x5C7;
1090 break; // 08~10
1091 case -2:
1092 init_prbs = 0x7A6;
1093 break; // 11~13
1094 case -1:
1095 init_prbs = 0x3D8;
1096 break; // 14~16
1097 case 0:
1098 init_prbs = 0x527;
1099 break; // 17~19
1100 case 1:
1101 init_prbs = 0x7FF;
1102 break; // 20~22
1103 case 2:
1104 init_prbs = 0x79B;
1105 break; // 23~25
1106 case 3:
1107 init_prbs = 0x3D6;
1108 break; // 26~28
1109 case 4:
1110 init_prbs = 0x3A2;
1111 break; // 29~31
1112 case 5:
1113 init_prbs = 0x53B;
1114 break; // 32~34
1115 case 6:
1116 init_prbs = 0x2F4;
1117 break; // 35~37
1118 default:
1119 case 7:
1120 init_prbs = 0x213;
1121 break; // 38~40
1122 }
1123 break;
1124
1125 case TRANSMISSION_MODE_4K:
1126 switch (sub_channel) {
1127 case -6:
1128 init_prbs = 0x0;
1129 break; // 41, 0, 1
1130 case -5:
1131 init_prbs = 0x208;
1132 break; // 02~04
1133 case -4:
1134 init_prbs = 0xC3;
1135 break; // 05~07
1136 case -3:
1137 init_prbs = 0x7B9;
1138 break; // 08~10
1139 case -2:
1140 init_prbs = 0x423;
1141 break; // 11~13
1142 case -1:
1143 init_prbs = 0x5C7;
1144 break; // 14~16
1145 case 0:
1146 init_prbs = 0x3D8;
1147 break; // 17~19
1148 case 1:
1149 init_prbs = 0x7FF;
1150 break; // 20~22
1151 case 2:
1152 init_prbs = 0x3D6;
1153 break; // 23~25
1154 case 3:
1155 init_prbs = 0x53B;
1156 break; // 26~28
1157 case 4:
1158 init_prbs = 0x213;
1159 break; // 29~31
1160 case 5:
1161 init_prbs = 0x29;
1162 break; // 32~34
1163 case 6:
1164 init_prbs = 0xD0;
1165 break; // 35~37
1166 default:
1167 case 7:
1168 init_prbs = 0x48E;
1169 break; // 38~40
1170 }
1171 break;
1172
1173 default:
1174 case TRANSMISSION_MODE_8K:
1175 switch (sub_channel) {
1176 case -6:
1177 init_prbs = 0x0;
1178 break; // 41, 0, 1
1179 case -5:
1180 init_prbs = 0x740;
1181 break; // 02~04
1182 case -4:
1183 init_prbs = 0x069;
1184 break; // 05~07
1185 case -3:
1186 init_prbs = 0x7DD;
1187 break; // 08~10
1188 case -2:
1189 init_prbs = 0x208;
1190 break; // 11~13
1191 case -1:
1192 init_prbs = 0x7B9;
1193 break; // 14~16
1194 case 0:
1195 init_prbs = 0x5C7;
1196 break; // 17~19
1197 case 1:
1198 init_prbs = 0x7FF;
1199 break; // 20~22
1200 case 2:
1201 init_prbs = 0x53B;
1202 break; // 23~25
1203 case 3:
1204 init_prbs = 0x29;
1205 break; // 26~28
1206 case 4:
1207 init_prbs = 0x48E;
1208 break; // 29~31
1209 case 5:
1210 init_prbs = 0x4C4;
1211 break; // 32~34
1212 case 6:
1213 init_prbs = 0x367;
1214 break; // 33~37
1215 default:
1216 case 7:
1217 init_prbs = 0x684;
1218 break; // 38~40
1219 }
1220 break;
1221 }
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001222 } else {
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001223 dib8000_write_word(state, 27, (u16) ((state->cfg.pll->ifreq >> 16) & 0x01ff));
1224 dib8000_write_word(state, 28, (u16) (state->cfg.pll->ifreq & 0xffff));
1225 dib8000_write_word(state, 26, (u16) ((state->cfg.pll->ifreq >> 25) & 0x0003));
1226 }
1227 /*P_mode == ?? */
1228 dib8000_write_word(state, 10, (seq << 4));
1229 // dib8000_write_word(state, 287, (dib8000_read_word(state, 287) & 0xe000) | 0x1000);
1230
Olivier Grenie4c70e072011-01-03 15:33:37 -03001231 switch (state->fe[0]->dtv_property_cache.guard_interval) {
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001232 case GUARD_INTERVAL_1_32:
1233 guard = 0;
1234 break;
1235 case GUARD_INTERVAL_1_16:
1236 guard = 1;
1237 break;
1238 case GUARD_INTERVAL_1_8:
1239 guard = 2;
1240 break;
1241 case GUARD_INTERVAL_1_4:
1242 default:
1243 guard = 3;
1244 break;
1245 }
1246
1247 dib8000_write_word(state, 1, (init_prbs << 2) | (guard & 0x3)); // ADDR 1
1248
1249 max_constellation = DQPSK;
1250 for (i = 0; i < 3; i++) {
Olivier Grenie4c70e072011-01-03 15:33:37 -03001251 switch (state->fe[0]->dtv_property_cache.layer[i].modulation) {
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001252 case DQPSK:
1253 constellation = 0;
1254 break;
1255 case QPSK:
1256 constellation = 1;
1257 break;
1258 case QAM_16:
1259 constellation = 2;
1260 break;
1261 case QAM_64:
1262 default:
1263 constellation = 3;
1264 break;
1265 }
1266
Olivier Grenie4c70e072011-01-03 15:33:37 -03001267 switch (state->fe[0]->dtv_property_cache.layer[i].fec) {
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001268 case FEC_1_2:
1269 crate = 1;
1270 break;
1271 case FEC_2_3:
1272 crate = 2;
1273 break;
1274 case FEC_3_4:
1275 crate = 3;
1276 break;
1277 case FEC_5_6:
1278 crate = 5;
1279 break;
1280 case FEC_7_8:
1281 default:
1282 crate = 7;
1283 break;
1284 }
1285
Olivier Grenie4c70e072011-01-03 15:33:37 -03001286 if ((state->fe[0]->dtv_property_cache.layer[i].interleaving > 0) &&
1287 ((state->fe[0]->dtv_property_cache.layer[i].interleaving <= 3) ||
1288 (state->fe[0]->dtv_property_cache.layer[i].interleaving == 4 && state->fe[0]->dtv_property_cache.isdbt_sb_mode == 1))
1289 )
1290 timeI = state->fe[0]->dtv_property_cache.layer[i].interleaving;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001291 else
1292 timeI = 0;
Olivier Grenie4c70e072011-01-03 15:33:37 -03001293 dib8000_write_word(state, 2 + i, (constellation << 10) | ((state->fe[0]->dtv_property_cache.layer[i].segment_count & 0xf) << 6) |
1294 (crate << 3) | timeI);
1295 if (state->fe[0]->dtv_property_cache.layer[i].segment_count > 0) {
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001296 switch (max_constellation) {
1297 case DQPSK:
1298 case QPSK:
Olivier Grenie4c70e072011-01-03 15:33:37 -03001299 if (state->fe[0]->dtv_property_cache.layer[i].modulation == QAM_16 ||
1300 state->fe[0]->dtv_property_cache.layer[i].modulation == QAM_64)
1301 max_constellation = state->fe[0]->dtv_property_cache.layer[i].modulation;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001302 break;
1303 case QAM_16:
Olivier Grenie4c70e072011-01-03 15:33:37 -03001304 if (state->fe[0]->dtv_property_cache.layer[i].modulation == QAM_64)
1305 max_constellation = state->fe[0]->dtv_property_cache.layer[i].modulation;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001306 break;
1307 }
1308 }
1309 }
1310
1311 mode = fft_to_mode(state);
1312
1313 //dib8000_write_word(state, 5, 13); /*p_last_seg = 13*/
1314
1315 dib8000_write_word(state, 274, (dib8000_read_word(state, 274) & 0xffcf) |
Olivier Grenie4c70e072011-01-03 15:33:37 -03001316 ((state->fe[0]->dtv_property_cache.isdbt_partial_reception & 1) << 5) | ((state->fe[0]->dtv_property_cache.
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001317 isdbt_sb_mode & 1) << 4));
1318
Olivier Grenie4c70e072011-01-03 15:33:37 -03001319 dprintk("mode = %d ; guard = %d", mode, state->fe[0]->dtv_property_cache.guard_interval);
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001320
1321 /* signal optimization parameter */
1322
Olivier Grenie4c70e072011-01-03 15:33:37 -03001323 if (state->fe[0]->dtv_property_cache.isdbt_partial_reception) {
1324 seg_diff_mask = (state->fe[0]->dtv_property_cache.layer[0].modulation == DQPSK) << permu_seg[0];
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001325 for (i = 1; i < 3; i++)
1326 nbseg_diff +=
Olivier Grenie4c70e072011-01-03 15:33:37 -03001327 (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 -03001328 for (i = 0; i < nbseg_diff; i++)
1329 seg_diff_mask |= 1 << permu_seg[i + 1];
1330 } else {
1331 for (i = 0; i < 3; i++)
1332 nbseg_diff +=
Olivier Grenie4c70e072011-01-03 15:33:37 -03001333 (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 -03001334 for (i = 0; i < nbseg_diff; i++)
1335 seg_diff_mask |= 1 << permu_seg[i];
1336 }
1337 dprintk("nbseg_diff = %X (%d)", seg_diff_mask, seg_diff_mask);
1338
1339 state->differential_constellation = (seg_diff_mask != 0);
Olivier Grenie4c70e072011-01-03 15:33:37 -03001340 dib8000_set_diversity_in(state->fe[0], state->diversity_onoff);
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001341
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001342 if (state->fe[0]->dtv_property_cache.isdbt_sb_mode == 1) {
1343 if (state->fe[0]->dtv_property_cache.isdbt_partial_reception == 1)
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001344 seg_mask13 = 0x00E0;
1345 else // 1-segment
1346 seg_mask13 = 0x0040;
1347 } else
1348 seg_mask13 = 0x1fff;
1349
1350 // WRITE: Mode & Diff mask
1351 dib8000_write_word(state, 0, (mode << 13) | seg_diff_mask);
1352
Olivier Grenie4c70e072011-01-03 15:33:37 -03001353 if ((seg_diff_mask) || (state->fe[0]->dtv_property_cache.isdbt_sb_mode))
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001354 dib8000_write_word(state, 268, (dib8000_read_word(state, 268) & 0xF9FF) | 0x0200);
1355 else
1356 dib8000_write_word(state, 268, (2 << 9) | 39); //init value
1357
1358 // ---- SMALL ----
1359 // P_small_seg_diff
1360 dib8000_write_word(state, 352, seg_diff_mask); // ADDR 352
1361
1362 dib8000_write_word(state, 353, seg_mask13); // ADDR 353
1363
Olivier Grenie4c70e072011-01-03 15:33:37 -03001364/* // P_small_narrow_band=0, P_small_last_seg=13, P_small_offset_num_car=5 */
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001365
1366 // ---- SMALL ----
Olivier Grenie4c70e072011-01-03 15:33:37 -03001367 if (state->fe[0]->dtv_property_cache.isdbt_sb_mode == 1) {
1368 switch (state->fe[0]->dtv_property_cache.transmission_mode) {
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001369 case TRANSMISSION_MODE_2K:
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001370 if (state->fe[0]->dtv_property_cache.isdbt_partial_reception == 0) {
1371 if (state->fe[0]->dtv_property_cache.layer[0].modulation == DQPSK)
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001372 ncoeff = coeff_2k_sb_1seg_dqpsk;
1373 else // QPSK or QAM
1374 ncoeff = coeff_2k_sb_1seg;
1375 } else { // 3-segments
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001376 if (state->fe[0]->dtv_property_cache.layer[0].modulation == DQPSK) {
1377 if (state->fe[0]->dtv_property_cache.layer[1].modulation == DQPSK)
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001378 ncoeff = coeff_2k_sb_3seg_0dqpsk_1dqpsk;
1379 else // QPSK or QAM on external segments
1380 ncoeff = coeff_2k_sb_3seg_0dqpsk;
1381 } else { // QPSK or QAM on central segment
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001382 if (state->fe[0]->dtv_property_cache.layer[1].modulation == DQPSK)
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001383 ncoeff = coeff_2k_sb_3seg_1dqpsk;
1384 else // QPSK or QAM on external segments
1385 ncoeff = coeff_2k_sb_3seg;
1386 }
1387 }
1388 break;
1389
1390 case TRANSMISSION_MODE_4K:
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001391 if (state->fe[0]->dtv_property_cache.isdbt_partial_reception == 0) {
1392 if (state->fe[0]->dtv_property_cache.layer[0].modulation == DQPSK)
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001393 ncoeff = coeff_4k_sb_1seg_dqpsk;
1394 else // QPSK or QAM
1395 ncoeff = coeff_4k_sb_1seg;
1396 } else { // 3-segments
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001397 if (state->fe[0]->dtv_property_cache.layer[0].modulation == DQPSK) {
1398 if (state->fe[0]->dtv_property_cache.layer[1].modulation == DQPSK) {
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001399 ncoeff = coeff_4k_sb_3seg_0dqpsk_1dqpsk;
1400 } else { // QPSK or QAM on external segments
1401 ncoeff = coeff_4k_sb_3seg_0dqpsk;
1402 }
1403 } else { // QPSK or QAM on central segment
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001404 if (state->fe[0]->dtv_property_cache.layer[1].modulation == DQPSK) {
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001405 ncoeff = coeff_4k_sb_3seg_1dqpsk;
1406 } else // QPSK or QAM on external segments
1407 ncoeff = coeff_4k_sb_3seg;
1408 }
1409 }
1410 break;
1411
1412 case TRANSMISSION_MODE_AUTO:
1413 case TRANSMISSION_MODE_8K:
1414 default:
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001415 if (state->fe[0]->dtv_property_cache.isdbt_partial_reception == 0) {
1416 if (state->fe[0]->dtv_property_cache.layer[0].modulation == DQPSK)
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001417 ncoeff = coeff_8k_sb_1seg_dqpsk;
1418 else // QPSK or QAM
1419 ncoeff = coeff_8k_sb_1seg;
1420 } else { // 3-segments
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001421 if (state->fe[0]->dtv_property_cache.layer[0].modulation == DQPSK) {
1422 if (state->fe[0]->dtv_property_cache.layer[1].modulation == DQPSK) {
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001423 ncoeff = coeff_8k_sb_3seg_0dqpsk_1dqpsk;
1424 } else { // QPSK or QAM on external segments
1425 ncoeff = coeff_8k_sb_3seg_0dqpsk;
1426 }
1427 } else { // QPSK or QAM on central segment
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001428 if (state->fe[0]->dtv_property_cache.layer[1].modulation == DQPSK) {
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001429 ncoeff = coeff_8k_sb_3seg_1dqpsk;
1430 } else // QPSK or QAM on external segments
1431 ncoeff = coeff_8k_sb_3seg;
1432 }
1433 }
1434 break;
1435 }
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001436 for (i = 0; i < 8; i++)
1437 dib8000_write_word(state, 343 + i, ncoeff[i]);
Márton Németh6e8fdbd2009-11-22 18:52:37 -03001438 }
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001439
1440 // P_small_coef_ext_enable=ISDB-Tsb, P_small_narrow_band=ISDB-Tsb, P_small_last_seg=13, P_small_offset_num_car=5
1441 dib8000_write_word(state, 351,
Olivier Grenie4c70e072011-01-03 15:33:37 -03001442 (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 -03001443
1444 // ---- COFF ----
1445 // Carloff, the most robust
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001446 if (state->fe[0]->dtv_property_cache.isdbt_sb_mode == 1) {
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001447
1448 // P_coff_cpil_alpha=4, P_coff_inh=0, P_coff_cpil_winlen=64
1449 // 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
1450 dib8000_write_word(state, 187,
Olivier Grenie4c70e072011-01-03 15:33:37 -03001451 (4 << 12) | (0 << 11) | (63 << 5) | (0x3 << 3) | ((~state->fe[0]->dtv_property_cache.isdbt_partial_reception & 1) << 2)
1452 | 0x3);
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001453
Olivier Grenie4c70e072011-01-03 15:33:37 -03001454/* // P_small_coef_ext_enable = 1 */
1455/* dib8000_write_word(state, 351, dib8000_read_word(state, 351) | 0x200); */
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001456
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001457 if (state->fe[0]->dtv_property_cache.isdbt_partial_reception == 0) {
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001458
1459 // 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)
1460 if (mode == 3)
1461 dib8000_write_word(state, 180, 0x1fcf | ((mode - 1) << 14));
1462 else
1463 dib8000_write_word(state, 180, 0x0fcf | ((mode - 1) << 14));
1464 // P_ctrl_corm_thres4pre_freq_inh=1,P_ctrl_pre_freq_mode_sat=1,
1465 // P_ctrl_pre_freq_inh=0, P_ctrl_pre_freq_step = 5, P_pre_freq_win_len=4
1466 dib8000_write_word(state, 338, (1 << 12) | (1 << 10) | (0 << 9) | (5 << 5) | 4);
1467 // P_ctrl_pre_freq_win_len=16, P_ctrl_pre_freq_thres_lockin=8
1468 dib8000_write_word(state, 340, (16 << 6) | (8 << 0));
1469 // P_ctrl_pre_freq_thres_lockout=6, P_small_use_tmcc/ac/cp=1
1470 dib8000_write_word(state, 341, (6 << 3) | (1 << 2) | (1 << 1) | (1 << 0));
1471
1472 // P_coff_corthres_8k, 4k, 2k and P_coff_cpilthres_8k, 4k, 2k
1473 dib8000_write_word(state, 181, 300);
1474 dib8000_write_word(state, 182, 150);
1475 dib8000_write_word(state, 183, 80);
1476 dib8000_write_word(state, 184, 300);
1477 dib8000_write_word(state, 185, 150);
1478 dib8000_write_word(state, 186, 80);
1479 } else { // Sound Broadcasting mode 3 seg
1480 // 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 -03001481 /* if (mode == 3) */
1482 /* dib8000_write_word(state, 180, 0x2fca | ((0) << 14)); */
1483 /* else */
1484 /* dib8000_write_word(state, 180, 0x2fca | ((1) << 14)); */
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001485 dib8000_write_word(state, 180, 0x1fcf | (1 << 14));
1486
1487 // P_ctrl_corm_thres4pre_freq_inh = 1, P_ctrl_pre_freq_mode_sat=1,
1488 // P_ctrl_pre_freq_inh=0, P_ctrl_pre_freq_step = 4, P_pre_freq_win_len=4
1489 dib8000_write_word(state, 338, (1 << 12) | (1 << 10) | (0 << 9) | (4 << 5) | 4);
1490 // P_ctrl_pre_freq_win_len=16, P_ctrl_pre_freq_thres_lockin=8
1491 dib8000_write_word(state, 340, (16 << 6) | (8 << 0));
1492 //P_ctrl_pre_freq_thres_lockout=6, P_small_use_tmcc/ac/cp=1
1493 dib8000_write_word(state, 341, (6 << 3) | (1 << 2) | (1 << 1) | (1 << 0));
1494
1495 // P_coff_corthres_8k, 4k, 2k and P_coff_cpilthres_8k, 4k, 2k
1496 dib8000_write_word(state, 181, 350);
1497 dib8000_write_word(state, 182, 300);
1498 dib8000_write_word(state, 183, 250);
1499 dib8000_write_word(state, 184, 350);
1500 dib8000_write_word(state, 185, 300);
1501 dib8000_write_word(state, 186, 250);
1502 }
1503
1504 } else if (state->isdbt_cfg_loaded == 0) { // if not Sound Broadcasting mode : put default values for 13 segments
1505 dib8000_write_word(state, 180, (16 << 6) | 9);
1506 dib8000_write_word(state, 187, (4 << 12) | (8 << 5) | 0x2);
1507 coff_pow = 0x2800;
1508 for (i = 0; i < 6; i++)
1509 dib8000_write_word(state, 181 + i, coff_pow);
1510
1511 // P_ctrl_corm_thres4pre_freq_inh=1, P_ctrl_pre_freq_mode_sat=1,
1512 // 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
1513 dib8000_write_word(state, 338, (1 << 12) | (1 << 10) | (0 << 9) | (3 << 5) | 1);
1514
1515 // P_ctrl_pre_freq_win_len=8, P_ctrl_pre_freq_thres_lockin=6
1516 dib8000_write_word(state, 340, (8 << 6) | (6 << 0));
1517 // P_ctrl_pre_freq_thres_lockout=4, P_small_use_tmcc/ac/cp=1
1518 dib8000_write_word(state, 341, (4 << 3) | (1 << 2) | (1 << 1) | (1 << 0));
1519 }
1520 // ---- FFT ----
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001521 if (state->fe[0]->dtv_property_cache.isdbt_sb_mode == 1 && state->fe[0]->dtv_property_cache.isdbt_partial_reception == 0)
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001522 dib8000_write_word(state, 178, 64); // P_fft_powrange=64
1523 else
1524 dib8000_write_word(state, 178, 32); // P_fft_powrange=32
1525
1526 /* make the cpil_coff_lock more robust but slower p_coff_winlen
1527 * 6bits; p_coff_thres_lock 6bits (for coff lock if needed)
1528 */
1529 /* if ( ( nbseg_diff>0)&&(nbseg_diff<13))
Olivier Grenie4c70e072011-01-03 15:33:37 -03001530 dib8000_write_word(state, 187, (dib8000_read_word(state, 187) & 0xfffb) | (1 << 3)); */
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001531
1532 dib8000_write_word(state, 189, ~seg_mask13 | seg_diff_mask); /* P_lmod4_seg_inh */
1533 dib8000_write_word(state, 192, ~seg_mask13 | seg_diff_mask); /* P_pha3_seg_inh */
1534 dib8000_write_word(state, 225, ~seg_mask13 | seg_diff_mask); /* P_tac_seg_inh */
Olivier Grenie4c70e072011-01-03 15:33:37 -03001535 if ((!state->fe[0]->dtv_property_cache.isdbt_sb_mode) && (state->cfg.pll->ifreq == 0))
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001536 dib8000_write_word(state, 266, ~seg_mask13 | seg_diff_mask | 0x40); /* P_equal_noise_seg_inh */
1537 else
1538 dib8000_write_word(state, 266, ~seg_mask13 | seg_diff_mask); /* P_equal_noise_seg_inh */
1539 dib8000_write_word(state, 287, ~seg_mask13 | 0x1000); /* P_tmcc_seg_inh */
1540 //dib8000_write_word(state, 288, ~seg_mask13 | seg_diff_mask); /* P_tmcc_seg_eq_inh */
1541 if (!autosearching)
1542 dib8000_write_word(state, 288, (~seg_mask13 | seg_diff_mask) & 0x1fff); /* P_tmcc_seg_eq_inh */
1543 else
1544 dib8000_write_word(state, 288, 0x1fff); //disable equalisation of the tmcc when autosearch to be able to find the DQPSK channels.
1545 dprintk("287 = %X (%d)", ~seg_mask13 | 0x1000, ~seg_mask13 | 0x1000);
1546
1547 dib8000_write_word(state, 211, seg_mask13 & (~seg_diff_mask)); /* P_des_seg_enabled */
1548
1549 /* offset loop parameters */
Olivier Grenie4c70e072011-01-03 15:33:37 -03001550 if (state->fe[0]->dtv_property_cache.isdbt_sb_mode == 1) {
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001551 if (state->fe[0]->dtv_property_cache.isdbt_partial_reception == 0)
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001552 /* P_timf_alpha = (11-P_mode), P_corm_alpha=6, P_corm_thres=0x80 */
1553 dib8000_write_word(state, 32, ((11 - mode) << 12) | (6 << 8) | 0x40);
1554
1555 else // Sound Broadcasting mode 3 seg
1556 /* P_timf_alpha = (10-P_mode), P_corm_alpha=6, P_corm_thres=0x80 */
1557 dib8000_write_word(state, 32, ((10 - mode) << 12) | (6 << 8) | 0x60);
1558 } else
1559 // TODO in 13 seg, timf_alpha can always be the same or not ?
1560 /* P_timf_alpha = (9-P_mode, P_corm_alpha=6, P_corm_thres=0x80 */
1561 dib8000_write_word(state, 32, ((9 - mode) << 12) | (6 << 8) | 0x80);
1562
Olivier Grenie4c70e072011-01-03 15:33:37 -03001563 if (state->fe[0]->dtv_property_cache.isdbt_sb_mode == 1) {
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001564 if (state->fe[0]->dtv_property_cache.isdbt_partial_reception == 0)
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001565 /* P_ctrl_pha_off_max=3 P_ctrl_sfreq_inh =0 P_ctrl_sfreq_step = (11-P_mode) */
1566 dib8000_write_word(state, 37, (3 << 5) | (0 << 4) | (10 - mode));
1567
1568 else // Sound Broadcasting mode 3 seg
1569 /* P_ctrl_pha_off_max=3 P_ctrl_sfreq_inh =0 P_ctrl_sfreq_step = (10-P_mode) */
1570 dib8000_write_word(state, 37, (3 << 5) | (0 << 4) | (9 - mode));
1571 } else
1572 /* P_ctrl_pha_off_max=3 P_ctrl_sfreq_inh =0 P_ctrl_sfreq_step = 9 */
1573 dib8000_write_word(state, 37, (3 << 5) | (0 << 4) | (8 - mode));
1574
1575 /* P_dvsy_sync_wait - reuse mode */
Olivier Grenie4c70e072011-01-03 15:33:37 -03001576 switch (state->fe[0]->dtv_property_cache.transmission_mode) {
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001577 case TRANSMISSION_MODE_8K:
1578 mode = 256;
1579 break;
1580 case TRANSMISSION_MODE_4K:
1581 mode = 128;
1582 break;
1583 default:
1584 case TRANSMISSION_MODE_2K:
1585 mode = 64;
1586 break;
1587 }
1588 if (state->cfg.diversity_delay == 0)
1589 mode = (mode * (1 << (guard)) * 3) / 2 + 48; // add 50% SFN margin + compensate for one DVSY-fifo
1590 else
1591 mode = (mode * (1 << (guard)) * 3) / 2 + state->cfg.diversity_delay; // add 50% SFN margin + compensate for DVSY-fifo
1592 mode <<= 4;
1593 dib8000_write_word(state, 273, (dib8000_read_word(state, 273) & 0x000f) | mode);
1594
1595 /* channel estimation fine configuration */
1596 switch (max_constellation) {
1597 case QAM_64:
1598 ana_gain = 0x7; // -1 : avoid def_est saturation when ADC target is -16dB
1599 coeff[0] = 0x0148; /* P_adp_regul_cnt 0.04 */
1600 coeff[1] = 0xfff0; /* P_adp_noise_cnt -0.002 */
1601 coeff[2] = 0x00a4; /* P_adp_regul_ext 0.02 */
1602 coeff[3] = 0xfff8; /* P_adp_noise_ext -0.001 */
1603 //if (!state->cfg.hostbus_diversity) //if diversity, we should prehaps use the configuration of the max_constallation -1
1604 break;
1605 case QAM_16:
1606 ana_gain = 0x7; // -1 : avoid def_est saturation when ADC target is -16dB
1607 coeff[0] = 0x023d; /* P_adp_regul_cnt 0.07 */
1608 coeff[1] = 0xffdf; /* P_adp_noise_cnt -0.004 */
1609 coeff[2] = 0x00a4; /* P_adp_regul_ext 0.02 */
1610 coeff[3] = 0xfff0; /* P_adp_noise_ext -0.002 */
1611 //if (!((state->cfg.hostbus_diversity) && (max_constellation == QAM_16)))
1612 break;
1613 default:
1614 ana_gain = 0; // 0 : goes along with ADC target at -22dB to keep good mobile performance and lock at sensitivity level
1615 coeff[0] = 0x099a; /* P_adp_regul_cnt 0.3 */
1616 coeff[1] = 0xffae; /* P_adp_noise_cnt -0.01 */
1617 coeff[2] = 0x0333; /* P_adp_regul_ext 0.1 */
1618 coeff[3] = 0xfff8; /* P_adp_noise_ext -0.002 */
1619 break;
1620 }
1621 for (mode = 0; mode < 4; mode++)
1622 dib8000_write_word(state, 215 + mode, coeff[mode]);
1623
1624 // update ana_gain depending on max constellation
1625 dib8000_write_word(state, 116, ana_gain);
1626 // update ADC target depending on ana_gain
1627 if (ana_gain) { // set -16dB ADC target for ana_gain=-1
1628 for (i = 0; i < 10; i++)
1629 dib8000_write_word(state, 80 + i, adc_target_16dB[i]);
1630 } else { // set -22dB ADC target for ana_gain=0
1631 for (i = 0; i < 10; i++)
1632 dib8000_write_word(state, 80 + i, adc_target_16dB[i] - 355);
1633 }
1634
1635 // ---- ANA_FE ----
Olivier Grenie4c70e072011-01-03 15:33:37 -03001636 if (state->fe[0]->dtv_property_cache.isdbt_sb_mode) {
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001637 if (state->fe[0]->dtv_property_cache.isdbt_partial_reception == 1)
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001638 ana_fe = ana_fe_coeff_3seg;
1639 else // 1-segment
1640 ana_fe = ana_fe_coeff_1seg;
1641 } else
1642 ana_fe = ana_fe_coeff_13seg;
1643
Olivier Grenie4c70e072011-01-03 15:33:37 -03001644 if (state->fe[0]->dtv_property_cache.isdbt_sb_mode == 1 || state->isdbt_cfg_loaded == 0)
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001645 for (mode = 0; mode < 24; mode++)
1646 dib8000_write_word(state, 117 + mode, ana_fe[mode]);
1647
1648 // ---- CHAN_BLK ----
1649 for (i = 0; i < 13; i++) {
1650 if ((((~seg_diff_mask) >> i) & 1) == 1) {
1651 P_cfr_left_edge += (1 << i) * ((i == 0) || ((((seg_mask13 & (~seg_diff_mask)) >> (i - 1)) & 1) == 0));
1652 P_cfr_right_edge += (1 << i) * ((i == 12) || ((((seg_mask13 & (~seg_diff_mask)) >> (i + 1)) & 1) == 0));
1653 }
1654 }
1655 dib8000_write_word(state, 222, P_cfr_left_edge); // P_cfr_left_edge
1656 dib8000_write_word(state, 223, P_cfr_right_edge); // P_cfr_right_edge
1657 // "P_cspu_left_edge" not used => do not care
1658 // "P_cspu_right_edge" not used => do not care
1659
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001660 if (state->fe[0]->dtv_property_cache.isdbt_sb_mode == 1) {
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001661 dib8000_write_word(state, 228, 1); // P_2d_mode_byp=1
1662 dib8000_write_word(state, 205, dib8000_read_word(state, 205) & 0xfff0); // P_cspu_win_cut = 0
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001663 if (state->fe[0]->dtv_property_cache.isdbt_partial_reception == 0
Olivier Grenie4c70e072011-01-03 15:33:37 -03001664 && state->fe[0]->dtv_property_cache.transmission_mode == TRANSMISSION_MODE_2K) {
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001665 //dib8000_write_word(state, 219, dib8000_read_word(state, 219) & 0xfffe); // P_adp_pass = 0
1666 dib8000_write_word(state, 265, 15); // P_equal_noise_sel = 15
1667 }
1668 } else if (state->isdbt_cfg_loaded == 0) {
1669 dib8000_write_word(state, 228, 0); // default value
1670 dib8000_write_word(state, 265, 31); // default value
1671 dib8000_write_word(state, 205, 0x200f); // init value
1672 }
1673 // ---- TMCC ----
1674 for (i = 0; i < 3; i++)
1675 tmcc_pow +=
Olivier Grenie4c70e072011-01-03 15:33:37 -03001676 (((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 -03001677 // Quantif of "P_tmcc_dec_thres_?k" is (0, 5+mode, 9);
1678 // Threshold is set at 1/4 of max power.
1679 tmcc_pow *= (1 << (9 - 2));
1680
1681 dib8000_write_word(state, 290, tmcc_pow); // P_tmcc_dec_thres_2k
1682 dib8000_write_word(state, 291, tmcc_pow); // P_tmcc_dec_thres_4k
1683 dib8000_write_word(state, 292, tmcc_pow); // P_tmcc_dec_thres_8k
1684 //dib8000_write_word(state, 287, (1 << 13) | 0x1000 );
1685 // ---- PHA3 ----
1686
1687 if (state->isdbt_cfg_loaded == 0)
1688 dib8000_write_word(state, 250, 3285); /*p_2d_hspeed_thr0 */
1689
Olivier Grenie4c70e072011-01-03 15:33:37 -03001690 if (state->fe[0]->dtv_property_cache.isdbt_sb_mode == 1)
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001691 state->isdbt_cfg_loaded = 0;
1692 else
1693 state->isdbt_cfg_loaded = 1;
1694
1695}
1696
1697static int dib8000_autosearch_start(struct dvb_frontend *fe)
1698{
1699 u8 factor;
1700 u32 value;
1701 struct dib8000_state *state = fe->demodulator_priv;
1702
1703 int slist = 0;
1704
Olivier Grenie4c70e072011-01-03 15:33:37 -03001705 state->fe[0]->dtv_property_cache.inversion = 0;
1706 if (!state->fe[0]->dtv_property_cache.isdbt_sb_mode)
1707 state->fe[0]->dtv_property_cache.layer[0].segment_count = 13;
1708 state->fe[0]->dtv_property_cache.layer[0].modulation = QAM_64;
1709 state->fe[0]->dtv_property_cache.layer[0].fec = FEC_2_3;
1710 state->fe[0]->dtv_property_cache.layer[0].interleaving = 0;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001711
1712 //choose the right list, in sb, always do everything
Olivier Grenie4c70e072011-01-03 15:33:37 -03001713 if (state->fe[0]->dtv_property_cache.isdbt_sb_mode) {
1714 state->fe[0]->dtv_property_cache.transmission_mode = TRANSMISSION_MODE_8K;
1715 state->fe[0]->dtv_property_cache.guard_interval = GUARD_INTERVAL_1_8;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001716 slist = 7;
1717 dib8000_write_word(state, 0, (dib8000_read_word(state, 0) & 0x9fff) | (1 << 13));
1718 } else {
Olivier Grenie4c70e072011-01-03 15:33:37 -03001719 if (state->fe[0]->dtv_property_cache.guard_interval == GUARD_INTERVAL_AUTO) {
1720 if (state->fe[0]->dtv_property_cache.transmission_mode == TRANSMISSION_MODE_AUTO) {
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001721 slist = 7;
1722 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 -03001723 } else
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001724 slist = 3;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001725 } else {
Olivier Grenie4c70e072011-01-03 15:33:37 -03001726 if (state->fe[0]->dtv_property_cache.transmission_mode == TRANSMISSION_MODE_AUTO) {
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001727 slist = 2;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001728 dib8000_write_word(state, 0, (dib8000_read_word(state, 0) & 0x9fff) | (1 << 13)); // P_mode = 1
Patrick Boettcher78f3bc62009-08-17 12:53:51 -03001729 } else
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001730 slist = 0;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001731 }
1732
Olivier Grenie4c70e072011-01-03 15:33:37 -03001733 if (state->fe[0]->dtv_property_cache.transmission_mode == TRANSMISSION_MODE_AUTO)
1734 state->fe[0]->dtv_property_cache.transmission_mode = TRANSMISSION_MODE_8K;
1735 if (state->fe[0]->dtv_property_cache.guard_interval == GUARD_INTERVAL_AUTO)
1736 state->fe[0]->dtv_property_cache.guard_interval = GUARD_INTERVAL_1_8;
Patrick Boettcher78f3bc62009-08-17 12:53:51 -03001737
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001738 dprintk("using list for autosearch : %d", slist);
1739 dib8000_set_channel(state, (unsigned char)slist, 1);
1740 //dib8000_write_word(state, 0, (dib8000_read_word(state, 0) & 0x9fff) | (1 << 13)); // P_mode = 1
1741
1742 factor = 1;
1743
1744 //set lock_mask values
1745 dib8000_write_word(state, 6, 0x4);
1746 dib8000_write_word(state, 7, 0x8);
1747 dib8000_write_word(state, 8, 0x1000);
1748
1749 //set lock_mask wait time values
1750 value = 50 * state->cfg.pll->internal * factor;
1751 dib8000_write_word(state, 11, (u16) ((value >> 16) & 0xffff)); // lock0 wait time
1752 dib8000_write_word(state, 12, (u16) (value & 0xffff)); // lock0 wait time
1753 value = 100 * state->cfg.pll->internal * factor;
1754 dib8000_write_word(state, 13, (u16) ((value >> 16) & 0xffff)); // lock1 wait time
1755 dib8000_write_word(state, 14, (u16) (value & 0xffff)); // lock1 wait time
1756 value = 1000 * state->cfg.pll->internal * factor;
1757 dib8000_write_word(state, 15, (u16) ((value >> 16) & 0xffff)); // lock2 wait time
1758 dib8000_write_word(state, 16, (u16) (value & 0xffff)); // lock2 wait time
1759
1760 value = dib8000_read_word(state, 0);
1761 dib8000_write_word(state, 0, (u16) ((1 << 15) | value));
1762 dib8000_read_word(state, 1284); // reset the INT. n_irq_pending
1763 dib8000_write_word(state, 0, (u16) value);
Patrick Boettcher78f3bc62009-08-17 12:53:51 -03001764
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001765 }
1766
1767 return 0;
1768}
1769
1770static int dib8000_autosearch_irq(struct dvb_frontend *fe)
1771{
1772 struct dib8000_state *state = fe->demodulator_priv;
1773 u16 irq_pending = dib8000_read_word(state, 1284);
1774
1775 if (irq_pending & 0x1) { // failed
1776 dprintk("dib8000_autosearch_irq failed");
1777 return 1;
1778 }
1779
1780 if (irq_pending & 0x2) { // succeeded
1781 dprintk("dib8000_autosearch_irq succeeded");
1782 return 2;
1783 }
1784
1785 return 0; // still pending
1786}
1787
1788static int dib8000_tune(struct dvb_frontend *fe)
1789{
1790 struct dib8000_state *state = fe->demodulator_priv;
1791 int ret = 0;
1792 u16 value, mode = fft_to_mode(state);
1793
1794 // we are already tuned - just resuming from suspend
1795 if (state == NULL)
1796 return -EINVAL;
1797
Olivier Grenie4c70e072011-01-03 15:33:37 -03001798 dib8000_set_bandwidth(fe, state->fe[0]->dtv_property_cache.bandwidth_hz / 1000);
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001799 dib8000_set_channel(state, 0, 0);
1800
1801 // restart demod
1802 ret |= dib8000_write_word(state, 770, 0x4000);
1803 ret |= dib8000_write_word(state, 770, 0x0000);
1804 msleep(45);
1805
1806 /* P_ctrl_inh_cor=0, P_ctrl_alpha_cor=4, P_ctrl_inh_isi=0, P_ctrl_alpha_isi=3 */
1807 /* ret |= dib8000_write_word(state, 29, (0 << 9) | (4 << 5) | (0 << 4) | (3 << 0) ); workaround inh_isi stays at 1 */
1808
1809 // never achieved a lock before - wait for timfreq to update
1810 if (state->timf == 0) {
Olivier Grenie4c70e072011-01-03 15:33:37 -03001811 if (state->fe[0]->dtv_property_cache.isdbt_sb_mode == 1) {
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001812 if (state->fe[0]->dtv_property_cache.isdbt_partial_reception == 0)
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001813 msleep(300);
1814 else // Sound Broadcasting mode 3 seg
1815 msleep(500);
1816 } else // 13 seg
1817 msleep(200);
1818 }
Olivier Grenie4c70e072011-01-03 15:33:37 -03001819 if (state->fe[0]->dtv_property_cache.isdbt_sb_mode == 1) {
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001820 if (state->fe[0]->dtv_property_cache.isdbt_partial_reception == 0) {
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001821
1822 /* P_timf_alpha = (13-P_mode) , P_corm_alpha=6, P_corm_thres=0x40 alpha to check on board */
1823 dib8000_write_word(state, 32, ((13 - mode) << 12) | (6 << 8) | 0x40);
1824 //dib8000_write_word(state, 32, (8 << 12) | (6 << 8) | 0x80);
1825
1826 /* P_ctrl_sfreq_step= (12-P_mode) P_ctrl_sfreq_inh =0 P_ctrl_pha_off_max */
1827 ret |= dib8000_write_word(state, 37, (12 - mode) | ((5 + mode) << 5));
1828
1829 } else { // Sound Broadcasting mode 3 seg
1830
1831 /* P_timf_alpha = (12-P_mode) , P_corm_alpha=6, P_corm_thres=0x60 alpha to check on board */
1832 dib8000_write_word(state, 32, ((12 - mode) << 12) | (6 << 8) | 0x60);
1833
1834 ret |= dib8000_write_word(state, 37, (11 - mode) | ((5 + mode) << 5));
1835 }
1836
1837 } else { // 13 seg
1838 /* P_timf_alpha = 8 , P_corm_alpha=6, P_corm_thres=0x80 alpha to check on board */
1839 dib8000_write_word(state, 32, ((11 - mode) << 12) | (6 << 8) | 0x80);
1840
1841 ret |= dib8000_write_word(state, 37, (10 - mode) | ((5 + mode) << 5));
1842
1843 }
1844
1845 // we achieved a coff_cpil_lock - it's time to update the timf
1846 if ((dib8000_read_word(state, 568) >> 11) & 0x1)
1847 dib8000_update_timf(state);
1848
1849 //now that tune is finished, lock0 should lock on fec_mpeg to output this lock on MP_LOCK. It's changed in autosearch start
1850 dib8000_write_word(state, 6, 0x200);
1851
1852 if (state->revision == 0x8002) {
1853 value = dib8000_read_word(state, 903);
1854 dib8000_write_word(state, 903, value & ~(1 << 3));
1855 msleep(1);
1856 dib8000_write_word(state, 903, value | (1 << 3));
1857 }
1858
1859 return ret;
1860}
1861
1862static int dib8000_wakeup(struct dvb_frontend *fe)
1863{
1864 struct dib8000_state *state = fe->demodulator_priv;
Olivier Grenie4c70e072011-01-03 15:33:37 -03001865 u8 index_frontend;
1866 int ret;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001867
1868 dib8000_set_power_mode(state, DIB8000M_POWER_ALL);
1869 dib8000_set_adc_state(state, DIBX000_ADC_ON);
1870 if (dib8000_set_adc_state(state, DIBX000_SLOW_ADC_ON) != 0)
1871 dprintk("could not start Slow ADC");
1872
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001873 for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
Olivier Grenie4c70e072011-01-03 15:33:37 -03001874 ret = state->fe[index_frontend]->ops.init(state->fe[index_frontend]);
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001875 if (ret < 0)
Olivier Grenie4c70e072011-01-03 15:33:37 -03001876 return ret;
1877 }
1878
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001879 return 0;
1880}
1881
1882static int dib8000_sleep(struct dvb_frontend *fe)
1883{
Olivier Grenie4c70e072011-01-03 15:33:37 -03001884 struct dib8000_state *state = fe->demodulator_priv;
1885 u8 index_frontend;
1886 int ret;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001887
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001888 for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
Olivier Grenie4c70e072011-01-03 15:33:37 -03001889 ret = state->fe[index_frontend]->ops.sleep(state->fe[index_frontend]);
1890 if (ret < 0)
1891 return ret;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001892 }
Olivier Grenie4c70e072011-01-03 15:33:37 -03001893
1894 dib8000_set_output_mode(fe, OUTMODE_HIGH_Z);
1895 dib8000_set_power_mode(state, DIB8000M_POWER_INTERFACE_ONLY);
1896 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 -03001897}
1898
Olivier Grenie9c783032009-12-07 07:49:40 -03001899enum frontend_tune_state dib8000_get_tune_state(struct dvb_frontend *fe)
Olivier Grenie03245a52009-12-04 13:27:57 -03001900{
1901 struct dib8000_state *state = fe->demodulator_priv;
1902 return state->tune_state;
1903}
1904EXPORT_SYMBOL(dib8000_get_tune_state);
1905
Olivier Grenie9c783032009-12-07 07:49:40 -03001906int dib8000_set_tune_state(struct dvb_frontend *fe, enum frontend_tune_state tune_state)
Olivier Grenie03245a52009-12-04 13:27:57 -03001907{
1908 struct dib8000_state *state = fe->demodulator_priv;
1909 state->tune_state = tune_state;
1910 return 0;
1911}
1912EXPORT_SYMBOL(dib8000_set_tune_state);
1913
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001914static int dib8000_get_frontend(struct dvb_frontend *fe, struct dvb_frontend_parameters *fep)
1915{
1916 struct dib8000_state *state = fe->demodulator_priv;
1917 u16 i, val = 0;
Olivier Grenie4c70e072011-01-03 15:33:37 -03001918 fe_status_t stat;
1919 u8 index_frontend, sub_index_frontend;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001920
1921 fe->dtv_property_cache.bandwidth_hz = 6000000;
1922
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001923 for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
Olivier Grenie4c70e072011-01-03 15:33:37 -03001924 state->fe[index_frontend]->ops.read_status(state->fe[index_frontend], &stat);
1925 if (stat&FE_HAS_SYNC) {
1926 dprintk("TMCC lock on the slave%i", index_frontend);
1927 /* synchronize the cache with the other frontends */
1928 state->fe[index_frontend]->ops.get_frontend(state->fe[index_frontend], fep);
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001929 for (sub_index_frontend = 0; (sub_index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[sub_index_frontend] != NULL); sub_index_frontend++) {
Olivier Grenie4c70e072011-01-03 15:33:37 -03001930 if (sub_index_frontend != index_frontend) {
1931 state->fe[sub_index_frontend]->dtv_property_cache.isdbt_sb_mode = state->fe[index_frontend]->dtv_property_cache.isdbt_sb_mode;
1932 state->fe[sub_index_frontend]->dtv_property_cache.inversion = state->fe[index_frontend]->dtv_property_cache.inversion;
1933 state->fe[sub_index_frontend]->dtv_property_cache.transmission_mode = state->fe[index_frontend]->dtv_property_cache.transmission_mode;
1934 state->fe[sub_index_frontend]->dtv_property_cache.guard_interval = state->fe[index_frontend]->dtv_property_cache.guard_interval;
1935 state->fe[sub_index_frontend]->dtv_property_cache.isdbt_partial_reception = state->fe[index_frontend]->dtv_property_cache.isdbt_partial_reception;
1936 for (i = 0; i < 3; i++) {
1937 state->fe[sub_index_frontend]->dtv_property_cache.layer[i].segment_count = state->fe[index_frontend]->dtv_property_cache.layer[i].segment_count;
1938 state->fe[sub_index_frontend]->dtv_property_cache.layer[i].interleaving = state->fe[index_frontend]->dtv_property_cache.layer[i].interleaving;
1939 state->fe[sub_index_frontend]->dtv_property_cache.layer[i].fec = state->fe[index_frontend]->dtv_property_cache.layer[i].fec;
1940 state->fe[sub_index_frontend]->dtv_property_cache.layer[i].modulation = state->fe[index_frontend]->dtv_property_cache.layer[i].modulation;
1941 }
1942 }
1943 }
1944 return 0;
1945 }
1946 }
1947
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001948 fe->dtv_property_cache.isdbt_sb_mode = dib8000_read_word(state, 508) & 0x1;
1949
1950 val = dib8000_read_word(state, 570);
1951 fe->dtv_property_cache.inversion = (val & 0x40) >> 6;
1952 switch ((val & 0x30) >> 4) {
1953 case 1:
1954 fe->dtv_property_cache.transmission_mode = TRANSMISSION_MODE_2K;
1955 break;
1956 case 3:
1957 default:
1958 fe->dtv_property_cache.transmission_mode = TRANSMISSION_MODE_8K;
1959 break;
1960 }
1961
1962 switch (val & 0x3) {
1963 case 0:
1964 fe->dtv_property_cache.guard_interval = GUARD_INTERVAL_1_32;
1965 dprintk("dib8000_get_frontend GI = 1/32 ");
1966 break;
1967 case 1:
1968 fe->dtv_property_cache.guard_interval = GUARD_INTERVAL_1_16;
1969 dprintk("dib8000_get_frontend GI = 1/16 ");
1970 break;
1971 case 2:
1972 dprintk("dib8000_get_frontend GI = 1/8 ");
1973 fe->dtv_property_cache.guard_interval = GUARD_INTERVAL_1_8;
1974 break;
1975 case 3:
1976 dprintk("dib8000_get_frontend GI = 1/4 ");
1977 fe->dtv_property_cache.guard_interval = GUARD_INTERVAL_1_4;
1978 break;
1979 }
1980
1981 val = dib8000_read_word(state, 505);
1982 fe->dtv_property_cache.isdbt_partial_reception = val & 1;
1983 dprintk("dib8000_get_frontend : partial_reception = %d ", fe->dtv_property_cache.isdbt_partial_reception);
1984
1985 for (i = 0; i < 3; i++) {
1986 val = dib8000_read_word(state, 493 + i);
1987 fe->dtv_property_cache.layer[i].segment_count = val & 0x0F;
1988 dprintk("dib8000_get_frontend : Layer %d segments = %d ", i, fe->dtv_property_cache.layer[i].segment_count);
1989
1990 val = dib8000_read_word(state, 499 + i);
1991 fe->dtv_property_cache.layer[i].interleaving = val & 0x3;
1992 dprintk("dib8000_get_frontend : Layer %d time_intlv = %d ", i, fe->dtv_property_cache.layer[i].interleaving);
1993
1994 val = dib8000_read_word(state, 481 + i);
1995 switch (val & 0x7) {
1996 case 1:
1997 fe->dtv_property_cache.layer[i].fec = FEC_1_2;
1998 dprintk("dib8000_get_frontend : Layer %d Code Rate = 1/2 ", i);
1999 break;
2000 case 2:
2001 fe->dtv_property_cache.layer[i].fec = FEC_2_3;
2002 dprintk("dib8000_get_frontend : Layer %d Code Rate = 2/3 ", i);
2003 break;
2004 case 3:
2005 fe->dtv_property_cache.layer[i].fec = FEC_3_4;
2006 dprintk("dib8000_get_frontend : Layer %d Code Rate = 3/4 ", i);
2007 break;
2008 case 5:
2009 fe->dtv_property_cache.layer[i].fec = FEC_5_6;
2010 dprintk("dib8000_get_frontend : Layer %d Code Rate = 5/6 ", i);
2011 break;
2012 default:
2013 fe->dtv_property_cache.layer[i].fec = FEC_7_8;
2014 dprintk("dib8000_get_frontend : Layer %d Code Rate = 7/8 ", i);
2015 break;
2016 }
2017
2018 val = dib8000_read_word(state, 487 + i);
2019 switch (val & 0x3) {
2020 case 0:
2021 dprintk("dib8000_get_frontend : Layer %d DQPSK ", i);
2022 fe->dtv_property_cache.layer[i].modulation = DQPSK;
2023 break;
2024 case 1:
2025 fe->dtv_property_cache.layer[i].modulation = QPSK;
2026 dprintk("dib8000_get_frontend : Layer %d QPSK ", i);
2027 break;
2028 case 2:
2029 fe->dtv_property_cache.layer[i].modulation = QAM_16;
2030 dprintk("dib8000_get_frontend : Layer %d QAM16 ", i);
2031 break;
2032 case 3:
2033 default:
2034 dprintk("dib8000_get_frontend : Layer %d QAM64 ", i);
2035 fe->dtv_property_cache.layer[i].modulation = QAM_64;
2036 break;
2037 }
2038 }
Olivier Grenie4c70e072011-01-03 15:33:37 -03002039
2040 /* synchronize the cache with the other frontends */
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002041 for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
Olivier Grenie4c70e072011-01-03 15:33:37 -03002042 state->fe[index_frontend]->dtv_property_cache.isdbt_sb_mode = fe->dtv_property_cache.isdbt_sb_mode;
2043 state->fe[index_frontend]->dtv_property_cache.inversion = fe->dtv_property_cache.inversion;
2044 state->fe[index_frontend]->dtv_property_cache.transmission_mode = fe->dtv_property_cache.transmission_mode;
2045 state->fe[index_frontend]->dtv_property_cache.guard_interval = fe->dtv_property_cache.guard_interval;
2046 state->fe[index_frontend]->dtv_property_cache.isdbt_partial_reception = fe->dtv_property_cache.isdbt_partial_reception;
2047 for (i = 0; i < 3; i++) {
2048 state->fe[index_frontend]->dtv_property_cache.layer[i].segment_count = fe->dtv_property_cache.layer[i].segment_count;
2049 state->fe[index_frontend]->dtv_property_cache.layer[i].interleaving = fe->dtv_property_cache.layer[i].interleaving;
2050 state->fe[index_frontend]->dtv_property_cache.layer[i].fec = fe->dtv_property_cache.layer[i].fec;
2051 state->fe[index_frontend]->dtv_property_cache.layer[i].modulation = fe->dtv_property_cache.layer[i].modulation;
2052 }
2053 }
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002054 return 0;
2055}
2056
2057static int dib8000_set_frontend(struct dvb_frontend *fe, struct dvb_frontend_parameters *fep)
2058{
2059 struct dib8000_state *state = fe->demodulator_priv;
Olivier Grenie4c70e072011-01-03 15:33:37 -03002060 u8 nbr_pending, exit_condition, index_frontend;
2061 s8 index_frontend_success = -1;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002062 int time, ret;
Olivier Grenie4c70e072011-01-03 15:33:37 -03002063 int time_slave = FE_CALLBACK_TIME_NEVER;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002064
Olivier Grenie4c70e072011-01-03 15:33:37 -03002065 if (state->fe[0]->dtv_property_cache.frequency == 0) {
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002066 dprintk("dib8000: must at least specify frequency ");
2067 return 0;
2068 }
2069
Olivier Grenie4c70e072011-01-03 15:33:37 -03002070 if (state->fe[0]->dtv_property_cache.bandwidth_hz == 0) {
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002071 dprintk("dib8000: no bandwidth specified, set to default ");
Olivier Grenie4c70e072011-01-03 15:33:37 -03002072 state->fe[0]->dtv_property_cache.bandwidth_hz = 6000000;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002073 }
2074
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002075 for (index_frontend = 0; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
Olivier Grenie4c70e072011-01-03 15:33:37 -03002076 /* synchronization of the cache */
2077 state->fe[index_frontend]->dtv_property_cache.delivery_system = SYS_ISDBT;
2078 memcpy(&state->fe[index_frontend]->dtv_property_cache, &fe->dtv_property_cache, sizeof(struct dtv_frontend_properties));
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002079
Olivier Grenie4c70e072011-01-03 15:33:37 -03002080 dib8000_set_output_mode(state->fe[index_frontend], OUTMODE_HIGH_Z);
2081 if (state->fe[index_frontend]->ops.tuner_ops.set_params)
2082 state->fe[index_frontend]->ops.tuner_ops.set_params(state->fe[index_frontend], fep);
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002083
Olivier Grenie4c70e072011-01-03 15:33:37 -03002084 dib8000_set_tune_state(state->fe[index_frontend], CT_AGC_START);
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002085 }
2086
Olivier Grenie4c70e072011-01-03 15:33:37 -03002087 /* start up the AGC */
2088 do {
2089 time = dib8000_agc_startup(state->fe[0]);
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002090 for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
Olivier Grenie4c70e072011-01-03 15:33:37 -03002091 time_slave = dib8000_agc_startup(state->fe[index_frontend]);
2092 if (time == FE_CALLBACK_TIME_NEVER)
2093 time = time_slave;
2094 else if ((time_slave != FE_CALLBACK_TIME_NEVER) && (time_slave > time))
2095 time = time_slave;
2096 }
2097 if (time != FE_CALLBACK_TIME_NEVER)
2098 msleep(time / 10);
2099 else
2100 break;
2101 exit_condition = 1;
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002102 for (index_frontend = 0; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
Olivier Grenie4c70e072011-01-03 15:33:37 -03002103 if (dib8000_get_tune_state(state->fe[index_frontend]) != CT_AGC_STOP) {
2104 exit_condition = 0;
2105 break;
2106 }
2107 }
2108 } while (exit_condition == 0);
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002109
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002110 for (index_frontend = 0; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++)
Olivier Grenie4c70e072011-01-03 15:33:37 -03002111 dib8000_set_tune_state(state->fe[index_frontend], CT_DEMOD_START);
2112
2113 if ((state->fe[0]->dtv_property_cache.delivery_system != SYS_ISDBT) ||
2114 (state->fe[0]->dtv_property_cache.inversion == INVERSION_AUTO) ||
2115 (state->fe[0]->dtv_property_cache.transmission_mode == TRANSMISSION_MODE_AUTO) ||
2116 (state->fe[0]->dtv_property_cache.guard_interval == GUARD_INTERVAL_AUTO) ||
2117 (((state->fe[0]->dtv_property_cache.isdbt_layer_enabled & (1 << 0)) != 0) &&
2118 (state->fe[0]->dtv_property_cache.layer[0].segment_count != 0xff) &&
2119 (state->fe[0]->dtv_property_cache.layer[0].segment_count != 0) &&
2120 ((state->fe[0]->dtv_property_cache.layer[0].modulation == QAM_AUTO) ||
2121 (state->fe[0]->dtv_property_cache.layer[0].fec == FEC_AUTO))) ||
2122 (((state->fe[0]->dtv_property_cache.isdbt_layer_enabled & (1 << 1)) != 0) &&
2123 (state->fe[0]->dtv_property_cache.layer[1].segment_count != 0xff) &&
2124 (state->fe[0]->dtv_property_cache.layer[1].segment_count != 0) &&
2125 ((state->fe[0]->dtv_property_cache.layer[1].modulation == QAM_AUTO) ||
2126 (state->fe[0]->dtv_property_cache.layer[1].fec == FEC_AUTO))) ||
2127 (((state->fe[0]->dtv_property_cache.isdbt_layer_enabled & (1 << 2)) != 0) &&
2128 (state->fe[0]->dtv_property_cache.layer[2].segment_count != 0xff) &&
2129 (state->fe[0]->dtv_property_cache.layer[2].segment_count != 0) &&
2130 ((state->fe[0]->dtv_property_cache.layer[2].modulation == QAM_AUTO) ||
2131 (state->fe[0]->dtv_property_cache.layer[2].fec == FEC_AUTO))) ||
2132 (((state->fe[0]->dtv_property_cache.layer[0].segment_count == 0) ||
2133 ((state->fe[0]->dtv_property_cache.isdbt_layer_enabled & (1 << 0)) == 0)) &&
2134 ((state->fe[0]->dtv_property_cache.layer[1].segment_count == 0) ||
2135 ((state->fe[0]->dtv_property_cache.isdbt_layer_enabled & (2 << 0)) == 0)) &&
2136 ((state->fe[0]->dtv_property_cache.layer[2].segment_count == 0) || ((state->fe[0]->dtv_property_cache.isdbt_layer_enabled & (3 << 0)) == 0)))) {
Mauro Carvalho Chehab2c2c4412011-01-16 13:02:52 -02002137 int i = 80000;
2138 u8 found = 0;
2139 u8 tune_failed = 0;
Olivier Grenie4c70e072011-01-03 15:33:37 -03002140
Mauro Carvalho Chehab2c2c4412011-01-16 13:02:52 -02002141 for (index_frontend = 0; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
2142 dib8000_set_bandwidth(state->fe[index_frontend], fe->dtv_property_cache.bandwidth_hz / 1000);
2143 dib8000_autosearch_start(state->fe[index_frontend]);
2144 }
Olivier Grenie4c70e072011-01-03 15:33:37 -03002145
Mauro Carvalho Chehab2c2c4412011-01-16 13:02:52 -02002146 do {
2147 msleep(20);
2148 nbr_pending = 0;
2149 exit_condition = 0; /* 0: tune pending; 1: tune failed; 2:tune success */
2150 for (index_frontend = 0; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
2151 if (((tune_failed >> index_frontend) & 0x1) == 0) {
2152 found = dib8000_autosearch_irq(state->fe[index_frontend]);
2153 switch (found) {
2154 case 0: /* tune pending */
2155 nbr_pending++;
2156 break;
2157 case 2:
2158 dprintk("autosearch succeed on the frontend%i", index_frontend);
2159 exit_condition = 2;
2160 index_frontend_success = index_frontend;
2161 break;
2162 default:
2163 dprintk("unhandled autosearch result");
2164 case 1:
2165 dprintk("autosearch failed for the frontend%i", index_frontend);
2166 break;
2167 }
2168 }
2169 }
Olivier Grenie4c70e072011-01-03 15:33:37 -03002170
Mauro Carvalho Chehab2c2c4412011-01-16 13:02:52 -02002171 /* if all tune are done and no success, exit: tune failed */
2172 if ((nbr_pending == 0) && (exit_condition == 0))
2173 exit_condition = 1;
2174 } while ((exit_condition == 0) && i--);
Olivier Grenie4c70e072011-01-03 15:33:37 -03002175
Mauro Carvalho Chehab2c2c4412011-01-16 13:02:52 -02002176 if (exit_condition == 1) { /* tune failed */
2177 dprintk("tune failed");
2178 return 0;
2179 }
Olivier Grenie4c70e072011-01-03 15:33:37 -03002180
Mauro Carvalho Chehab2c2c4412011-01-16 13:02:52 -02002181 dprintk("tune success on frontend%i", index_frontend_success);
Olivier Grenie4c70e072011-01-03 15:33:37 -03002182
Mauro Carvalho Chehab2c2c4412011-01-16 13:02:52 -02002183 dib8000_get_frontend(fe, fep);
2184 }
Olivier Grenie4c70e072011-01-03 15:33:37 -03002185
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002186 for (index_frontend = 0, ret = 0; (ret >= 0) && (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++)
Olivier Grenie4c70e072011-01-03 15:33:37 -03002187 ret = dib8000_tune(state->fe[index_frontend]);
Olivier Grenie4c70e072011-01-03 15:33:37 -03002188
2189 /* set output mode and diversity input */
2190 dib8000_set_output_mode(state->fe[0], state->cfg.output_mode);
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002191 for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
Olivier Grenie4c70e072011-01-03 15:33:37 -03002192 dib8000_set_output_mode(state->fe[index_frontend], OUTMODE_DIVERSITY);
2193 dib8000_set_diversity_in(state->fe[index_frontend-1], 1);
2194 }
2195
2196 /* turn off the diversity of the last chip */
2197 dib8000_set_diversity_in(state->fe[index_frontend-1], 0);
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002198
2199 return ret;
2200}
2201
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002202static u16 dib8000_read_lock(struct dvb_frontend *fe)
2203{
Olivier Grenie4c70e072011-01-03 15:33:37 -03002204 struct dib8000_state *state = fe->demodulator_priv;
2205
2206 return dib8000_read_word(state, 568);
2207}
2208
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002209static int dib8000_read_status(struct dvb_frontend *fe, fe_status_t * stat)
2210{
2211 struct dib8000_state *state = fe->demodulator_priv;
Olivier Grenie4c70e072011-01-03 15:33:37 -03002212 u16 lock_slave = 0, lock = dib8000_read_word(state, 568);
2213 u8 index_frontend;
2214
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002215 for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++)
Olivier Grenie4c70e072011-01-03 15:33:37 -03002216 lock_slave |= dib8000_read_lock(state->fe[index_frontend]);
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002217
2218 *stat = 0;
2219
Olivier Grenie4c70e072011-01-03 15:33:37 -03002220 if (((lock >> 13) & 1) || ((lock_slave >> 13) & 1))
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002221 *stat |= FE_HAS_SIGNAL;
2222
Olivier Grenie4c70e072011-01-03 15:33:37 -03002223 if (((lock >> 8) & 1) || ((lock_slave >> 8) & 1)) /* Equal */
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002224 *stat |= FE_HAS_CARRIER;
2225
Olivier Grenie4c70e072011-01-03 15:33:37 -03002226 if ((((lock >> 1) & 0xf) == 0xf) || (((lock_slave >> 1) & 0xf) == 0xf)) /* TMCC_SYNC */
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002227 *stat |= FE_HAS_SYNC;
2228
Olivier Grenie4c70e072011-01-03 15:33:37 -03002229 if ((((lock >> 12) & 1) || ((lock_slave >> 12) & 1)) && ((lock >> 5) & 7)) /* FEC MPEG */
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002230 *stat |= FE_HAS_LOCK;
2231
Olivier Grenie4c70e072011-01-03 15:33:37 -03002232 if (((lock >> 12) & 1) || ((lock_slave >> 12) & 1)) {
Olivier Grenie89dfc552009-11-30 06:38:49 -03002233 lock = dib8000_read_word(state, 554); /* Viterbi Layer A */
2234 if (lock & 0x01)
2235 *stat |= FE_HAS_VITERBI;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002236
Olivier Grenie89dfc552009-11-30 06:38:49 -03002237 lock = dib8000_read_word(state, 555); /* Viterbi Layer B */
2238 if (lock & 0x01)
2239 *stat |= FE_HAS_VITERBI;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002240
Olivier Grenie89dfc552009-11-30 06:38:49 -03002241 lock = dib8000_read_word(state, 556); /* Viterbi Layer C */
2242 if (lock & 0x01)
2243 *stat |= FE_HAS_VITERBI;
2244 }
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002245
2246 return 0;
2247}
2248
2249static int dib8000_read_ber(struct dvb_frontend *fe, u32 * ber)
2250{
2251 struct dib8000_state *state = fe->demodulator_priv;
2252 *ber = (dib8000_read_word(state, 560) << 16) | dib8000_read_word(state, 561); // 13 segments
2253 return 0;
2254}
2255
2256static int dib8000_read_unc_blocks(struct dvb_frontend *fe, u32 * unc)
2257{
2258 struct dib8000_state *state = fe->demodulator_priv;
2259 *unc = dib8000_read_word(state, 565); // packet error on 13 seg
2260 return 0;
2261}
2262
2263static int dib8000_read_signal_strength(struct dvb_frontend *fe, u16 * strength)
2264{
2265 struct dib8000_state *state = fe->demodulator_priv;
Olivier Grenie4c70e072011-01-03 15:33:37 -03002266 u8 index_frontend;
2267 u16 val;
2268
2269 *strength = 0;
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002270 for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
Olivier Grenie4c70e072011-01-03 15:33:37 -03002271 state->fe[index_frontend]->ops.read_signal_strength(state->fe[index_frontend], &val);
2272 if (val > 65535 - *strength)
2273 *strength = 65535;
2274 else
2275 *strength += val;
2276 }
2277
2278 val = 65535 - dib8000_read_word(state, 390);
2279 if (val > 65535 - *strength)
2280 *strength = 65535;
2281 else
2282 *strength += val;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002283 return 0;
2284}
2285
Olivier Grenie4c70e072011-01-03 15:33:37 -03002286static u32 dib8000_get_snr(struct dvb_frontend *fe)
2287{
2288 struct dib8000_state *state = fe->demodulator_priv;
2289 u32 n, s, exp;
2290 u16 val;
2291
2292 val = dib8000_read_word(state, 542);
2293 n = (val >> 6) & 0xff;
2294 exp = (val & 0x3f);
2295 if ((exp & 0x20) != 0)
2296 exp -= 0x40;
2297 n <<= exp+16;
2298
2299 val = dib8000_read_word(state, 543);
2300 s = (val >> 6) & 0xff;
2301 exp = (val & 0x3f);
2302 if ((exp & 0x20) != 0)
2303 exp -= 0x40;
2304 s <<= exp+16;
2305
2306 if (n > 0) {
2307 u32 t = (s/n) << 16;
2308 return t + ((s << 16) - n*t) / n;
2309 }
2310 return 0xffffffff;
2311}
2312
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002313static int dib8000_read_snr(struct dvb_frontend *fe, u16 * snr)
2314{
2315 struct dib8000_state *state = fe->demodulator_priv;
Olivier Grenie4c70e072011-01-03 15:33:37 -03002316 u8 index_frontend;
2317 u32 snr_master;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002318
Olivier Grenie4c70e072011-01-03 15:33:37 -03002319 snr_master = dib8000_get_snr(fe);
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002320 for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++)
Olivier Grenie4c70e072011-01-03 15:33:37 -03002321 snr_master += dib8000_get_snr(state->fe[index_frontend]);
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002322
Olivier Grenie4c70e072011-01-03 15:33:37 -03002323 if (snr_master != 0) {
2324 snr_master = 10*intlog10(snr_master>>16);
2325 *snr = snr_master / ((1 << 24) / 10);
2326 }
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002327 else
Olivier Grenie4c70e072011-01-03 15:33:37 -03002328 *snr = 0;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002329
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002330 return 0;
2331}
2332
Olivier Grenie4c70e072011-01-03 15:33:37 -03002333int dib8000_set_slave_frontend(struct dvb_frontend *fe, struct dvb_frontend *fe_slave)
2334{
2335 struct dib8000_state *state = fe->demodulator_priv;
2336 u8 index_frontend = 1;
2337
2338 while ((index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL))
2339 index_frontend++;
2340 if (index_frontend < MAX_NUMBER_OF_FRONTENDS) {
2341 dprintk("set slave fe %p to index %i", fe_slave, index_frontend);
2342 state->fe[index_frontend] = fe_slave;
2343 return 0;
2344 }
2345
2346 dprintk("too many slave frontend");
2347 return -ENOMEM;
2348}
2349EXPORT_SYMBOL(dib8000_set_slave_frontend);
2350
2351int dib8000_remove_slave_frontend(struct dvb_frontend *fe)
2352{
2353 struct dib8000_state *state = fe->demodulator_priv;
2354 u8 index_frontend = 1;
2355
2356 while ((index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL))
2357 index_frontend++;
2358 if (index_frontend != 1) {
2359 dprintk("remove slave fe %p (index %i)", state->fe[index_frontend-1], index_frontend-1);
2360 state->fe[index_frontend] = NULL;
2361 return 0;
2362 }
2363
2364 dprintk("no frontend to be removed");
2365 return -ENODEV;
2366}
2367EXPORT_SYMBOL(dib8000_remove_slave_frontend);
2368
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002369struct dvb_frontend *dib8000_get_slave_frontend(struct dvb_frontend *fe, int slave_index)
Olivier Grenie4c70e072011-01-03 15:33:37 -03002370{
2371 struct dib8000_state *state = fe->demodulator_priv;
2372
2373 if (slave_index >= MAX_NUMBER_OF_FRONTENDS)
2374 return NULL;
2375 return state->fe[slave_index];
2376}
2377EXPORT_SYMBOL(dib8000_get_slave_frontend);
2378
2379
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002380int dib8000_i2c_enumeration(struct i2c_adapter *host, int no_of_demods, u8 default_addr, u8 first_addr)
2381{
2382 int k = 0;
2383 u8 new_addr = 0;
2384 struct i2c_device client = {.adap = host };
2385
2386 for (k = no_of_demods - 1; k >= 0; k--) {
2387 /* designated i2c address */
2388 new_addr = first_addr + (k << 1);
2389
2390 client.addr = new_addr;
2391 dib8000_i2c_write16(&client, 1287, 0x0003); /* sram lead in, rdy */
2392 if (dib8000_identify(&client) == 0) {
2393 dib8000_i2c_write16(&client, 1287, 0x0003); /* sram lead in, rdy */
2394 client.addr = default_addr;
2395 if (dib8000_identify(&client) == 0) {
2396 dprintk("#%d: not identified", k);
2397 return -EINVAL;
2398 }
2399 }
2400
2401 /* start diversity to pull_down div_str - just for i2c-enumeration */
2402 dib8000_i2c_write16(&client, 1286, (1 << 10) | (4 << 6));
2403
2404 /* set new i2c address and force divstart */
2405 dib8000_i2c_write16(&client, 1285, (new_addr << 2) | 0x2);
2406 client.addr = new_addr;
2407 dib8000_identify(&client);
2408
2409 dprintk("IC %d initialized (to i2c_address 0x%x)", k, new_addr);
2410 }
2411
2412 for (k = 0; k < no_of_demods; k++) {
2413 new_addr = first_addr | (k << 1);
2414 client.addr = new_addr;
2415
2416 // unforce divstr
2417 dib8000_i2c_write16(&client, 1285, new_addr << 2);
2418
2419 /* deactivate div - it was just for i2c-enumeration */
2420 dib8000_i2c_write16(&client, 1286, 0);
2421 }
2422
2423 return 0;
2424}
2425
2426EXPORT_SYMBOL(dib8000_i2c_enumeration);
2427static int dib8000_fe_get_tune_settings(struct dvb_frontend *fe, struct dvb_frontend_tune_settings *tune)
2428{
2429 tune->min_delay_ms = 1000;
2430 tune->step_size = 0;
2431 tune->max_drift = 0;
2432 return 0;
2433}
2434
2435static void dib8000_release(struct dvb_frontend *fe)
2436{
2437 struct dib8000_state *st = fe->demodulator_priv;
Olivier Grenie4c70e072011-01-03 15:33:37 -03002438 u8 index_frontend;
2439
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002440 for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (st->fe[index_frontend] != NULL); index_frontend++)
Olivier Grenie4c70e072011-01-03 15:33:37 -03002441 dvb_frontend_detach(st->fe[index_frontend]);
2442
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002443 dibx000_exit_i2c_master(&st->i2c_master);
Olivier Grenie4c70e072011-01-03 15:33:37 -03002444 kfree(st->fe[0]);
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002445 kfree(st);
2446}
2447
2448struct i2c_adapter *dib8000_get_i2c_master(struct dvb_frontend *fe, enum dibx000_i2c_interface intf, int gating)
2449{
2450 struct dib8000_state *st = fe->demodulator_priv;
2451 return dibx000_get_i2c_adapter(&st->i2c_master, intf, gating);
2452}
2453
2454EXPORT_SYMBOL(dib8000_get_i2c_master);
2455
Olivier Grenief8731f42009-09-18 04:08:43 -03002456int dib8000_pid_filter_ctrl(struct dvb_frontend *fe, u8 onoff)
2457{
2458 struct dib8000_state *st = fe->demodulator_priv;
Olivier Grenie4c70e072011-01-03 15:33:37 -03002459 u16 val = dib8000_read_word(st, 299) & 0xffef;
2460 val |= (onoff & 0x1) << 4;
Olivier Grenief8731f42009-09-18 04:08:43 -03002461
Olivier Grenie4c70e072011-01-03 15:33:37 -03002462 dprintk("pid filter enabled %d", onoff);
2463 return dib8000_write_word(st, 299, val);
Olivier Grenief8731f42009-09-18 04:08:43 -03002464}
2465EXPORT_SYMBOL(dib8000_pid_filter_ctrl);
2466
2467int dib8000_pid_filter(struct dvb_frontend *fe, u8 id, u16 pid, u8 onoff)
2468{
2469 struct dib8000_state *st = fe->demodulator_priv;
Olivier Grenie4c70e072011-01-03 15:33:37 -03002470 dprintk("Index %x, PID %d, OnOff %d", id, pid, onoff);
2471 return dib8000_write_word(st, 305 + id, onoff ? (1 << 13) | pid : 0);
Olivier Grenief8731f42009-09-18 04:08:43 -03002472}
2473EXPORT_SYMBOL(dib8000_pid_filter);
2474
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002475static const struct dvb_frontend_ops dib8000_ops = {
2476 .info = {
2477 .name = "DiBcom 8000 ISDB-T",
2478 .type = FE_OFDM,
2479 .frequency_min = 44250000,
2480 .frequency_max = 867250000,
2481 .frequency_stepsize = 62500,
2482 .caps = FE_CAN_INVERSION_AUTO |
2483 FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
2484 FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
2485 FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO |
2486 FE_CAN_TRANSMISSION_MODE_AUTO | FE_CAN_GUARD_INTERVAL_AUTO | FE_CAN_RECOVER | FE_CAN_HIERARCHY_AUTO,
2487 },
2488
2489 .release = dib8000_release,
2490
2491 .init = dib8000_wakeup,
2492 .sleep = dib8000_sleep,
2493
2494 .set_frontend = dib8000_set_frontend,
2495 .get_tune_settings = dib8000_fe_get_tune_settings,
2496 .get_frontend = dib8000_get_frontend,
2497
2498 .read_status = dib8000_read_status,
2499 .read_ber = dib8000_read_ber,
2500 .read_signal_strength = dib8000_read_signal_strength,
2501 .read_snr = dib8000_read_snr,
2502 .read_ucblocks = dib8000_read_unc_blocks,
2503};
2504
2505struct dvb_frontend *dib8000_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr, struct dib8000_config *cfg)
2506{
2507 struct dvb_frontend *fe;
2508 struct dib8000_state *state;
2509
2510 dprintk("dib8000_attach");
2511
2512 state = kzalloc(sizeof(struct dib8000_state), GFP_KERNEL);
2513 if (state == NULL)
2514 return NULL;
Olivier Grenie4c70e072011-01-03 15:33:37 -03002515 fe = kzalloc(sizeof(struct dvb_frontend), GFP_KERNEL);
2516 if (fe == NULL)
Dan Carpentered54c0e2011-01-19 11:27:58 -03002517 goto error;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002518
2519 memcpy(&state->cfg, cfg, sizeof(struct dib8000_config));
2520 state->i2c.adap = i2c_adap;
2521 state->i2c.addr = i2c_addr;
2522 state->gpio_val = cfg->gpio_val;
2523 state->gpio_dir = cfg->gpio_dir;
2524
2525 /* Ensure the output mode remains at the previous default if it's
2526 * not specifically set by the caller.
2527 */
2528 if ((state->cfg.output_mode != OUTMODE_MPEG2_SERIAL) && (state->cfg.output_mode != OUTMODE_MPEG2_PAR_GATED_CLK))
2529 state->cfg.output_mode = OUTMODE_MPEG2_FIFO;
2530
Olivier Grenie4c70e072011-01-03 15:33:37 -03002531 state->fe[0] = fe;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002532 fe->demodulator_priv = state;
Olivier Grenie4c70e072011-01-03 15:33:37 -03002533 memcpy(&state->fe[0]->ops, &dib8000_ops, sizeof(struct dvb_frontend_ops));
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002534
2535 state->timf_default = cfg->pll->timf;
2536
2537 if (dib8000_identify(&state->i2c) == 0)
2538 goto error;
2539
2540 dibx000_init_i2c_master(&state->i2c_master, DIB8000, state->i2c.adap, state->i2c.addr);
2541
2542 dib8000_reset(fe);
2543
2544 dib8000_write_word(state, 285, (dib8000_read_word(state, 285) & ~0x60) | (3 << 5)); /* ber_rs_len = 3 */
2545
2546 return fe;
2547
2548 error:
2549 kfree(state);
2550 return NULL;
2551}
2552
2553EXPORT_SYMBOL(dib8000_attach);
2554
2555MODULE_AUTHOR("Olivier Grenie <Olivier.Grenie@dibcom.fr, " "Patrick Boettcher <pboettcher@dibcom.fr>");
2556MODULE_DESCRIPTION("Driver for the DiBcom 8000 ISDB-T demodulator");
2557MODULE_LICENSE("GPL");