blob: 7d2ea112ae2bf9217363f3f0172a81d6340b3f0f [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;
Olivier Grenie5a0deee2011-05-03 12:27:33 -030038 u8 *i2c_write_buffer;
39 u8 *i2c_read_buffer;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -030040};
41
42struct dib8000_state {
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -030043 struct dib8000_config cfg;
44
45 struct i2c_device i2c;
46
47 struct dibx000_i2c_master i2c_master;
48
49 u16 wbd_ref;
50
51 u8 current_band;
52 u32 current_bandwidth;
53 struct dibx000_agc_config *current_agc;
54 u32 timf;
55 u32 timf_default;
56
57 u8 div_force_off:1;
58 u8 div_state:1;
59 u16 div_sync_wait;
60
61 u8 agc_state;
62 u8 differential_constellation;
63 u8 diversity_onoff;
64
65 s16 ber_monitored_layer;
66 u16 gpio_dir;
67 u16 gpio_val;
68
69 u16 revision;
70 u8 isdbt_cfg_loaded;
71 enum frontend_tune_state tune_state;
72 u32 status;
Olivier Grenie4c70e072011-01-03 15:33:37 -030073
74 struct dvb_frontend *fe[MAX_NUMBER_OF_FRONTENDS];
Olivier Grenie5a0deee2011-05-03 12:27:33 -030075
76 /* for the I2C transfer */
77 struct i2c_msg msg[2];
78 u8 i2c_write_buffer[4];
79 u8 i2c_read_buffer[2];
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -030080};
81
82enum dib8000_power_mode {
83 DIB8000M_POWER_ALL = 0,
84 DIB8000M_POWER_INTERFACE_ONLY,
85};
86
87static u16 dib8000_i2c_read16(struct i2c_device *i2c, u16 reg)
88{
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -030089 struct i2c_msg msg[2] = {
Olivier Grenie5a0deee2011-05-03 12:27:33 -030090 {.addr = i2c->addr >> 1, .flags = 0,
91 .buf = i2c->i2c_write_buffer, .len = 2},
92 {.addr = i2c->addr >> 1, .flags = I2C_M_RD,
93 .buf = i2c->i2c_read_buffer, .len = 2},
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -030094 };
95
Olivier Grenie5a0deee2011-05-03 12:27:33 -030096 msg[0].buf[0] = reg >> 8;
97 msg[0].buf[1] = reg & 0xff;
98
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -030099 if (i2c_transfer(i2c->adap, msg, 2) != 2)
100 dprintk("i2c read error on %d", reg);
101
Olivier Grenie5a0deee2011-05-03 12:27:33 -0300102 return (msg[1].buf[0] << 8) | msg[1].buf[1];
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300103}
104
105static u16 dib8000_read_word(struct dib8000_state *state, u16 reg)
106{
Olivier Grenie5a0deee2011-05-03 12:27:33 -0300107 state->i2c_write_buffer[0] = reg >> 8;
108 state->i2c_write_buffer[1] = reg & 0xff;
109
110 memset(state->msg, 0, 2 * sizeof(struct i2c_msg));
111 state->msg[0].addr = state->i2c.addr >> 1;
112 state->msg[0].flags = 0;
113 state->msg[0].buf = state->i2c_write_buffer;
114 state->msg[0].len = 2;
115 state->msg[1].addr = state->i2c.addr >> 1;
116 state->msg[1].flags = I2C_M_RD;
117 state->msg[1].buf = state->i2c_read_buffer;
118 state->msg[1].len = 2;
119
120 if (i2c_transfer(state->i2c.adap, state->msg, 2) != 2)
121 dprintk("i2c read error on %d", reg);
122
123 return (state->i2c_read_buffer[0] << 8) | state->i2c_read_buffer[1];
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300124}
125
126static u32 dib8000_read32(struct dib8000_state *state, u16 reg)
127{
128 u16 rw[2];
129
130 rw[0] = dib8000_read_word(state, reg + 0);
131 rw[1] = dib8000_read_word(state, reg + 1);
132
133 return ((rw[0] << 16) | (rw[1]));
134}
135
136static int dib8000_i2c_write16(struct i2c_device *i2c, u16 reg, u16 val)
137{
Olivier Grenie5a0deee2011-05-03 12:27:33 -0300138 struct i2c_msg msg = {.addr = i2c->addr >> 1, .flags = 0,
139 .buf = i2c->i2c_write_buffer, .len = 4};
140 int ret = 0;
141
142 msg.buf[0] = (reg >> 8) & 0xff;
143 msg.buf[1] = reg & 0xff;
144 msg.buf[2] = (val >> 8) & 0xff;
145 msg.buf[3] = val & 0xff;
146
147 ret = i2c_transfer(i2c->adap, &msg, 1) != 1 ? -EREMOTEIO : 0;
148
149 return ret;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300150}
151
152static int dib8000_write_word(struct dib8000_state *state, u16 reg, u16 val)
153{
Olivier Grenie5a0deee2011-05-03 12:27:33 -0300154 state->i2c_write_buffer[0] = (reg >> 8) & 0xff;
155 state->i2c_write_buffer[1] = reg & 0xff;
156 state->i2c_write_buffer[2] = (val >> 8) & 0xff;
157 state->i2c_write_buffer[3] = val & 0xff;
158
159 memset(&state->msg[0], 0, sizeof(struct i2c_msg));
160 state->msg[0].addr = state->i2c.addr >> 1;
161 state->msg[0].flags = 0;
162 state->msg[0].buf = state->i2c_write_buffer;
163 state->msg[0].len = 4;
164
165 return i2c_transfer(state->i2c.adap, state->msg, 1) != 1 ? -EREMOTEIO : 0;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300166}
167
Olivier Grenie4c70e072011-01-03 15:33:37 -0300168static const s16 coeff_2k_sb_1seg_dqpsk[8] = {
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300169 (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 -0300170 (920 << 5) | 0x09
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300171};
172
Olivier Grenie4c70e072011-01-03 15:33:37 -0300173static const s16 coeff_2k_sb_1seg[8] = {
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300174 (692 << 5) | 0x0b, (683 << 5) | 0x01, (519 << 5) | 0x09, (692 << 5) | 0x0b, 0 | 0x1f, 0 | 0x1f, 0 | 0x1f, 0 | 0x1f
175};
176
Olivier Grenie4c70e072011-01-03 15:33:37 -0300177static const s16 coeff_2k_sb_3seg_0dqpsk_1dqpsk[8] = {
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300178 (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 -0300179 (-931 << 5) | 0x0f
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300180};
181
Olivier Grenie4c70e072011-01-03 15:33:37 -0300182static const s16 coeff_2k_sb_3seg_0dqpsk[8] = {
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300183 (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 -0300184 (982 << 5) | 0x0c
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300185};
186
Olivier Grenie4c70e072011-01-03 15:33:37 -0300187static const s16 coeff_2k_sb_3seg_1dqpsk[8] = {
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300188 (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 -0300189 (-720 << 5) | 0x0d
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300190};
191
Olivier Grenie4c70e072011-01-03 15:33:37 -0300192static const s16 coeff_2k_sb_3seg[8] = {
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300193 (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 -0300194 (-610 << 5) | 0x0a
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300195};
196
Olivier Grenie4c70e072011-01-03 15:33:37 -0300197static const s16 coeff_4k_sb_1seg_dqpsk[8] = {
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300198 (-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 -0300199 (-922 << 5) | 0x0d
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300200};
201
Olivier Grenie4c70e072011-01-03 15:33:37 -0300202static const s16 coeff_4k_sb_1seg[8] = {
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300203 (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 -0300204 (-655 << 5) | 0x0a
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300205};
206
Olivier Grenie4c70e072011-01-03 15:33:37 -0300207static const s16 coeff_4k_sb_3seg_0dqpsk_1dqpsk[8] = {
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300208 (-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 -0300209 (-958 << 5) | 0x13
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300210};
211
Olivier Grenie4c70e072011-01-03 15:33:37 -0300212static const s16 coeff_4k_sb_3seg_0dqpsk[8] = {
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300213 (-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 -0300214 (-568 << 5) | 0x0f
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300215};
216
Olivier Grenie4c70e072011-01-03 15:33:37 -0300217static const s16 coeff_4k_sb_3seg_1dqpsk[8] = {
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300218 (-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 -0300219 (-848 << 5) | 0x13
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300220};
221
Olivier Grenie4c70e072011-01-03 15:33:37 -0300222static const s16 coeff_4k_sb_3seg[8] = {
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300223 (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 -0300224 (-869 << 5) | 0x13
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300225};
226
Olivier Grenie4c70e072011-01-03 15:33:37 -0300227static const s16 coeff_8k_sb_1seg_dqpsk[8] = {
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300228 (-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 -0300229 (-598 << 5) | 0x10
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300230};
231
Olivier Grenie4c70e072011-01-03 15:33:37 -0300232static const s16 coeff_8k_sb_1seg[8] = {
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300233 (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 -0300234 (585 << 5) | 0x0f
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300235};
236
Olivier Grenie4c70e072011-01-03 15:33:37 -0300237static const s16 coeff_8k_sb_3seg_0dqpsk_1dqpsk[8] = {
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300238 (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 -0300239 (0 << 5) | 0x14
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300240};
241
Olivier Grenie4c70e072011-01-03 15:33:37 -0300242static const s16 coeff_8k_sb_3seg_0dqpsk[8] = {
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300243 (-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 -0300244 (-877 << 5) | 0x15
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300245};
246
Olivier Grenie4c70e072011-01-03 15:33:37 -0300247static const s16 coeff_8k_sb_3seg_1dqpsk[8] = {
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300248 (-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 -0300249 (-921 << 5) | 0x14
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300250};
251
Olivier Grenie4c70e072011-01-03 15:33:37 -0300252static const s16 coeff_8k_sb_3seg[8] = {
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300253 (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 -0300254 (690 << 5) | 0x14
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300255};
256
Olivier Grenie4c70e072011-01-03 15:33:37 -0300257static const s16 ana_fe_coeff_3seg[24] = {
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300258 81, 80, 78, 74, 68, 61, 54, 45, 37, 28, 19, 11, 4, 1022, 1017, 1013, 1010, 1008, 1008, 1008, 1008, 1010, 1014, 1017
259};
260
Olivier Grenie4c70e072011-01-03 15:33:37 -0300261static const s16 ana_fe_coeff_1seg[24] = {
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300262 249, 226, 164, 82, 5, 981, 970, 988, 1018, 20, 31, 26, 8, 1012, 1000, 1018, 1012, 8, 15, 14, 9, 3, 1017, 1003
263};
264
Olivier Grenie4c70e072011-01-03 15:33:37 -0300265static const s16 ana_fe_coeff_13seg[24] = {
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300266 396, 305, 105, -51, -77, -12, 41, 31, -11, -30, -11, 14, 15, -2, -13, -7, 5, 8, 1, -6, -7, -3, 0, 1
267};
268
269static u16 fft_to_mode(struct dib8000_state *state)
270{
271 u16 mode;
Olivier Grenie4c70e072011-01-03 15:33:37 -0300272 switch (state->fe[0]->dtv_property_cache.transmission_mode) {
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300273 case TRANSMISSION_MODE_2K:
274 mode = 1;
275 break;
276 case TRANSMISSION_MODE_4K:
277 mode = 2;
278 break;
279 default:
280 case TRANSMISSION_MODE_AUTO:
281 case TRANSMISSION_MODE_8K:
282 mode = 3;
283 break;
284 }
285 return mode;
286}
287
288static void dib8000_set_acquisition_mode(struct dib8000_state *state)
289{
290 u16 nud = dib8000_read_word(state, 298);
291 nud |= (1 << 3) | (1 << 0);
292 dprintk("acquisition mode activated");
293 dib8000_write_word(state, 298, nud);
294}
Olivier Grenie4c70e072011-01-03 15:33:37 -0300295static int dib8000_set_output_mode(struct dvb_frontend *fe, int mode)
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300296{
Olivier Grenie4c70e072011-01-03 15:33:37 -0300297 struct dib8000_state *state = fe->demodulator_priv;
298
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300299 u16 outreg, fifo_threshold, smo_mode, sram = 0x0205; /* by default SDRAM deintlv is enabled */
300
301 outreg = 0;
302 fifo_threshold = 1792;
303 smo_mode = (dib8000_read_word(state, 299) & 0x0050) | (1 << 1);
304
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300305 dprintk("-I- Setting output mode for demod %p to %d",
306 &state->fe[0], mode);
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300307
308 switch (mode) {
309 case OUTMODE_MPEG2_PAR_GATED_CLK: // STBs with parallel gated clock
310 outreg = (1 << 10); /* 0x0400 */
311 break;
312 case OUTMODE_MPEG2_PAR_CONT_CLK: // STBs with parallel continues clock
313 outreg = (1 << 10) | (1 << 6); /* 0x0440 */
314 break;
315 case OUTMODE_MPEG2_SERIAL: // STBs with serial input
316 outreg = (1 << 10) | (2 << 6) | (0 << 1); /* 0x0482 */
317 break;
318 case OUTMODE_DIVERSITY:
319 if (state->cfg.hostbus_diversity) {
320 outreg = (1 << 10) | (4 << 6); /* 0x0500 */
321 sram &= 0xfdff;
322 } else
323 sram |= 0x0c00;
324 break;
325 case OUTMODE_MPEG2_FIFO: // e.g. USB feeding
326 smo_mode |= (3 << 1);
327 fifo_threshold = 512;
328 outreg = (1 << 10) | (5 << 6);
329 break;
330 case OUTMODE_HIGH_Z: // disable
331 outreg = 0;
332 break;
333
334 case OUTMODE_ANALOG_ADC:
335 outreg = (1 << 10) | (3 << 6);
336 dib8000_set_acquisition_mode(state);
337 break;
338
339 default:
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300340 dprintk("Unhandled output_mode passed to be set for demod %p",
341 &state->fe[0]);
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300342 return -EINVAL;
343 }
344
345 if (state->cfg.output_mpeg2_in_188_bytes)
346 smo_mode |= (1 << 5);
347
348 dib8000_write_word(state, 299, smo_mode);
349 dib8000_write_word(state, 300, fifo_threshold); /* synchronous fread */
350 dib8000_write_word(state, 1286, outreg);
351 dib8000_write_word(state, 1291, sram);
352
353 return 0;
354}
355
356static int dib8000_set_diversity_in(struct dvb_frontend *fe, int onoff)
357{
358 struct dib8000_state *state = fe->demodulator_priv;
359 u16 sync_wait = dib8000_read_word(state, 273) & 0xfff0;
360
361 if (!state->differential_constellation) {
362 dib8000_write_word(state, 272, 1 << 9); //dvsy_off_lmod4 = 1
363 dib8000_write_word(state, 273, sync_wait | (1 << 2) | 2); // sync_enable = 1; comb_mode = 2
364 } else {
365 dib8000_write_word(state, 272, 0); //dvsy_off_lmod4 = 0
366 dib8000_write_word(state, 273, sync_wait); // sync_enable = 0; comb_mode = 0
367 }
368 state->diversity_onoff = onoff;
369
370 switch (onoff) {
371 case 0: /* only use the internal way - not the diversity input */
372 dib8000_write_word(state, 270, 1);
373 dib8000_write_word(state, 271, 0);
374 break;
375 case 1: /* both ways */
376 dib8000_write_word(state, 270, 6);
377 dib8000_write_word(state, 271, 6);
378 break;
379 case 2: /* only the diversity input */
380 dib8000_write_word(state, 270, 0);
381 dib8000_write_word(state, 271, 1);
382 break;
383 }
384 return 0;
385}
386
387static void dib8000_set_power_mode(struct dib8000_state *state, enum dib8000_power_mode mode)
388{
389 /* by default everything is going to be powered off */
390 u16 reg_774 = 0x3fff, reg_775 = 0xffff, reg_776 = 0xffff,
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300391 reg_900 = (dib8000_read_word(state, 900) & 0xfffc) | 0x3,
392 reg_1280 = (dib8000_read_word(state, 1280) & 0x00ff) | 0xff00;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300393
394 /* now, depending on the requested mode, we power on */
395 switch (mode) {
396 /* power up everything in the demod */
397 case DIB8000M_POWER_ALL:
398 reg_774 = 0x0000;
399 reg_775 = 0x0000;
400 reg_776 = 0x0000;
401 reg_900 &= 0xfffc;
402 reg_1280 &= 0x00ff;
403 break;
404 case DIB8000M_POWER_INTERFACE_ONLY:
405 reg_1280 &= 0x00ff;
406 break;
407 }
408
409 dprintk("powermode : 774 : %x ; 775 : %x; 776 : %x ; 900 : %x; 1280 : %x", reg_774, reg_775, reg_776, reg_900, reg_1280);
410 dib8000_write_word(state, 774, reg_774);
411 dib8000_write_word(state, 775, reg_775);
412 dib8000_write_word(state, 776, reg_776);
413 dib8000_write_word(state, 900, reg_900);
414 dib8000_write_word(state, 1280, reg_1280);
415}
416
417static int dib8000_set_adc_state(struct dib8000_state *state, enum dibx000_adc_states no)
418{
419 int ret = 0;
420 u16 reg_907 = dib8000_read_word(state, 907), reg_908 = dib8000_read_word(state, 908);
421
422 switch (no) {
423 case DIBX000_SLOW_ADC_ON:
424 reg_908 |= (1 << 1) | (1 << 0);
425 ret |= dib8000_write_word(state, 908, reg_908);
426 reg_908 &= ~(1 << 1);
427 break;
428
429 case DIBX000_SLOW_ADC_OFF:
430 reg_908 |= (1 << 1) | (1 << 0);
431 break;
432
433 case DIBX000_ADC_ON:
434 reg_907 &= 0x0fff;
435 reg_908 &= 0x0003;
436 break;
437
438 case DIBX000_ADC_OFF: // leave the VBG voltage on
439 reg_907 |= (1 << 14) | (1 << 13) | (1 << 12);
440 reg_908 |= (1 << 5) | (1 << 4) | (1 << 3) | (1 << 2);
441 break;
442
443 case DIBX000_VBG_ENABLE:
444 reg_907 &= ~(1 << 15);
445 break;
446
447 case DIBX000_VBG_DISABLE:
448 reg_907 |= (1 << 15);
449 break;
450
451 default:
452 break;
453 }
454
455 ret |= dib8000_write_word(state, 907, reg_907);
456 ret |= dib8000_write_word(state, 908, reg_908);
457
458 return ret;
459}
460
Olivier Grenie4c70e072011-01-03 15:33:37 -0300461static int dib8000_set_bandwidth(struct dvb_frontend *fe, u32 bw)
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300462{
Olivier Grenie4c70e072011-01-03 15:33:37 -0300463 struct dib8000_state *state = fe->demodulator_priv;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300464 u32 timf;
465
466 if (bw == 0)
467 bw = 6000;
468
469 if (state->timf == 0) {
470 dprintk("using default timf");
471 timf = state->timf_default;
472 } else {
473 dprintk("using updated timf");
474 timf = state->timf;
475 }
476
477 dib8000_write_word(state, 29, (u16) ((timf >> 16) & 0xffff));
478 dib8000_write_word(state, 30, (u16) ((timf) & 0xffff));
479
480 return 0;
481}
482
483static int dib8000_sad_calib(struct dib8000_state *state)
484{
485/* internal */
486 dib8000_write_word(state, 923, (0 << 1) | (0 << 0));
487 dib8000_write_word(state, 924, 776); // 0.625*3.3 / 4096
488
489 /* do the calibration */
490 dib8000_write_word(state, 923, (1 << 0));
491 dib8000_write_word(state, 923, (0 << 0));
492
493 msleep(1);
494 return 0;
495}
496
497int dib8000_set_wbd_ref(struct dvb_frontend *fe, u16 value)
498{
499 struct dib8000_state *state = fe->demodulator_priv;
500 if (value > 4095)
501 value = 4095;
502 state->wbd_ref = value;
503 return dib8000_write_word(state, 106, value);
504}
505
506EXPORT_SYMBOL(dib8000_set_wbd_ref);
507static void dib8000_reset_pll_common(struct dib8000_state *state, const struct dibx000_bandwidth_config *bw)
508{
509 dprintk("ifreq: %d %x, inversion: %d", bw->ifreq, bw->ifreq, bw->ifreq >> 25);
510 dib8000_write_word(state, 23, (u16) (((bw->internal * 1000) >> 16) & 0xffff)); /* P_sec_len */
511 dib8000_write_word(state, 24, (u16) ((bw->internal * 1000) & 0xffff));
512 dib8000_write_word(state, 27, (u16) ((bw->ifreq >> 16) & 0x01ff));
513 dib8000_write_word(state, 28, (u16) (bw->ifreq & 0xffff));
514 dib8000_write_word(state, 26, (u16) ((bw->ifreq >> 25) & 0x0003));
515
516 dib8000_write_word(state, 922, bw->sad_cfg);
517}
518
519static void dib8000_reset_pll(struct dib8000_state *state)
520{
521 const struct dibx000_bandwidth_config *pll = state->cfg.pll;
522 u16 clk_cfg1;
523
524 // clk_cfg0
525 dib8000_write_word(state, 901, (pll->pll_prediv << 8) | (pll->pll_ratio << 0));
526
527 // clk_cfg1
528 clk_cfg1 = (1 << 10) | (0 << 9) | (pll->IO_CLK_en_core << 8) |
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300529 (pll->bypclk_div << 5) | (pll->enable_refdiv << 4) | (1 << 3) |
530 (pll->pll_range << 1) | (pll->pll_reset << 0);
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300531
532 dib8000_write_word(state, 902, clk_cfg1);
533 clk_cfg1 = (clk_cfg1 & 0xfff7) | (pll->pll_bypass << 3);
534 dib8000_write_word(state, 902, clk_cfg1);
535
536 dprintk("clk_cfg1: 0x%04x", clk_cfg1); /* 0x507 1 0 1 000 0 0 11 1 */
537
538 /* smpl_cfg: P_refclksel=2, P_ensmplsel=1 nodivsmpl=1 */
539 if (state->cfg.pll->ADClkSrc == 0)
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300540 dib8000_write_word(state, 904, (0 << 15) | (0 << 12) | (0 << 10) |
541 (pll->modulo << 8) | (pll->ADClkSrc << 7) | (0 << 1));
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300542 else if (state->cfg.refclksel != 0)
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300543 dib8000_write_word(state, 904, (0 << 15) | (1 << 12) |
544 ((state->cfg.refclksel & 0x3) << 10) | (pll->modulo << 8) |
545 (pll->ADClkSrc << 7) | (0 << 1));
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300546 else
547 dib8000_write_word(state, 904, (0 << 15) | (1 << 12) | (3 << 10) | (pll->modulo << 8) | (pll->ADClkSrc << 7) | (0 << 1));
548
549 dib8000_reset_pll_common(state, pll);
550}
551
552static int dib8000_reset_gpio(struct dib8000_state *st)
553{
554 /* reset the GPIOs */
555 dib8000_write_word(st, 1029, st->cfg.gpio_dir);
556 dib8000_write_word(st, 1030, st->cfg.gpio_val);
557
558 /* TODO 782 is P_gpio_od */
559
560 dib8000_write_word(st, 1032, st->cfg.gpio_pwm_pos);
561
562 dib8000_write_word(st, 1037, st->cfg.pwm_freq_div);
563 return 0;
564}
565
566static int dib8000_cfg_gpio(struct dib8000_state *st, u8 num, u8 dir, u8 val)
567{
568 st->cfg.gpio_dir = dib8000_read_word(st, 1029);
569 st->cfg.gpio_dir &= ~(1 << num); /* reset the direction bit */
570 st->cfg.gpio_dir |= (dir & 0x1) << num; /* set the new direction */
571 dib8000_write_word(st, 1029, st->cfg.gpio_dir);
572
573 st->cfg.gpio_val = dib8000_read_word(st, 1030);
574 st->cfg.gpio_val &= ~(1 << num); /* reset the direction bit */
575 st->cfg.gpio_val |= (val & 0x01) << num; /* set the new value */
576 dib8000_write_word(st, 1030, st->cfg.gpio_val);
577
578 dprintk("gpio dir: %x: gpio val: %x", st->cfg.gpio_dir, st->cfg.gpio_val);
579
580 return 0;
581}
582
583int dib8000_set_gpio(struct dvb_frontend *fe, u8 num, u8 dir, u8 val)
584{
585 struct dib8000_state *state = fe->demodulator_priv;
586 return dib8000_cfg_gpio(state, num, dir, val);
587}
588
589EXPORT_SYMBOL(dib8000_set_gpio);
590static const u16 dib8000_defaults[] = {
591 /* auto search configuration - lock0 by default waiting
592 * for cpil_lock; lock1 cpil_lock; lock2 tmcc_sync_lock */
593 3, 7,
594 0x0004,
595 0x0400,
596 0x0814,
597
598 12, 11,
599 0x001b,
600 0x7740,
601 0x005b,
602 0x8d80,
603 0x01c9,
604 0xc380,
605 0x0000,
606 0x0080,
607 0x0000,
608 0x0090,
609 0x0001,
610 0xd4c0,
611
612 /*1, 32,
Olivier Grenie4c70e072011-01-03 15:33:37 -0300613 0x6680 // P_corm_thres Lock algorithms configuration */
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300614
615 11, 80, /* set ADC level to -16 */
616 (1 << 13) - 825 - 117,
617 (1 << 13) - 837 - 117,
618 (1 << 13) - 811 - 117,
619 (1 << 13) - 766 - 117,
620 (1 << 13) - 737 - 117,
621 (1 << 13) - 693 - 117,
622 (1 << 13) - 648 - 117,
623 (1 << 13) - 619 - 117,
624 (1 << 13) - 575 - 117,
625 (1 << 13) - 531 - 117,
626 (1 << 13) - 501 - 117,
627
628 4, 108,
629 0,
630 0,
631 0,
632 0,
633
634 1, 175,
635 0x0410,
636 1, 179,
637 8192, // P_fft_nb_to_cut
638
639 6, 181,
640 0x2800, // P_coff_corthres_ ( 2k 4k 8k ) 0x2800
641 0x2800,
642 0x2800,
643 0x2800, // P_coff_cpilthres_ ( 2k 4k 8k ) 0x2800
644 0x2800,
645 0x2800,
646
647 2, 193,
648 0x0666, // P_pha3_thres
649 0x0000, // P_cti_use_cpe, P_cti_use_prog
650
651 2, 205,
652 0x200f, // P_cspu_regul, P_cspu_win_cut
653 0x000f, // P_des_shift_work
654
655 5, 215,
656 0x023d, // P_adp_regul_cnt
657 0x00a4, // P_adp_noise_cnt
658 0x00a4, // P_adp_regul_ext
659 0x7ff0, // P_adp_noise_ext
660 0x3ccc, // P_adp_fil
661
662 1, 230,
663 0x0000, // P_2d_byp_ti_num
664
665 1, 263,
666 0x800, //P_equal_thres_wgn
667
668 1, 268,
669 (2 << 9) | 39, // P_equal_ctrl_synchro, P_equal_speedmode
670
671 1, 270,
672 0x0001, // P_div_lock0_wait
673 1, 285,
674 0x0020, //p_fec_
675 1, 299,
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300676 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 -0300677
678 1, 338,
679 (1 << 12) | // P_ctrl_corm_thres4pre_freq_inh=1
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300680 (1 << 10) |
681 (0 << 9) | /* P_ctrl_pre_freq_inh=0 */
682 (3 << 5) | /* P_ctrl_pre_freq_step=3 */
683 (1 << 0), /* P_pre_freq_win_len=1 */
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300684
685 1, 903,
686 (0 << 4) | 2, // P_divclksel=0 P_divbitsel=2 (was clk=3,bit=1 for MPW)
687
688 0,
689};
690
691static u16 dib8000_identify(struct i2c_device *client)
692{
693 u16 value;
694
695 //because of glitches sometimes
696 value = dib8000_i2c_read16(client, 896);
697
698 if ((value = dib8000_i2c_read16(client, 896)) != 0x01b3) {
699 dprintk("wrong Vendor ID (read=0x%x)", value);
700 return 0;
701 }
702
703 value = dib8000_i2c_read16(client, 897);
704 if (value != 0x8000 && value != 0x8001 && value != 0x8002) {
705 dprintk("wrong Device ID (%x)", value);
706 return 0;
707 }
708
709 switch (value) {
710 case 0x8000:
711 dprintk("found DiB8000A");
712 break;
713 case 0x8001:
714 dprintk("found DiB8000B");
715 break;
716 case 0x8002:
717 dprintk("found DiB8000C");
718 break;
719 }
720 return value;
721}
722
723static int dib8000_reset(struct dvb_frontend *fe)
724{
725 struct dib8000_state *state = fe->demodulator_priv;
726
727 dib8000_write_word(state, 1287, 0x0003); /* sram lead in, rdy */
728
729 if ((state->revision = dib8000_identify(&state->i2c)) == 0)
730 return -EINVAL;
731
732 if (state->revision == 0x8000)
733 dprintk("error : dib8000 MA not supported");
734
735 dibx000_reset_i2c_master(&state->i2c_master);
736
737 dib8000_set_power_mode(state, DIB8000M_POWER_ALL);
738
739 /* always leave the VBG voltage on - it consumes almost nothing but takes a long time to start */
740 dib8000_set_adc_state(state, DIBX000_VBG_ENABLE);
741
742 /* restart all parts */
743 dib8000_write_word(state, 770, 0xffff);
744 dib8000_write_word(state, 771, 0xffff);
745 dib8000_write_word(state, 772, 0xfffc);
746 dib8000_write_word(state, 898, 0x000c); // sad
747 dib8000_write_word(state, 1280, 0x004d);
748 dib8000_write_word(state, 1281, 0x000c);
749
750 dib8000_write_word(state, 770, 0x0000);
751 dib8000_write_word(state, 771, 0x0000);
752 dib8000_write_word(state, 772, 0x0000);
753 dib8000_write_word(state, 898, 0x0004); // sad
754 dib8000_write_word(state, 1280, 0x0000);
755 dib8000_write_word(state, 1281, 0x0000);
756
757 /* drives */
758 if (state->cfg.drives)
759 dib8000_write_word(state, 906, state->cfg.drives);
760 else {
761 dprintk("using standard PAD-drive-settings, please adjust settings in config-struct to be optimal.");
762 dib8000_write_word(state, 906, 0x2d98); // min drive SDRAM - not optimal - adjust
763 }
764
765 dib8000_reset_pll(state);
766
767 if (dib8000_reset_gpio(state) != 0)
768 dprintk("GPIO reset was not successful.");
769
Olivier Grenie4c70e072011-01-03 15:33:37 -0300770 if (dib8000_set_output_mode(fe, OUTMODE_HIGH_Z) != 0)
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300771 dprintk("OUTPUT_MODE could not be resetted.");
772
773 state->current_agc = NULL;
774
775 // P_iqc_alpha_pha, P_iqc_alpha_amp, P_iqc_dcc_alpha, ...
776 /* P_iqc_ca2 = 0; P_iqc_impnc_on = 0; P_iqc_mode = 0; */
777 if (state->cfg.pll->ifreq == 0)
778 dib8000_write_word(state, 40, 0x0755); /* P_iqc_corr_inh = 0 enable IQcorr block */
779 else
780 dib8000_write_word(state, 40, 0x1f55); /* P_iqc_corr_inh = 1 disable IQcorr block */
781
782 {
783 u16 l = 0, r;
784 const u16 *n;
785 n = dib8000_defaults;
786 l = *n++;
787 while (l) {
788 r = *n++;
789 do {
790 dib8000_write_word(state, r, *n++);
791 r++;
792 } while (--l);
793 l = *n++;
794 }
795 }
796 state->isdbt_cfg_loaded = 0;
797
798 //div_cfg override for special configs
799 if (state->cfg.div_cfg != 0)
800 dib8000_write_word(state, 903, state->cfg.div_cfg);
801
802 /* unforce divstr regardless whether i2c enumeration was done or not */
803 dib8000_write_word(state, 1285, dib8000_read_word(state, 1285) & ~(1 << 1));
804
Olivier Grenie4c70e072011-01-03 15:33:37 -0300805 dib8000_set_bandwidth(fe, 6000);
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300806
807 dib8000_set_adc_state(state, DIBX000_SLOW_ADC_ON);
808 dib8000_sad_calib(state);
809 dib8000_set_adc_state(state, DIBX000_SLOW_ADC_OFF);
810
811 dib8000_set_power_mode(state, DIB8000M_POWER_INTERFACE_ONLY);
812
813 return 0;
814}
815
816static void dib8000_restart_agc(struct dib8000_state *state)
817{
818 // P_restart_iqc & P_restart_agc
819 dib8000_write_word(state, 770, 0x0a00);
820 dib8000_write_word(state, 770, 0x0000);
821}
822
823static int dib8000_update_lna(struct dib8000_state *state)
824{
825 u16 dyn_gain;
826
827 if (state->cfg.update_lna) {
828 // read dyn_gain here (because it is demod-dependent and not tuner)
829 dyn_gain = dib8000_read_word(state, 390);
830
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300831 if (state->cfg.update_lna(state->fe[0], dyn_gain)) {
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300832 dib8000_restart_agc(state);
833 return 1;
834 }
835 }
836 return 0;
837}
838
839static int dib8000_set_agc_config(struct dib8000_state *state, u8 band)
840{
841 struct dibx000_agc_config *agc = NULL;
842 int i;
843 if (state->current_band == band && state->current_agc != NULL)
844 return 0;
845 state->current_band = band;
846
847 for (i = 0; i < state->cfg.agc_config_count; i++)
848 if (state->cfg.agc[i].band_caps & band) {
849 agc = &state->cfg.agc[i];
850 break;
851 }
852
853 if (agc == NULL) {
854 dprintk("no valid AGC configuration found for band 0x%02x", band);
855 return -EINVAL;
856 }
857
858 state->current_agc = agc;
859
860 /* AGC */
861 dib8000_write_word(state, 76, agc->setup);
862 dib8000_write_word(state, 77, agc->inv_gain);
863 dib8000_write_word(state, 78, agc->time_stabiliz);
864 dib8000_write_word(state, 101, (agc->alpha_level << 12) | agc->thlock);
865
866 // Demod AGC loop configuration
867 dib8000_write_word(state, 102, (agc->alpha_mant << 5) | agc->alpha_exp);
868 dib8000_write_word(state, 103, (agc->beta_mant << 6) | agc->beta_exp);
869
870 dprintk("WBD: ref: %d, sel: %d, active: %d, alpha: %d",
871 state->wbd_ref != 0 ? state->wbd_ref : agc->wbd_ref, agc->wbd_sel, !agc->perform_agc_softsplit, agc->wbd_sel);
872
873 /* AGC continued */
874 if (state->wbd_ref != 0)
875 dib8000_write_word(state, 106, state->wbd_ref);
876 else // use default
877 dib8000_write_word(state, 106, agc->wbd_ref);
878 dib8000_write_word(state, 107, (agc->wbd_alpha << 9) | (agc->perform_agc_softsplit << 8));
879 dib8000_write_word(state, 108, agc->agc1_max);
880 dib8000_write_word(state, 109, agc->agc1_min);
881 dib8000_write_word(state, 110, agc->agc2_max);
882 dib8000_write_word(state, 111, agc->agc2_min);
883 dib8000_write_word(state, 112, (agc->agc1_pt1 << 8) | agc->agc1_pt2);
884 dib8000_write_word(state, 113, (agc->agc1_slope1 << 8) | agc->agc1_slope2);
885 dib8000_write_word(state, 114, (agc->agc2_pt1 << 8) | agc->agc2_pt2);
886 dib8000_write_word(state, 115, (agc->agc2_slope1 << 8) | agc->agc2_slope2);
887
888 dib8000_write_word(state, 75, agc->agc1_pt3);
889 dib8000_write_word(state, 923, (dib8000_read_word(state, 923) & 0xffe3) | (agc->wbd_inv << 4) | (agc->wbd_sel << 2)); /*LB : 929 -> 923 */
890
891 return 0;
892}
893
Olivier Grenie03245a52009-12-04 13:27:57 -0300894void dib8000_pwm_agc_reset(struct dvb_frontend *fe)
895{
896 struct dib8000_state *state = fe->demodulator_priv;
897 dib8000_set_adc_state(state, DIBX000_ADC_ON);
898 dib8000_set_agc_config(state, (unsigned char)(BAND_OF_FREQUENCY(fe->dtv_property_cache.frequency / 1000)));
899}
900EXPORT_SYMBOL(dib8000_pwm_agc_reset);
901
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300902static int dib8000_agc_soft_split(struct dib8000_state *state)
903{
904 u16 agc, split_offset;
905
906 if (!state->current_agc || !state->current_agc->perform_agc_softsplit || state->current_agc->split.max == 0)
907 return FE_CALLBACK_TIME_NEVER;
908
909 // n_agc_global
910 agc = dib8000_read_word(state, 390);
911
912 if (agc > state->current_agc->split.min_thres)
913 split_offset = state->current_agc->split.min;
914 else if (agc < state->current_agc->split.max_thres)
915 split_offset = state->current_agc->split.max;
916 else
917 split_offset = state->current_agc->split.max *
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300918 (agc - state->current_agc->split.min_thres) /
919 (state->current_agc->split.max_thres - state->current_agc->split.min_thres);
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300920
921 dprintk("AGC split_offset: %d", split_offset);
922
923 // P_agc_force_split and P_agc_split_offset
924 dib8000_write_word(state, 107, (dib8000_read_word(state, 107) & 0xff00) | split_offset);
925 return 5000;
926}
927
928static int dib8000_agc_startup(struct dvb_frontend *fe)
929{
930 struct dib8000_state *state = fe->demodulator_priv;
931 enum frontend_tune_state *tune_state = &state->tune_state;
932
933 int ret = 0;
934
935 switch (*tune_state) {
936 case CT_AGC_START:
937 // set power-up level: interf+analog+AGC
938
939 dib8000_set_adc_state(state, DIBX000_ADC_ON);
940
941 if (dib8000_set_agc_config(state, (unsigned char)(BAND_OF_FREQUENCY(fe->dtv_property_cache.frequency / 1000))) != 0) {
942 *tune_state = CT_AGC_STOP;
943 state->status = FE_STATUS_TUNE_FAILED;
944 break;
945 }
946
947 ret = 70;
948 *tune_state = CT_AGC_STEP_0;
949 break;
950
951 case CT_AGC_STEP_0:
952 //AGC initialization
953 if (state->cfg.agc_control)
Olivier Grenie4c70e072011-01-03 15:33:37 -0300954 state->cfg.agc_control(fe, 1);
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300955
956 dib8000_restart_agc(state);
957
958 // wait AGC rough lock time
959 ret = 50;
960 *tune_state = CT_AGC_STEP_1;
961 break;
962
963 case CT_AGC_STEP_1:
964 // wait AGC accurate lock time
965 ret = 70;
966
967 if (dib8000_update_lna(state))
968 // wait only AGC rough lock time
969 ret = 50;
970 else
971 *tune_state = CT_AGC_STEP_2;
972 break;
973
974 case CT_AGC_STEP_2:
975 dib8000_agc_soft_split(state);
976
977 if (state->cfg.agc_control)
Olivier Grenie4c70e072011-01-03 15:33:37 -0300978 state->cfg.agc_control(fe, 0);
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300979
980 *tune_state = CT_AGC_STOP;
981 break;
982 default:
983 ret = dib8000_agc_soft_split(state);
984 break;
985 }
986 return ret;
987
988}
989
Olivier Grenie4c70e072011-01-03 15:33:37 -0300990static const s32 lut_1000ln_mant[] =
Olivier Grenie03245a52009-12-04 13:27:57 -0300991{
Olivier Grenie9c783032009-12-07 07:49:40 -0300992 908, 7003, 7090, 7170, 7244, 7313, 7377, 7438, 7495, 7549, 7600
Olivier Grenie03245a52009-12-04 13:27:57 -0300993};
994
Olivier Grenie4c70e072011-01-03 15:33:37 -0300995s32 dib8000_get_adc_power(struct dvb_frontend *fe, u8 mode)
Olivier Grenie03245a52009-12-04 13:27:57 -0300996{
Olivier Grenie4c70e072011-01-03 15:33:37 -0300997 struct dib8000_state *state = fe->demodulator_priv;
998 u32 ix = 0, tmp_val = 0, exp = 0, mant = 0;
999 s32 val;
Olivier Grenie03245a52009-12-04 13:27:57 -03001000
Olivier Grenie4c70e072011-01-03 15:33:37 -03001001 val = dib8000_read32(state, 384);
Olivier Grenie4c70e072011-01-03 15:33:37 -03001002 if (mode) {
1003 tmp_val = val;
1004 while (tmp_val >>= 1)
1005 exp++;
1006 mant = (val * 1000 / (1<<exp));
1007 ix = (u8)((mant-1000)/100); /* index of the LUT */
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001008 val = (lut_1000ln_mant[ix] + 693*(exp-20) - 6908);
Olivier Grenie4c70e072011-01-03 15:33:37 -03001009 val = (val*256)/1000;
1010 }
1011 return val;
Olivier Grenie03245a52009-12-04 13:27:57 -03001012}
1013EXPORT_SYMBOL(dib8000_get_adc_power);
1014
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001015static void dib8000_update_timf(struct dib8000_state *state)
1016{
1017 u32 timf = state->timf = dib8000_read32(state, 435);
1018
1019 dib8000_write_word(state, 29, (u16) (timf >> 16));
1020 dib8000_write_word(state, 30, (u16) (timf & 0xffff));
1021 dprintk("Updated timing frequency: %d (default: %d)", state->timf, state->timf_default);
1022}
1023
Olivier Grenie5a0deee2011-05-03 12:27:33 -03001024static const u16 adc_target_16dB[11] = {
1025 (1 << 13) - 825 - 117,
1026 (1 << 13) - 837 - 117,
1027 (1 << 13) - 811 - 117,
1028 (1 << 13) - 766 - 117,
1029 (1 << 13) - 737 - 117,
1030 (1 << 13) - 693 - 117,
1031 (1 << 13) - 648 - 117,
1032 (1 << 13) - 619 - 117,
1033 (1 << 13) - 575 - 117,
1034 (1 << 13) - 531 - 117,
1035 (1 << 13) - 501 - 117
1036};
1037static const u8 permu_seg[] = { 6, 5, 7, 4, 8, 3, 9, 2, 10, 1, 11, 0, 12 };
1038
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001039static void dib8000_set_channel(struct dib8000_state *state, u8 seq, u8 autosearching)
1040{
1041 u16 mode, max_constellation, seg_diff_mask = 0, nbseg_diff = 0;
1042 u8 guard, crate, constellation, timeI;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001043 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 -03001044 const s16 *ncoeff = NULL, *ana_fe;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001045 u16 tmcc_pow = 0;
1046 u16 coff_pow = 0x2800;
1047 u16 init_prbs = 0xfff;
1048 u16 ana_gain = 0;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001049
1050 if (state->ber_monitored_layer != LAYER_ALL)
1051 dib8000_write_word(state, 285, (dib8000_read_word(state, 285) & 0x60) | state->ber_monitored_layer);
1052 else
1053 dib8000_write_word(state, 285, dib8000_read_word(state, 285) & 0x60);
1054
1055 i = dib8000_read_word(state, 26) & 1; // P_dds_invspec
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001056 dib8000_write_word(state, 26, state->fe[0]->dtv_property_cache.inversion^i);
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001057
Olivier Grenie4c70e072011-01-03 15:33:37 -03001058 if (state->fe[0]->dtv_property_cache.isdbt_sb_mode) {
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001059 //compute new dds_freq for the seg and adjust prbs
1060 int seg_offset =
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001061 state->fe[0]->dtv_property_cache.isdbt_sb_segment_idx -
1062 (state->fe[0]->dtv_property_cache.isdbt_sb_segment_count / 2) -
Olivier Grenie4c70e072011-01-03 15:33:37 -03001063 (state->fe[0]->dtv_property_cache.isdbt_sb_segment_count % 2);
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001064 int clk = state->cfg.pll->internal;
1065 u32 segtodds = ((u32) (430 << 23) / clk) << 3; // segtodds = SegBW / Fclk * pow(2,26)
1066 int dds_offset = seg_offset * segtodds;
1067 int new_dds, sub_channel;
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001068 if ((state->fe[0]->dtv_property_cache.isdbt_sb_segment_count % 2) == 0)
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001069 dds_offset -= (int)(segtodds / 2);
1070
1071 if (state->cfg.pll->ifreq == 0) {
Olivier Grenie4c70e072011-01-03 15:33:37 -03001072 if ((state->fe[0]->dtv_property_cache.inversion ^ i) == 0) {
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001073 dib8000_write_word(state, 26, dib8000_read_word(state, 26) | 1);
1074 new_dds = dds_offset;
1075 } else
1076 new_dds = dds_offset;
1077
1078 // We shift tuning frequency if the wanted segment is :
1079 // - the segment of center frequency with an odd total number of segments
1080 // - the segment to the left of center frequency with an even total number of segments
1081 // - the segment to the right of center frequency with an even total number of segments
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001082 if ((state->fe[0]->dtv_property_cache.delivery_system == SYS_ISDBT)
1083 && (state->fe[0]->dtv_property_cache.isdbt_sb_mode == 1)
Olivier Grenie4c70e072011-01-03 15:33:37 -03001084 && (((state->fe[0]->dtv_property_cache.isdbt_sb_segment_count % 2)
1085 && (state->fe[0]->dtv_property_cache.isdbt_sb_segment_idx ==
1086 ((state->fe[0]->dtv_property_cache.isdbt_sb_segment_count / 2) + 1)))
1087 || (((state->fe[0]->dtv_property_cache.isdbt_sb_segment_count % 2) == 0)
1088 && (state->fe[0]->dtv_property_cache.isdbt_sb_segment_idx == (state->fe[0]->dtv_property_cache.isdbt_sb_segment_count / 2)))
1089 || (((state->fe[0]->dtv_property_cache.isdbt_sb_segment_count % 2) == 0)
1090 && (state->fe[0]->dtv_property_cache.isdbt_sb_segment_idx ==
1091 ((state->fe[0]->dtv_property_cache.isdbt_sb_segment_count / 2) + 1)))
1092 )) {
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001093 new_dds -= ((u32) (850 << 22) / clk) << 4; // new_dds = 850 (freq shift in KHz) / Fclk * pow(2,26)
1094 }
1095 } else {
Olivier Grenie4c70e072011-01-03 15:33:37 -03001096 if ((state->fe[0]->dtv_property_cache.inversion ^ i) == 0)
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001097 new_dds = state->cfg.pll->ifreq - dds_offset;
1098 else
1099 new_dds = state->cfg.pll->ifreq + dds_offset;
1100 }
1101 dib8000_write_word(state, 27, (u16) ((new_dds >> 16) & 0x01ff));
1102 dib8000_write_word(state, 28, (u16) (new_dds & 0xffff));
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001103 if (state->fe[0]->dtv_property_cache.isdbt_sb_segment_count % 2)
Olivier Grenie4c70e072011-01-03 15:33:37 -03001104 sub_channel = ((state->fe[0]->dtv_property_cache.isdbt_sb_subchannel + (3 * seg_offset) + 1) % 41) / 3;
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001105 else
Olivier Grenie4c70e072011-01-03 15:33:37 -03001106 sub_channel = ((state->fe[0]->dtv_property_cache.isdbt_sb_subchannel + (3 * seg_offset)) % 41) / 3;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001107 sub_channel -= 6;
1108
Olivier Grenie4c70e072011-01-03 15:33:37 -03001109 if (state->fe[0]->dtv_property_cache.transmission_mode == TRANSMISSION_MODE_2K
1110 || state->fe[0]->dtv_property_cache.transmission_mode == TRANSMISSION_MODE_4K) {
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001111 dib8000_write_word(state, 219, dib8000_read_word(state, 219) | 0x1); //adp_pass =1
1112 dib8000_write_word(state, 190, dib8000_read_word(state, 190) | (0x1 << 14)); //pha3_force_pha_shift = 1
1113 } else {
1114 dib8000_write_word(state, 219, dib8000_read_word(state, 219) & 0xfffe); //adp_pass =0
1115 dib8000_write_word(state, 190, dib8000_read_word(state, 190) & 0xbfff); //pha3_force_pha_shift = 0
1116 }
1117
Olivier Grenie4c70e072011-01-03 15:33:37 -03001118 switch (state->fe[0]->dtv_property_cache.transmission_mode) {
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001119 case TRANSMISSION_MODE_2K:
1120 switch (sub_channel) {
1121 case -6:
1122 init_prbs = 0x0;
1123 break; // 41, 0, 1
1124 case -5:
1125 init_prbs = 0x423;
1126 break; // 02~04
1127 case -4:
1128 init_prbs = 0x9;
1129 break; // 05~07
1130 case -3:
1131 init_prbs = 0x5C7;
1132 break; // 08~10
1133 case -2:
1134 init_prbs = 0x7A6;
1135 break; // 11~13
1136 case -1:
1137 init_prbs = 0x3D8;
1138 break; // 14~16
1139 case 0:
1140 init_prbs = 0x527;
1141 break; // 17~19
1142 case 1:
1143 init_prbs = 0x7FF;
1144 break; // 20~22
1145 case 2:
1146 init_prbs = 0x79B;
1147 break; // 23~25
1148 case 3:
1149 init_prbs = 0x3D6;
1150 break; // 26~28
1151 case 4:
1152 init_prbs = 0x3A2;
1153 break; // 29~31
1154 case 5:
1155 init_prbs = 0x53B;
1156 break; // 32~34
1157 case 6:
1158 init_prbs = 0x2F4;
1159 break; // 35~37
1160 default:
1161 case 7:
1162 init_prbs = 0x213;
1163 break; // 38~40
1164 }
1165 break;
1166
1167 case TRANSMISSION_MODE_4K:
1168 switch (sub_channel) {
1169 case -6:
1170 init_prbs = 0x0;
1171 break; // 41, 0, 1
1172 case -5:
1173 init_prbs = 0x208;
1174 break; // 02~04
1175 case -4:
1176 init_prbs = 0xC3;
1177 break; // 05~07
1178 case -3:
1179 init_prbs = 0x7B9;
1180 break; // 08~10
1181 case -2:
1182 init_prbs = 0x423;
1183 break; // 11~13
1184 case -1:
1185 init_prbs = 0x5C7;
1186 break; // 14~16
1187 case 0:
1188 init_prbs = 0x3D8;
1189 break; // 17~19
1190 case 1:
1191 init_prbs = 0x7FF;
1192 break; // 20~22
1193 case 2:
1194 init_prbs = 0x3D6;
1195 break; // 23~25
1196 case 3:
1197 init_prbs = 0x53B;
1198 break; // 26~28
1199 case 4:
1200 init_prbs = 0x213;
1201 break; // 29~31
1202 case 5:
1203 init_prbs = 0x29;
1204 break; // 32~34
1205 case 6:
1206 init_prbs = 0xD0;
1207 break; // 35~37
1208 default:
1209 case 7:
1210 init_prbs = 0x48E;
1211 break; // 38~40
1212 }
1213 break;
1214
1215 default:
1216 case TRANSMISSION_MODE_8K:
1217 switch (sub_channel) {
1218 case -6:
1219 init_prbs = 0x0;
1220 break; // 41, 0, 1
1221 case -5:
1222 init_prbs = 0x740;
1223 break; // 02~04
1224 case -4:
1225 init_prbs = 0x069;
1226 break; // 05~07
1227 case -3:
1228 init_prbs = 0x7DD;
1229 break; // 08~10
1230 case -2:
1231 init_prbs = 0x208;
1232 break; // 11~13
1233 case -1:
1234 init_prbs = 0x7B9;
1235 break; // 14~16
1236 case 0:
1237 init_prbs = 0x5C7;
1238 break; // 17~19
1239 case 1:
1240 init_prbs = 0x7FF;
1241 break; // 20~22
1242 case 2:
1243 init_prbs = 0x53B;
1244 break; // 23~25
1245 case 3:
1246 init_prbs = 0x29;
1247 break; // 26~28
1248 case 4:
1249 init_prbs = 0x48E;
1250 break; // 29~31
1251 case 5:
1252 init_prbs = 0x4C4;
1253 break; // 32~34
1254 case 6:
1255 init_prbs = 0x367;
1256 break; // 33~37
1257 default:
1258 case 7:
1259 init_prbs = 0x684;
1260 break; // 38~40
1261 }
1262 break;
1263 }
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001264 } else {
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001265 dib8000_write_word(state, 27, (u16) ((state->cfg.pll->ifreq >> 16) & 0x01ff));
1266 dib8000_write_word(state, 28, (u16) (state->cfg.pll->ifreq & 0xffff));
1267 dib8000_write_word(state, 26, (u16) ((state->cfg.pll->ifreq >> 25) & 0x0003));
1268 }
1269 /*P_mode == ?? */
1270 dib8000_write_word(state, 10, (seq << 4));
1271 // dib8000_write_word(state, 287, (dib8000_read_word(state, 287) & 0xe000) | 0x1000);
1272
Olivier Grenie4c70e072011-01-03 15:33:37 -03001273 switch (state->fe[0]->dtv_property_cache.guard_interval) {
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001274 case GUARD_INTERVAL_1_32:
1275 guard = 0;
1276 break;
1277 case GUARD_INTERVAL_1_16:
1278 guard = 1;
1279 break;
1280 case GUARD_INTERVAL_1_8:
1281 guard = 2;
1282 break;
1283 case GUARD_INTERVAL_1_4:
1284 default:
1285 guard = 3;
1286 break;
1287 }
1288
1289 dib8000_write_word(state, 1, (init_prbs << 2) | (guard & 0x3)); // ADDR 1
1290
1291 max_constellation = DQPSK;
1292 for (i = 0; i < 3; i++) {
Olivier Grenie4c70e072011-01-03 15:33:37 -03001293 switch (state->fe[0]->dtv_property_cache.layer[i].modulation) {
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001294 case DQPSK:
1295 constellation = 0;
1296 break;
1297 case QPSK:
1298 constellation = 1;
1299 break;
1300 case QAM_16:
1301 constellation = 2;
1302 break;
1303 case QAM_64:
1304 default:
1305 constellation = 3;
1306 break;
1307 }
1308
Olivier Grenie4c70e072011-01-03 15:33:37 -03001309 switch (state->fe[0]->dtv_property_cache.layer[i].fec) {
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001310 case FEC_1_2:
1311 crate = 1;
1312 break;
1313 case FEC_2_3:
1314 crate = 2;
1315 break;
1316 case FEC_3_4:
1317 crate = 3;
1318 break;
1319 case FEC_5_6:
1320 crate = 5;
1321 break;
1322 case FEC_7_8:
1323 default:
1324 crate = 7;
1325 break;
1326 }
1327
Olivier Grenie4c70e072011-01-03 15:33:37 -03001328 if ((state->fe[0]->dtv_property_cache.layer[i].interleaving > 0) &&
1329 ((state->fe[0]->dtv_property_cache.layer[i].interleaving <= 3) ||
1330 (state->fe[0]->dtv_property_cache.layer[i].interleaving == 4 && state->fe[0]->dtv_property_cache.isdbt_sb_mode == 1))
1331 )
1332 timeI = state->fe[0]->dtv_property_cache.layer[i].interleaving;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001333 else
1334 timeI = 0;
Olivier Grenie4c70e072011-01-03 15:33:37 -03001335 dib8000_write_word(state, 2 + i, (constellation << 10) | ((state->fe[0]->dtv_property_cache.layer[i].segment_count & 0xf) << 6) |
1336 (crate << 3) | timeI);
1337 if (state->fe[0]->dtv_property_cache.layer[i].segment_count > 0) {
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001338 switch (max_constellation) {
1339 case DQPSK:
1340 case QPSK:
Olivier Grenie4c70e072011-01-03 15:33:37 -03001341 if (state->fe[0]->dtv_property_cache.layer[i].modulation == QAM_16 ||
1342 state->fe[0]->dtv_property_cache.layer[i].modulation == QAM_64)
1343 max_constellation = state->fe[0]->dtv_property_cache.layer[i].modulation;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001344 break;
1345 case QAM_16:
Olivier Grenie4c70e072011-01-03 15:33:37 -03001346 if (state->fe[0]->dtv_property_cache.layer[i].modulation == QAM_64)
1347 max_constellation = state->fe[0]->dtv_property_cache.layer[i].modulation;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001348 break;
1349 }
1350 }
1351 }
1352
1353 mode = fft_to_mode(state);
1354
1355 //dib8000_write_word(state, 5, 13); /*p_last_seg = 13*/
1356
1357 dib8000_write_word(state, 274, (dib8000_read_word(state, 274) & 0xffcf) |
Olivier Grenie4c70e072011-01-03 15:33:37 -03001358 ((state->fe[0]->dtv_property_cache.isdbt_partial_reception & 1) << 5) | ((state->fe[0]->dtv_property_cache.
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001359 isdbt_sb_mode & 1) << 4));
1360
Olivier Grenie4c70e072011-01-03 15:33:37 -03001361 dprintk("mode = %d ; guard = %d", mode, state->fe[0]->dtv_property_cache.guard_interval);
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001362
1363 /* signal optimization parameter */
1364
Olivier Grenie4c70e072011-01-03 15:33:37 -03001365 if (state->fe[0]->dtv_property_cache.isdbt_partial_reception) {
1366 seg_diff_mask = (state->fe[0]->dtv_property_cache.layer[0].modulation == DQPSK) << permu_seg[0];
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001367 for (i = 1; i < 3; i++)
1368 nbseg_diff +=
Olivier Grenie4c70e072011-01-03 15:33:37 -03001369 (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 -03001370 for (i = 0; i < nbseg_diff; i++)
1371 seg_diff_mask |= 1 << permu_seg[i + 1];
1372 } else {
1373 for (i = 0; i < 3; i++)
1374 nbseg_diff +=
Olivier Grenie4c70e072011-01-03 15:33:37 -03001375 (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 -03001376 for (i = 0; i < nbseg_diff; i++)
1377 seg_diff_mask |= 1 << permu_seg[i];
1378 }
1379 dprintk("nbseg_diff = %X (%d)", seg_diff_mask, seg_diff_mask);
1380
1381 state->differential_constellation = (seg_diff_mask != 0);
Olivier Grenie4c70e072011-01-03 15:33:37 -03001382 dib8000_set_diversity_in(state->fe[0], state->diversity_onoff);
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001383
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001384 if (state->fe[0]->dtv_property_cache.isdbt_sb_mode == 1) {
1385 if (state->fe[0]->dtv_property_cache.isdbt_partial_reception == 1)
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001386 seg_mask13 = 0x00E0;
1387 else // 1-segment
1388 seg_mask13 = 0x0040;
1389 } else
1390 seg_mask13 = 0x1fff;
1391
1392 // WRITE: Mode & Diff mask
1393 dib8000_write_word(state, 0, (mode << 13) | seg_diff_mask);
1394
Olivier Grenie4c70e072011-01-03 15:33:37 -03001395 if ((seg_diff_mask) || (state->fe[0]->dtv_property_cache.isdbt_sb_mode))
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001396 dib8000_write_word(state, 268, (dib8000_read_word(state, 268) & 0xF9FF) | 0x0200);
1397 else
1398 dib8000_write_word(state, 268, (2 << 9) | 39); //init value
1399
1400 // ---- SMALL ----
1401 // P_small_seg_diff
1402 dib8000_write_word(state, 352, seg_diff_mask); // ADDR 352
1403
1404 dib8000_write_word(state, 353, seg_mask13); // ADDR 353
1405
Olivier Grenie4c70e072011-01-03 15:33:37 -03001406/* // P_small_narrow_band=0, P_small_last_seg=13, P_small_offset_num_car=5 */
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001407
1408 // ---- SMALL ----
Olivier Grenie4c70e072011-01-03 15:33:37 -03001409 if (state->fe[0]->dtv_property_cache.isdbt_sb_mode == 1) {
1410 switch (state->fe[0]->dtv_property_cache.transmission_mode) {
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001411 case TRANSMISSION_MODE_2K:
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001412 if (state->fe[0]->dtv_property_cache.isdbt_partial_reception == 0) {
1413 if (state->fe[0]->dtv_property_cache.layer[0].modulation == DQPSK)
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001414 ncoeff = coeff_2k_sb_1seg_dqpsk;
1415 else // QPSK or QAM
1416 ncoeff = coeff_2k_sb_1seg;
1417 } else { // 3-segments
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001418 if (state->fe[0]->dtv_property_cache.layer[0].modulation == DQPSK) {
1419 if (state->fe[0]->dtv_property_cache.layer[1].modulation == DQPSK)
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001420 ncoeff = coeff_2k_sb_3seg_0dqpsk_1dqpsk;
1421 else // QPSK or QAM on external segments
1422 ncoeff = coeff_2k_sb_3seg_0dqpsk;
1423 } else { // QPSK or QAM on central segment
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001424 if (state->fe[0]->dtv_property_cache.layer[1].modulation == DQPSK)
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001425 ncoeff = coeff_2k_sb_3seg_1dqpsk;
1426 else // QPSK or QAM on external segments
1427 ncoeff = coeff_2k_sb_3seg;
1428 }
1429 }
1430 break;
1431
1432 case TRANSMISSION_MODE_4K:
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001433 if (state->fe[0]->dtv_property_cache.isdbt_partial_reception == 0) {
1434 if (state->fe[0]->dtv_property_cache.layer[0].modulation == DQPSK)
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001435 ncoeff = coeff_4k_sb_1seg_dqpsk;
1436 else // QPSK or QAM
1437 ncoeff = coeff_4k_sb_1seg;
1438 } else { // 3-segments
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001439 if (state->fe[0]->dtv_property_cache.layer[0].modulation == DQPSK) {
1440 if (state->fe[0]->dtv_property_cache.layer[1].modulation == DQPSK) {
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001441 ncoeff = coeff_4k_sb_3seg_0dqpsk_1dqpsk;
1442 } else { // QPSK or QAM on external segments
1443 ncoeff = coeff_4k_sb_3seg_0dqpsk;
1444 }
1445 } else { // QPSK or QAM on central segment
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001446 if (state->fe[0]->dtv_property_cache.layer[1].modulation == DQPSK) {
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001447 ncoeff = coeff_4k_sb_3seg_1dqpsk;
1448 } else // QPSK or QAM on external segments
1449 ncoeff = coeff_4k_sb_3seg;
1450 }
1451 }
1452 break;
1453
1454 case TRANSMISSION_MODE_AUTO:
1455 case TRANSMISSION_MODE_8K:
1456 default:
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001457 if (state->fe[0]->dtv_property_cache.isdbt_partial_reception == 0) {
1458 if (state->fe[0]->dtv_property_cache.layer[0].modulation == DQPSK)
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001459 ncoeff = coeff_8k_sb_1seg_dqpsk;
1460 else // QPSK or QAM
1461 ncoeff = coeff_8k_sb_1seg;
1462 } else { // 3-segments
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001463 if (state->fe[0]->dtv_property_cache.layer[0].modulation == DQPSK) {
1464 if (state->fe[0]->dtv_property_cache.layer[1].modulation == DQPSK) {
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001465 ncoeff = coeff_8k_sb_3seg_0dqpsk_1dqpsk;
1466 } else { // QPSK or QAM on external segments
1467 ncoeff = coeff_8k_sb_3seg_0dqpsk;
1468 }
1469 } else { // QPSK or QAM on central segment
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001470 if (state->fe[0]->dtv_property_cache.layer[1].modulation == DQPSK) {
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001471 ncoeff = coeff_8k_sb_3seg_1dqpsk;
1472 } else // QPSK or QAM on external segments
1473 ncoeff = coeff_8k_sb_3seg;
1474 }
1475 }
1476 break;
1477 }
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001478 for (i = 0; i < 8; i++)
1479 dib8000_write_word(state, 343 + i, ncoeff[i]);
Márton Németh6e8fdbd2009-11-22 18:52:37 -03001480 }
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001481
1482 // P_small_coef_ext_enable=ISDB-Tsb, P_small_narrow_band=ISDB-Tsb, P_small_last_seg=13, P_small_offset_num_car=5
1483 dib8000_write_word(state, 351,
Olivier Grenie4c70e072011-01-03 15:33:37 -03001484 (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 -03001485
1486 // ---- COFF ----
1487 // Carloff, the most robust
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001488 if (state->fe[0]->dtv_property_cache.isdbt_sb_mode == 1) {
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001489
1490 // P_coff_cpil_alpha=4, P_coff_inh=0, P_coff_cpil_winlen=64
1491 // 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
1492 dib8000_write_word(state, 187,
Olivier Grenie4c70e072011-01-03 15:33:37 -03001493 (4 << 12) | (0 << 11) | (63 << 5) | (0x3 << 3) | ((~state->fe[0]->dtv_property_cache.isdbt_partial_reception & 1) << 2)
1494 | 0x3);
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001495
Olivier Grenie4c70e072011-01-03 15:33:37 -03001496/* // P_small_coef_ext_enable = 1 */
1497/* dib8000_write_word(state, 351, dib8000_read_word(state, 351) | 0x200); */
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001498
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001499 if (state->fe[0]->dtv_property_cache.isdbt_partial_reception == 0) {
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001500
1501 // 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)
1502 if (mode == 3)
1503 dib8000_write_word(state, 180, 0x1fcf | ((mode - 1) << 14));
1504 else
1505 dib8000_write_word(state, 180, 0x0fcf | ((mode - 1) << 14));
1506 // P_ctrl_corm_thres4pre_freq_inh=1,P_ctrl_pre_freq_mode_sat=1,
1507 // P_ctrl_pre_freq_inh=0, P_ctrl_pre_freq_step = 5, P_pre_freq_win_len=4
1508 dib8000_write_word(state, 338, (1 << 12) | (1 << 10) | (0 << 9) | (5 << 5) | 4);
1509 // P_ctrl_pre_freq_win_len=16, P_ctrl_pre_freq_thres_lockin=8
1510 dib8000_write_word(state, 340, (16 << 6) | (8 << 0));
1511 // P_ctrl_pre_freq_thres_lockout=6, P_small_use_tmcc/ac/cp=1
1512 dib8000_write_word(state, 341, (6 << 3) | (1 << 2) | (1 << 1) | (1 << 0));
1513
1514 // P_coff_corthres_8k, 4k, 2k and P_coff_cpilthres_8k, 4k, 2k
1515 dib8000_write_word(state, 181, 300);
1516 dib8000_write_word(state, 182, 150);
1517 dib8000_write_word(state, 183, 80);
1518 dib8000_write_word(state, 184, 300);
1519 dib8000_write_word(state, 185, 150);
1520 dib8000_write_word(state, 186, 80);
1521 } else { // Sound Broadcasting mode 3 seg
1522 // 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 -03001523 /* if (mode == 3) */
1524 /* dib8000_write_word(state, 180, 0x2fca | ((0) << 14)); */
1525 /* else */
1526 /* dib8000_write_word(state, 180, 0x2fca | ((1) << 14)); */
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001527 dib8000_write_word(state, 180, 0x1fcf | (1 << 14));
1528
1529 // P_ctrl_corm_thres4pre_freq_inh = 1, P_ctrl_pre_freq_mode_sat=1,
1530 // P_ctrl_pre_freq_inh=0, P_ctrl_pre_freq_step = 4, P_pre_freq_win_len=4
1531 dib8000_write_word(state, 338, (1 << 12) | (1 << 10) | (0 << 9) | (4 << 5) | 4);
1532 // P_ctrl_pre_freq_win_len=16, P_ctrl_pre_freq_thres_lockin=8
1533 dib8000_write_word(state, 340, (16 << 6) | (8 << 0));
1534 //P_ctrl_pre_freq_thres_lockout=6, P_small_use_tmcc/ac/cp=1
1535 dib8000_write_word(state, 341, (6 << 3) | (1 << 2) | (1 << 1) | (1 << 0));
1536
1537 // P_coff_corthres_8k, 4k, 2k and P_coff_cpilthres_8k, 4k, 2k
1538 dib8000_write_word(state, 181, 350);
1539 dib8000_write_word(state, 182, 300);
1540 dib8000_write_word(state, 183, 250);
1541 dib8000_write_word(state, 184, 350);
1542 dib8000_write_word(state, 185, 300);
1543 dib8000_write_word(state, 186, 250);
1544 }
1545
1546 } else if (state->isdbt_cfg_loaded == 0) { // if not Sound Broadcasting mode : put default values for 13 segments
1547 dib8000_write_word(state, 180, (16 << 6) | 9);
1548 dib8000_write_word(state, 187, (4 << 12) | (8 << 5) | 0x2);
1549 coff_pow = 0x2800;
1550 for (i = 0; i < 6; i++)
1551 dib8000_write_word(state, 181 + i, coff_pow);
1552
1553 // P_ctrl_corm_thres4pre_freq_inh=1, P_ctrl_pre_freq_mode_sat=1,
1554 // 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
1555 dib8000_write_word(state, 338, (1 << 12) | (1 << 10) | (0 << 9) | (3 << 5) | 1);
1556
1557 // P_ctrl_pre_freq_win_len=8, P_ctrl_pre_freq_thres_lockin=6
1558 dib8000_write_word(state, 340, (8 << 6) | (6 << 0));
1559 // P_ctrl_pre_freq_thres_lockout=4, P_small_use_tmcc/ac/cp=1
1560 dib8000_write_word(state, 341, (4 << 3) | (1 << 2) | (1 << 1) | (1 << 0));
1561 }
1562 // ---- FFT ----
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001563 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 -03001564 dib8000_write_word(state, 178, 64); // P_fft_powrange=64
1565 else
1566 dib8000_write_word(state, 178, 32); // P_fft_powrange=32
1567
1568 /* make the cpil_coff_lock more robust but slower p_coff_winlen
1569 * 6bits; p_coff_thres_lock 6bits (for coff lock if needed)
1570 */
1571 /* if ( ( nbseg_diff>0)&&(nbseg_diff<13))
Olivier Grenie4c70e072011-01-03 15:33:37 -03001572 dib8000_write_word(state, 187, (dib8000_read_word(state, 187) & 0xfffb) | (1 << 3)); */
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001573
1574 dib8000_write_word(state, 189, ~seg_mask13 | seg_diff_mask); /* P_lmod4_seg_inh */
1575 dib8000_write_word(state, 192, ~seg_mask13 | seg_diff_mask); /* P_pha3_seg_inh */
1576 dib8000_write_word(state, 225, ~seg_mask13 | seg_diff_mask); /* P_tac_seg_inh */
Olivier Grenie4c70e072011-01-03 15:33:37 -03001577 if ((!state->fe[0]->dtv_property_cache.isdbt_sb_mode) && (state->cfg.pll->ifreq == 0))
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001578 dib8000_write_word(state, 266, ~seg_mask13 | seg_diff_mask | 0x40); /* P_equal_noise_seg_inh */
1579 else
1580 dib8000_write_word(state, 266, ~seg_mask13 | seg_diff_mask); /* P_equal_noise_seg_inh */
1581 dib8000_write_word(state, 287, ~seg_mask13 | 0x1000); /* P_tmcc_seg_inh */
1582 //dib8000_write_word(state, 288, ~seg_mask13 | seg_diff_mask); /* P_tmcc_seg_eq_inh */
1583 if (!autosearching)
1584 dib8000_write_word(state, 288, (~seg_mask13 | seg_diff_mask) & 0x1fff); /* P_tmcc_seg_eq_inh */
1585 else
1586 dib8000_write_word(state, 288, 0x1fff); //disable equalisation of the tmcc when autosearch to be able to find the DQPSK channels.
1587 dprintk("287 = %X (%d)", ~seg_mask13 | 0x1000, ~seg_mask13 | 0x1000);
1588
1589 dib8000_write_word(state, 211, seg_mask13 & (~seg_diff_mask)); /* P_des_seg_enabled */
1590
1591 /* offset loop parameters */
Olivier Grenie4c70e072011-01-03 15:33:37 -03001592 if (state->fe[0]->dtv_property_cache.isdbt_sb_mode == 1) {
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001593 if (state->fe[0]->dtv_property_cache.isdbt_partial_reception == 0)
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001594 /* P_timf_alpha = (11-P_mode), P_corm_alpha=6, P_corm_thres=0x80 */
1595 dib8000_write_word(state, 32, ((11 - mode) << 12) | (6 << 8) | 0x40);
1596
1597 else // Sound Broadcasting mode 3 seg
1598 /* P_timf_alpha = (10-P_mode), P_corm_alpha=6, P_corm_thres=0x80 */
1599 dib8000_write_word(state, 32, ((10 - mode) << 12) | (6 << 8) | 0x60);
1600 } else
1601 // TODO in 13 seg, timf_alpha can always be the same or not ?
1602 /* P_timf_alpha = (9-P_mode, P_corm_alpha=6, P_corm_thres=0x80 */
1603 dib8000_write_word(state, 32, ((9 - mode) << 12) | (6 << 8) | 0x80);
1604
Olivier Grenie4c70e072011-01-03 15:33:37 -03001605 if (state->fe[0]->dtv_property_cache.isdbt_sb_mode == 1) {
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001606 if (state->fe[0]->dtv_property_cache.isdbt_partial_reception == 0)
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001607 /* P_ctrl_pha_off_max=3 P_ctrl_sfreq_inh =0 P_ctrl_sfreq_step = (11-P_mode) */
1608 dib8000_write_word(state, 37, (3 << 5) | (0 << 4) | (10 - mode));
1609
1610 else // Sound Broadcasting mode 3 seg
1611 /* P_ctrl_pha_off_max=3 P_ctrl_sfreq_inh =0 P_ctrl_sfreq_step = (10-P_mode) */
1612 dib8000_write_word(state, 37, (3 << 5) | (0 << 4) | (9 - mode));
1613 } else
1614 /* P_ctrl_pha_off_max=3 P_ctrl_sfreq_inh =0 P_ctrl_sfreq_step = 9 */
1615 dib8000_write_word(state, 37, (3 << 5) | (0 << 4) | (8 - mode));
1616
1617 /* P_dvsy_sync_wait - reuse mode */
Olivier Grenie4c70e072011-01-03 15:33:37 -03001618 switch (state->fe[0]->dtv_property_cache.transmission_mode) {
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001619 case TRANSMISSION_MODE_8K:
1620 mode = 256;
1621 break;
1622 case TRANSMISSION_MODE_4K:
1623 mode = 128;
1624 break;
1625 default:
1626 case TRANSMISSION_MODE_2K:
1627 mode = 64;
1628 break;
1629 }
1630 if (state->cfg.diversity_delay == 0)
1631 mode = (mode * (1 << (guard)) * 3) / 2 + 48; // add 50% SFN margin + compensate for one DVSY-fifo
1632 else
1633 mode = (mode * (1 << (guard)) * 3) / 2 + state->cfg.diversity_delay; // add 50% SFN margin + compensate for DVSY-fifo
1634 mode <<= 4;
1635 dib8000_write_word(state, 273, (dib8000_read_word(state, 273) & 0x000f) | mode);
1636
1637 /* channel estimation fine configuration */
1638 switch (max_constellation) {
1639 case QAM_64:
1640 ana_gain = 0x7; // -1 : avoid def_est saturation when ADC target is -16dB
1641 coeff[0] = 0x0148; /* P_adp_regul_cnt 0.04 */
1642 coeff[1] = 0xfff0; /* P_adp_noise_cnt -0.002 */
1643 coeff[2] = 0x00a4; /* P_adp_regul_ext 0.02 */
1644 coeff[3] = 0xfff8; /* P_adp_noise_ext -0.001 */
1645 //if (!state->cfg.hostbus_diversity) //if diversity, we should prehaps use the configuration of the max_constallation -1
1646 break;
1647 case QAM_16:
1648 ana_gain = 0x7; // -1 : avoid def_est saturation when ADC target is -16dB
1649 coeff[0] = 0x023d; /* P_adp_regul_cnt 0.07 */
1650 coeff[1] = 0xffdf; /* P_adp_noise_cnt -0.004 */
1651 coeff[2] = 0x00a4; /* P_adp_regul_ext 0.02 */
1652 coeff[3] = 0xfff0; /* P_adp_noise_ext -0.002 */
1653 //if (!((state->cfg.hostbus_diversity) && (max_constellation == QAM_16)))
1654 break;
1655 default:
1656 ana_gain = 0; // 0 : goes along with ADC target at -22dB to keep good mobile performance and lock at sensitivity level
1657 coeff[0] = 0x099a; /* P_adp_regul_cnt 0.3 */
1658 coeff[1] = 0xffae; /* P_adp_noise_cnt -0.01 */
1659 coeff[2] = 0x0333; /* P_adp_regul_ext 0.1 */
1660 coeff[3] = 0xfff8; /* P_adp_noise_ext -0.002 */
1661 break;
1662 }
1663 for (mode = 0; mode < 4; mode++)
1664 dib8000_write_word(state, 215 + mode, coeff[mode]);
1665
1666 // update ana_gain depending on max constellation
1667 dib8000_write_word(state, 116, ana_gain);
1668 // update ADC target depending on ana_gain
1669 if (ana_gain) { // set -16dB ADC target for ana_gain=-1
1670 for (i = 0; i < 10; i++)
1671 dib8000_write_word(state, 80 + i, adc_target_16dB[i]);
1672 } else { // set -22dB ADC target for ana_gain=0
1673 for (i = 0; i < 10; i++)
1674 dib8000_write_word(state, 80 + i, adc_target_16dB[i] - 355);
1675 }
1676
1677 // ---- ANA_FE ----
Olivier Grenie4c70e072011-01-03 15:33:37 -03001678 if (state->fe[0]->dtv_property_cache.isdbt_sb_mode) {
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001679 if (state->fe[0]->dtv_property_cache.isdbt_partial_reception == 1)
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001680 ana_fe = ana_fe_coeff_3seg;
1681 else // 1-segment
1682 ana_fe = ana_fe_coeff_1seg;
1683 } else
1684 ana_fe = ana_fe_coeff_13seg;
1685
Olivier Grenie4c70e072011-01-03 15:33:37 -03001686 if (state->fe[0]->dtv_property_cache.isdbt_sb_mode == 1 || state->isdbt_cfg_loaded == 0)
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001687 for (mode = 0; mode < 24; mode++)
1688 dib8000_write_word(state, 117 + mode, ana_fe[mode]);
1689
1690 // ---- CHAN_BLK ----
1691 for (i = 0; i < 13; i++) {
1692 if ((((~seg_diff_mask) >> i) & 1) == 1) {
1693 P_cfr_left_edge += (1 << i) * ((i == 0) || ((((seg_mask13 & (~seg_diff_mask)) >> (i - 1)) & 1) == 0));
1694 P_cfr_right_edge += (1 << i) * ((i == 12) || ((((seg_mask13 & (~seg_diff_mask)) >> (i + 1)) & 1) == 0));
1695 }
1696 }
1697 dib8000_write_word(state, 222, P_cfr_left_edge); // P_cfr_left_edge
1698 dib8000_write_word(state, 223, P_cfr_right_edge); // P_cfr_right_edge
1699 // "P_cspu_left_edge" not used => do not care
1700 // "P_cspu_right_edge" not used => do not care
1701
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001702 if (state->fe[0]->dtv_property_cache.isdbt_sb_mode == 1) {
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001703 dib8000_write_word(state, 228, 1); // P_2d_mode_byp=1
1704 dib8000_write_word(state, 205, dib8000_read_word(state, 205) & 0xfff0); // P_cspu_win_cut = 0
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001705 if (state->fe[0]->dtv_property_cache.isdbt_partial_reception == 0
Olivier Grenie4c70e072011-01-03 15:33:37 -03001706 && state->fe[0]->dtv_property_cache.transmission_mode == TRANSMISSION_MODE_2K) {
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001707 //dib8000_write_word(state, 219, dib8000_read_word(state, 219) & 0xfffe); // P_adp_pass = 0
1708 dib8000_write_word(state, 265, 15); // P_equal_noise_sel = 15
1709 }
1710 } else if (state->isdbt_cfg_loaded == 0) {
1711 dib8000_write_word(state, 228, 0); // default value
1712 dib8000_write_word(state, 265, 31); // default value
1713 dib8000_write_word(state, 205, 0x200f); // init value
1714 }
1715 // ---- TMCC ----
1716 for (i = 0; i < 3; i++)
1717 tmcc_pow +=
Olivier Grenie4c70e072011-01-03 15:33:37 -03001718 (((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 -03001719 // Quantif of "P_tmcc_dec_thres_?k" is (0, 5+mode, 9);
1720 // Threshold is set at 1/4 of max power.
1721 tmcc_pow *= (1 << (9 - 2));
1722
1723 dib8000_write_word(state, 290, tmcc_pow); // P_tmcc_dec_thres_2k
1724 dib8000_write_word(state, 291, tmcc_pow); // P_tmcc_dec_thres_4k
1725 dib8000_write_word(state, 292, tmcc_pow); // P_tmcc_dec_thres_8k
1726 //dib8000_write_word(state, 287, (1 << 13) | 0x1000 );
1727 // ---- PHA3 ----
1728
1729 if (state->isdbt_cfg_loaded == 0)
1730 dib8000_write_word(state, 250, 3285); /*p_2d_hspeed_thr0 */
1731
Olivier Grenie4c70e072011-01-03 15:33:37 -03001732 if (state->fe[0]->dtv_property_cache.isdbt_sb_mode == 1)
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001733 state->isdbt_cfg_loaded = 0;
1734 else
1735 state->isdbt_cfg_loaded = 1;
1736
1737}
1738
1739static int dib8000_autosearch_start(struct dvb_frontend *fe)
1740{
1741 u8 factor;
1742 u32 value;
1743 struct dib8000_state *state = fe->demodulator_priv;
1744
1745 int slist = 0;
1746
Olivier Grenie4c70e072011-01-03 15:33:37 -03001747 state->fe[0]->dtv_property_cache.inversion = 0;
1748 if (!state->fe[0]->dtv_property_cache.isdbt_sb_mode)
1749 state->fe[0]->dtv_property_cache.layer[0].segment_count = 13;
1750 state->fe[0]->dtv_property_cache.layer[0].modulation = QAM_64;
1751 state->fe[0]->dtv_property_cache.layer[0].fec = FEC_2_3;
1752 state->fe[0]->dtv_property_cache.layer[0].interleaving = 0;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001753
1754 //choose the right list, in sb, always do everything
Olivier Grenie4c70e072011-01-03 15:33:37 -03001755 if (state->fe[0]->dtv_property_cache.isdbt_sb_mode) {
1756 state->fe[0]->dtv_property_cache.transmission_mode = TRANSMISSION_MODE_8K;
1757 state->fe[0]->dtv_property_cache.guard_interval = GUARD_INTERVAL_1_8;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001758 slist = 7;
1759 dib8000_write_word(state, 0, (dib8000_read_word(state, 0) & 0x9fff) | (1 << 13));
1760 } else {
Olivier Grenie4c70e072011-01-03 15:33:37 -03001761 if (state->fe[0]->dtv_property_cache.guard_interval == GUARD_INTERVAL_AUTO) {
1762 if (state->fe[0]->dtv_property_cache.transmission_mode == TRANSMISSION_MODE_AUTO) {
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001763 slist = 7;
1764 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 -03001765 } else
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001766 slist = 3;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001767 } else {
Olivier Grenie4c70e072011-01-03 15:33:37 -03001768 if (state->fe[0]->dtv_property_cache.transmission_mode == TRANSMISSION_MODE_AUTO) {
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001769 slist = 2;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001770 dib8000_write_word(state, 0, (dib8000_read_word(state, 0) & 0x9fff) | (1 << 13)); // P_mode = 1
Patrick Boettcher78f3bc62009-08-17 12:53:51 -03001771 } else
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001772 slist = 0;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001773 }
1774
Olivier Grenie4c70e072011-01-03 15:33:37 -03001775 if (state->fe[0]->dtv_property_cache.transmission_mode == TRANSMISSION_MODE_AUTO)
1776 state->fe[0]->dtv_property_cache.transmission_mode = TRANSMISSION_MODE_8K;
1777 if (state->fe[0]->dtv_property_cache.guard_interval == GUARD_INTERVAL_AUTO)
1778 state->fe[0]->dtv_property_cache.guard_interval = GUARD_INTERVAL_1_8;
Patrick Boettcher78f3bc62009-08-17 12:53:51 -03001779
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001780 dprintk("using list for autosearch : %d", slist);
1781 dib8000_set_channel(state, (unsigned char)slist, 1);
1782 //dib8000_write_word(state, 0, (dib8000_read_word(state, 0) & 0x9fff) | (1 << 13)); // P_mode = 1
1783
1784 factor = 1;
1785
1786 //set lock_mask values
1787 dib8000_write_word(state, 6, 0x4);
1788 dib8000_write_word(state, 7, 0x8);
1789 dib8000_write_word(state, 8, 0x1000);
1790
1791 //set lock_mask wait time values
1792 value = 50 * state->cfg.pll->internal * factor;
1793 dib8000_write_word(state, 11, (u16) ((value >> 16) & 0xffff)); // lock0 wait time
1794 dib8000_write_word(state, 12, (u16) (value & 0xffff)); // lock0 wait time
1795 value = 100 * state->cfg.pll->internal * factor;
1796 dib8000_write_word(state, 13, (u16) ((value >> 16) & 0xffff)); // lock1 wait time
1797 dib8000_write_word(state, 14, (u16) (value & 0xffff)); // lock1 wait time
1798 value = 1000 * state->cfg.pll->internal * factor;
1799 dib8000_write_word(state, 15, (u16) ((value >> 16) & 0xffff)); // lock2 wait time
1800 dib8000_write_word(state, 16, (u16) (value & 0xffff)); // lock2 wait time
1801
1802 value = dib8000_read_word(state, 0);
1803 dib8000_write_word(state, 0, (u16) ((1 << 15) | value));
1804 dib8000_read_word(state, 1284); // reset the INT. n_irq_pending
1805 dib8000_write_word(state, 0, (u16) value);
Patrick Boettcher78f3bc62009-08-17 12:53:51 -03001806
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001807 }
1808
1809 return 0;
1810}
1811
1812static int dib8000_autosearch_irq(struct dvb_frontend *fe)
1813{
1814 struct dib8000_state *state = fe->demodulator_priv;
1815 u16 irq_pending = dib8000_read_word(state, 1284);
1816
1817 if (irq_pending & 0x1) { // failed
1818 dprintk("dib8000_autosearch_irq failed");
1819 return 1;
1820 }
1821
1822 if (irq_pending & 0x2) { // succeeded
1823 dprintk("dib8000_autosearch_irq succeeded");
1824 return 2;
1825 }
1826
1827 return 0; // still pending
1828}
1829
1830static int dib8000_tune(struct dvb_frontend *fe)
1831{
1832 struct dib8000_state *state = fe->demodulator_priv;
1833 int ret = 0;
1834 u16 value, mode = fft_to_mode(state);
1835
1836 // we are already tuned - just resuming from suspend
1837 if (state == NULL)
1838 return -EINVAL;
1839
Olivier Grenie4c70e072011-01-03 15:33:37 -03001840 dib8000_set_bandwidth(fe, state->fe[0]->dtv_property_cache.bandwidth_hz / 1000);
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001841 dib8000_set_channel(state, 0, 0);
1842
1843 // restart demod
1844 ret |= dib8000_write_word(state, 770, 0x4000);
1845 ret |= dib8000_write_word(state, 770, 0x0000);
1846 msleep(45);
1847
1848 /* P_ctrl_inh_cor=0, P_ctrl_alpha_cor=4, P_ctrl_inh_isi=0, P_ctrl_alpha_isi=3 */
1849 /* ret |= dib8000_write_word(state, 29, (0 << 9) | (4 << 5) | (0 << 4) | (3 << 0) ); workaround inh_isi stays at 1 */
1850
1851 // never achieved a lock before - wait for timfreq to update
1852 if (state->timf == 0) {
Olivier Grenie4c70e072011-01-03 15:33:37 -03001853 if (state->fe[0]->dtv_property_cache.isdbt_sb_mode == 1) {
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001854 if (state->fe[0]->dtv_property_cache.isdbt_partial_reception == 0)
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001855 msleep(300);
1856 else // Sound Broadcasting mode 3 seg
1857 msleep(500);
1858 } else // 13 seg
1859 msleep(200);
1860 }
Olivier Grenie4c70e072011-01-03 15:33:37 -03001861 if (state->fe[0]->dtv_property_cache.isdbt_sb_mode == 1) {
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001862 if (state->fe[0]->dtv_property_cache.isdbt_partial_reception == 0) {
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001863
1864 /* P_timf_alpha = (13-P_mode) , P_corm_alpha=6, P_corm_thres=0x40 alpha to check on board */
1865 dib8000_write_word(state, 32, ((13 - mode) << 12) | (6 << 8) | 0x40);
1866 //dib8000_write_word(state, 32, (8 << 12) | (6 << 8) | 0x80);
1867
1868 /* P_ctrl_sfreq_step= (12-P_mode) P_ctrl_sfreq_inh =0 P_ctrl_pha_off_max */
1869 ret |= dib8000_write_word(state, 37, (12 - mode) | ((5 + mode) << 5));
1870
1871 } else { // Sound Broadcasting mode 3 seg
1872
1873 /* P_timf_alpha = (12-P_mode) , P_corm_alpha=6, P_corm_thres=0x60 alpha to check on board */
1874 dib8000_write_word(state, 32, ((12 - mode) << 12) | (6 << 8) | 0x60);
1875
1876 ret |= dib8000_write_word(state, 37, (11 - mode) | ((5 + mode) << 5));
1877 }
1878
1879 } else { // 13 seg
1880 /* P_timf_alpha = 8 , P_corm_alpha=6, P_corm_thres=0x80 alpha to check on board */
1881 dib8000_write_word(state, 32, ((11 - mode) << 12) | (6 << 8) | 0x80);
1882
1883 ret |= dib8000_write_word(state, 37, (10 - mode) | ((5 + mode) << 5));
1884
1885 }
1886
1887 // we achieved a coff_cpil_lock - it's time to update the timf
1888 if ((dib8000_read_word(state, 568) >> 11) & 0x1)
1889 dib8000_update_timf(state);
1890
1891 //now that tune is finished, lock0 should lock on fec_mpeg to output this lock on MP_LOCK. It's changed in autosearch start
1892 dib8000_write_word(state, 6, 0x200);
1893
1894 if (state->revision == 0x8002) {
1895 value = dib8000_read_word(state, 903);
1896 dib8000_write_word(state, 903, value & ~(1 << 3));
1897 msleep(1);
1898 dib8000_write_word(state, 903, value | (1 << 3));
1899 }
1900
1901 return ret;
1902}
1903
1904static int dib8000_wakeup(struct dvb_frontend *fe)
1905{
1906 struct dib8000_state *state = fe->demodulator_priv;
Olivier Grenie4c70e072011-01-03 15:33:37 -03001907 u8 index_frontend;
1908 int ret;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001909
1910 dib8000_set_power_mode(state, DIB8000M_POWER_ALL);
1911 dib8000_set_adc_state(state, DIBX000_ADC_ON);
1912 if (dib8000_set_adc_state(state, DIBX000_SLOW_ADC_ON) != 0)
1913 dprintk("could not start Slow ADC");
1914
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001915 for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
Olivier Grenie4c70e072011-01-03 15:33:37 -03001916 ret = state->fe[index_frontend]->ops.init(state->fe[index_frontend]);
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001917 if (ret < 0)
Olivier Grenie4c70e072011-01-03 15:33:37 -03001918 return ret;
1919 }
1920
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001921 return 0;
1922}
1923
1924static int dib8000_sleep(struct dvb_frontend *fe)
1925{
Olivier Grenie4c70e072011-01-03 15:33:37 -03001926 struct dib8000_state *state = fe->demodulator_priv;
1927 u8 index_frontend;
1928 int ret;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001929
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001930 for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
Olivier Grenie4c70e072011-01-03 15:33:37 -03001931 ret = state->fe[index_frontend]->ops.sleep(state->fe[index_frontend]);
1932 if (ret < 0)
1933 return ret;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001934 }
Olivier Grenie4c70e072011-01-03 15:33:37 -03001935
1936 dib8000_set_output_mode(fe, OUTMODE_HIGH_Z);
1937 dib8000_set_power_mode(state, DIB8000M_POWER_INTERFACE_ONLY);
1938 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 -03001939}
1940
Olivier Grenie9c783032009-12-07 07:49:40 -03001941enum frontend_tune_state dib8000_get_tune_state(struct dvb_frontend *fe)
Olivier Grenie03245a52009-12-04 13:27:57 -03001942{
1943 struct dib8000_state *state = fe->demodulator_priv;
1944 return state->tune_state;
1945}
1946EXPORT_SYMBOL(dib8000_get_tune_state);
1947
Olivier Grenie9c783032009-12-07 07:49:40 -03001948int dib8000_set_tune_state(struct dvb_frontend *fe, enum frontend_tune_state tune_state)
Olivier Grenie03245a52009-12-04 13:27:57 -03001949{
1950 struct dib8000_state *state = fe->demodulator_priv;
1951 state->tune_state = tune_state;
1952 return 0;
1953}
1954EXPORT_SYMBOL(dib8000_set_tune_state);
1955
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001956static int dib8000_get_frontend(struct dvb_frontend *fe, struct dvb_frontend_parameters *fep)
1957{
1958 struct dib8000_state *state = fe->demodulator_priv;
1959 u16 i, val = 0;
Olivier Grenie4c70e072011-01-03 15:33:37 -03001960 fe_status_t stat;
1961 u8 index_frontend, sub_index_frontend;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001962
1963 fe->dtv_property_cache.bandwidth_hz = 6000000;
1964
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001965 for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
Olivier Grenie4c70e072011-01-03 15:33:37 -03001966 state->fe[index_frontend]->ops.read_status(state->fe[index_frontend], &stat);
1967 if (stat&FE_HAS_SYNC) {
1968 dprintk("TMCC lock on the slave%i", index_frontend);
1969 /* synchronize the cache with the other frontends */
1970 state->fe[index_frontend]->ops.get_frontend(state->fe[index_frontend], fep);
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001971 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 -03001972 if (sub_index_frontend != index_frontend) {
1973 state->fe[sub_index_frontend]->dtv_property_cache.isdbt_sb_mode = state->fe[index_frontend]->dtv_property_cache.isdbt_sb_mode;
1974 state->fe[sub_index_frontend]->dtv_property_cache.inversion = state->fe[index_frontend]->dtv_property_cache.inversion;
1975 state->fe[sub_index_frontend]->dtv_property_cache.transmission_mode = state->fe[index_frontend]->dtv_property_cache.transmission_mode;
1976 state->fe[sub_index_frontend]->dtv_property_cache.guard_interval = state->fe[index_frontend]->dtv_property_cache.guard_interval;
1977 state->fe[sub_index_frontend]->dtv_property_cache.isdbt_partial_reception = state->fe[index_frontend]->dtv_property_cache.isdbt_partial_reception;
1978 for (i = 0; i < 3; i++) {
1979 state->fe[sub_index_frontend]->dtv_property_cache.layer[i].segment_count = state->fe[index_frontend]->dtv_property_cache.layer[i].segment_count;
1980 state->fe[sub_index_frontend]->dtv_property_cache.layer[i].interleaving = state->fe[index_frontend]->dtv_property_cache.layer[i].interleaving;
1981 state->fe[sub_index_frontend]->dtv_property_cache.layer[i].fec = state->fe[index_frontend]->dtv_property_cache.layer[i].fec;
1982 state->fe[sub_index_frontend]->dtv_property_cache.layer[i].modulation = state->fe[index_frontend]->dtv_property_cache.layer[i].modulation;
1983 }
1984 }
1985 }
1986 return 0;
1987 }
1988 }
1989
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001990 fe->dtv_property_cache.isdbt_sb_mode = dib8000_read_word(state, 508) & 0x1;
1991
1992 val = dib8000_read_word(state, 570);
1993 fe->dtv_property_cache.inversion = (val & 0x40) >> 6;
1994 switch ((val & 0x30) >> 4) {
1995 case 1:
1996 fe->dtv_property_cache.transmission_mode = TRANSMISSION_MODE_2K;
1997 break;
1998 case 3:
1999 default:
2000 fe->dtv_property_cache.transmission_mode = TRANSMISSION_MODE_8K;
2001 break;
2002 }
2003
2004 switch (val & 0x3) {
2005 case 0:
2006 fe->dtv_property_cache.guard_interval = GUARD_INTERVAL_1_32;
2007 dprintk("dib8000_get_frontend GI = 1/32 ");
2008 break;
2009 case 1:
2010 fe->dtv_property_cache.guard_interval = GUARD_INTERVAL_1_16;
2011 dprintk("dib8000_get_frontend GI = 1/16 ");
2012 break;
2013 case 2:
2014 dprintk("dib8000_get_frontend GI = 1/8 ");
2015 fe->dtv_property_cache.guard_interval = GUARD_INTERVAL_1_8;
2016 break;
2017 case 3:
2018 dprintk("dib8000_get_frontend GI = 1/4 ");
2019 fe->dtv_property_cache.guard_interval = GUARD_INTERVAL_1_4;
2020 break;
2021 }
2022
2023 val = dib8000_read_word(state, 505);
2024 fe->dtv_property_cache.isdbt_partial_reception = val & 1;
2025 dprintk("dib8000_get_frontend : partial_reception = %d ", fe->dtv_property_cache.isdbt_partial_reception);
2026
2027 for (i = 0; i < 3; i++) {
2028 val = dib8000_read_word(state, 493 + i);
2029 fe->dtv_property_cache.layer[i].segment_count = val & 0x0F;
2030 dprintk("dib8000_get_frontend : Layer %d segments = %d ", i, fe->dtv_property_cache.layer[i].segment_count);
2031
2032 val = dib8000_read_word(state, 499 + i);
2033 fe->dtv_property_cache.layer[i].interleaving = val & 0x3;
2034 dprintk("dib8000_get_frontend : Layer %d time_intlv = %d ", i, fe->dtv_property_cache.layer[i].interleaving);
2035
2036 val = dib8000_read_word(state, 481 + i);
2037 switch (val & 0x7) {
2038 case 1:
2039 fe->dtv_property_cache.layer[i].fec = FEC_1_2;
2040 dprintk("dib8000_get_frontend : Layer %d Code Rate = 1/2 ", i);
2041 break;
2042 case 2:
2043 fe->dtv_property_cache.layer[i].fec = FEC_2_3;
2044 dprintk("dib8000_get_frontend : Layer %d Code Rate = 2/3 ", i);
2045 break;
2046 case 3:
2047 fe->dtv_property_cache.layer[i].fec = FEC_3_4;
2048 dprintk("dib8000_get_frontend : Layer %d Code Rate = 3/4 ", i);
2049 break;
2050 case 5:
2051 fe->dtv_property_cache.layer[i].fec = FEC_5_6;
2052 dprintk("dib8000_get_frontend : Layer %d Code Rate = 5/6 ", i);
2053 break;
2054 default:
2055 fe->dtv_property_cache.layer[i].fec = FEC_7_8;
2056 dprintk("dib8000_get_frontend : Layer %d Code Rate = 7/8 ", i);
2057 break;
2058 }
2059
2060 val = dib8000_read_word(state, 487 + i);
2061 switch (val & 0x3) {
2062 case 0:
2063 dprintk("dib8000_get_frontend : Layer %d DQPSK ", i);
2064 fe->dtv_property_cache.layer[i].modulation = DQPSK;
2065 break;
2066 case 1:
2067 fe->dtv_property_cache.layer[i].modulation = QPSK;
2068 dprintk("dib8000_get_frontend : Layer %d QPSK ", i);
2069 break;
2070 case 2:
2071 fe->dtv_property_cache.layer[i].modulation = QAM_16;
2072 dprintk("dib8000_get_frontend : Layer %d QAM16 ", i);
2073 break;
2074 case 3:
2075 default:
2076 dprintk("dib8000_get_frontend : Layer %d QAM64 ", i);
2077 fe->dtv_property_cache.layer[i].modulation = QAM_64;
2078 break;
2079 }
2080 }
Olivier Grenie4c70e072011-01-03 15:33:37 -03002081
2082 /* synchronize the cache with the other frontends */
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002083 for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
Olivier Grenie4c70e072011-01-03 15:33:37 -03002084 state->fe[index_frontend]->dtv_property_cache.isdbt_sb_mode = fe->dtv_property_cache.isdbt_sb_mode;
2085 state->fe[index_frontend]->dtv_property_cache.inversion = fe->dtv_property_cache.inversion;
2086 state->fe[index_frontend]->dtv_property_cache.transmission_mode = fe->dtv_property_cache.transmission_mode;
2087 state->fe[index_frontend]->dtv_property_cache.guard_interval = fe->dtv_property_cache.guard_interval;
2088 state->fe[index_frontend]->dtv_property_cache.isdbt_partial_reception = fe->dtv_property_cache.isdbt_partial_reception;
2089 for (i = 0; i < 3; i++) {
2090 state->fe[index_frontend]->dtv_property_cache.layer[i].segment_count = fe->dtv_property_cache.layer[i].segment_count;
2091 state->fe[index_frontend]->dtv_property_cache.layer[i].interleaving = fe->dtv_property_cache.layer[i].interleaving;
2092 state->fe[index_frontend]->dtv_property_cache.layer[i].fec = fe->dtv_property_cache.layer[i].fec;
2093 state->fe[index_frontend]->dtv_property_cache.layer[i].modulation = fe->dtv_property_cache.layer[i].modulation;
2094 }
2095 }
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002096 return 0;
2097}
2098
2099static int dib8000_set_frontend(struct dvb_frontend *fe, struct dvb_frontend_parameters *fep)
2100{
2101 struct dib8000_state *state = fe->demodulator_priv;
Olivier Grenie4c70e072011-01-03 15:33:37 -03002102 u8 nbr_pending, exit_condition, index_frontend;
2103 s8 index_frontend_success = -1;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002104 int time, ret;
Olivier Grenie4c70e072011-01-03 15:33:37 -03002105 int time_slave = FE_CALLBACK_TIME_NEVER;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002106
Olivier Grenie4c70e072011-01-03 15:33:37 -03002107 if (state->fe[0]->dtv_property_cache.frequency == 0) {
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002108 dprintk("dib8000: must at least specify frequency ");
2109 return 0;
2110 }
2111
Olivier Grenie4c70e072011-01-03 15:33:37 -03002112 if (state->fe[0]->dtv_property_cache.bandwidth_hz == 0) {
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002113 dprintk("dib8000: no bandwidth specified, set to default ");
Olivier Grenie4c70e072011-01-03 15:33:37 -03002114 state->fe[0]->dtv_property_cache.bandwidth_hz = 6000000;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002115 }
2116
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002117 for (index_frontend = 0; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
Olivier Grenie4c70e072011-01-03 15:33:37 -03002118 /* synchronization of the cache */
2119 state->fe[index_frontend]->dtv_property_cache.delivery_system = SYS_ISDBT;
2120 memcpy(&state->fe[index_frontend]->dtv_property_cache, &fe->dtv_property_cache, sizeof(struct dtv_frontend_properties));
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002121
Olivier Grenie4c70e072011-01-03 15:33:37 -03002122 dib8000_set_output_mode(state->fe[index_frontend], OUTMODE_HIGH_Z);
2123 if (state->fe[index_frontend]->ops.tuner_ops.set_params)
2124 state->fe[index_frontend]->ops.tuner_ops.set_params(state->fe[index_frontend], fep);
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002125
Olivier Grenie4c70e072011-01-03 15:33:37 -03002126 dib8000_set_tune_state(state->fe[index_frontend], CT_AGC_START);
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002127 }
2128
Olivier Grenie4c70e072011-01-03 15:33:37 -03002129 /* start up the AGC */
2130 do {
2131 time = dib8000_agc_startup(state->fe[0]);
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002132 for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
Olivier Grenie4c70e072011-01-03 15:33:37 -03002133 time_slave = dib8000_agc_startup(state->fe[index_frontend]);
2134 if (time == FE_CALLBACK_TIME_NEVER)
2135 time = time_slave;
2136 else if ((time_slave != FE_CALLBACK_TIME_NEVER) && (time_slave > time))
2137 time = time_slave;
2138 }
2139 if (time != FE_CALLBACK_TIME_NEVER)
2140 msleep(time / 10);
2141 else
2142 break;
2143 exit_condition = 1;
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002144 for (index_frontend = 0; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
Olivier Grenie4c70e072011-01-03 15:33:37 -03002145 if (dib8000_get_tune_state(state->fe[index_frontend]) != CT_AGC_STOP) {
2146 exit_condition = 0;
2147 break;
2148 }
2149 }
2150 } while (exit_condition == 0);
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002151
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002152 for (index_frontend = 0; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++)
Olivier Grenie4c70e072011-01-03 15:33:37 -03002153 dib8000_set_tune_state(state->fe[index_frontend], CT_DEMOD_START);
2154
2155 if ((state->fe[0]->dtv_property_cache.delivery_system != SYS_ISDBT) ||
2156 (state->fe[0]->dtv_property_cache.inversion == INVERSION_AUTO) ||
2157 (state->fe[0]->dtv_property_cache.transmission_mode == TRANSMISSION_MODE_AUTO) ||
2158 (state->fe[0]->dtv_property_cache.guard_interval == GUARD_INTERVAL_AUTO) ||
2159 (((state->fe[0]->dtv_property_cache.isdbt_layer_enabled & (1 << 0)) != 0) &&
2160 (state->fe[0]->dtv_property_cache.layer[0].segment_count != 0xff) &&
2161 (state->fe[0]->dtv_property_cache.layer[0].segment_count != 0) &&
2162 ((state->fe[0]->dtv_property_cache.layer[0].modulation == QAM_AUTO) ||
2163 (state->fe[0]->dtv_property_cache.layer[0].fec == FEC_AUTO))) ||
2164 (((state->fe[0]->dtv_property_cache.isdbt_layer_enabled & (1 << 1)) != 0) &&
2165 (state->fe[0]->dtv_property_cache.layer[1].segment_count != 0xff) &&
2166 (state->fe[0]->dtv_property_cache.layer[1].segment_count != 0) &&
2167 ((state->fe[0]->dtv_property_cache.layer[1].modulation == QAM_AUTO) ||
2168 (state->fe[0]->dtv_property_cache.layer[1].fec == FEC_AUTO))) ||
2169 (((state->fe[0]->dtv_property_cache.isdbt_layer_enabled & (1 << 2)) != 0) &&
2170 (state->fe[0]->dtv_property_cache.layer[2].segment_count != 0xff) &&
2171 (state->fe[0]->dtv_property_cache.layer[2].segment_count != 0) &&
2172 ((state->fe[0]->dtv_property_cache.layer[2].modulation == QAM_AUTO) ||
2173 (state->fe[0]->dtv_property_cache.layer[2].fec == FEC_AUTO))) ||
2174 (((state->fe[0]->dtv_property_cache.layer[0].segment_count == 0) ||
2175 ((state->fe[0]->dtv_property_cache.isdbt_layer_enabled & (1 << 0)) == 0)) &&
2176 ((state->fe[0]->dtv_property_cache.layer[1].segment_count == 0) ||
2177 ((state->fe[0]->dtv_property_cache.isdbt_layer_enabled & (2 << 0)) == 0)) &&
2178 ((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 -02002179 int i = 80000;
2180 u8 found = 0;
2181 u8 tune_failed = 0;
Olivier Grenie4c70e072011-01-03 15:33:37 -03002182
Mauro Carvalho Chehab2c2c4412011-01-16 13:02:52 -02002183 for (index_frontend = 0; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
2184 dib8000_set_bandwidth(state->fe[index_frontend], fe->dtv_property_cache.bandwidth_hz / 1000);
2185 dib8000_autosearch_start(state->fe[index_frontend]);
2186 }
Olivier Grenie4c70e072011-01-03 15:33:37 -03002187
Mauro Carvalho Chehab2c2c4412011-01-16 13:02:52 -02002188 do {
2189 msleep(20);
2190 nbr_pending = 0;
2191 exit_condition = 0; /* 0: tune pending; 1: tune failed; 2:tune success */
2192 for (index_frontend = 0; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
2193 if (((tune_failed >> index_frontend) & 0x1) == 0) {
2194 found = dib8000_autosearch_irq(state->fe[index_frontend]);
2195 switch (found) {
2196 case 0: /* tune pending */
2197 nbr_pending++;
2198 break;
2199 case 2:
2200 dprintk("autosearch succeed on the frontend%i", index_frontend);
2201 exit_condition = 2;
2202 index_frontend_success = index_frontend;
2203 break;
2204 default:
2205 dprintk("unhandled autosearch result");
2206 case 1:
2207 dprintk("autosearch failed for the frontend%i", index_frontend);
2208 break;
2209 }
2210 }
2211 }
Olivier Grenie4c70e072011-01-03 15:33:37 -03002212
Mauro Carvalho Chehab2c2c4412011-01-16 13:02:52 -02002213 /* if all tune are done and no success, exit: tune failed */
2214 if ((nbr_pending == 0) && (exit_condition == 0))
2215 exit_condition = 1;
2216 } while ((exit_condition == 0) && i--);
Olivier Grenie4c70e072011-01-03 15:33:37 -03002217
Mauro Carvalho Chehab2c2c4412011-01-16 13:02:52 -02002218 if (exit_condition == 1) { /* tune failed */
2219 dprintk("tune failed");
2220 return 0;
2221 }
Olivier Grenie4c70e072011-01-03 15:33:37 -03002222
Mauro Carvalho Chehab2c2c4412011-01-16 13:02:52 -02002223 dprintk("tune success on frontend%i", index_frontend_success);
Olivier Grenie4c70e072011-01-03 15:33:37 -03002224
Mauro Carvalho Chehab2c2c4412011-01-16 13:02:52 -02002225 dib8000_get_frontend(fe, fep);
2226 }
Olivier Grenie4c70e072011-01-03 15:33:37 -03002227
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002228 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 -03002229 ret = dib8000_tune(state->fe[index_frontend]);
Olivier Grenie4c70e072011-01-03 15:33:37 -03002230
2231 /* set output mode and diversity input */
2232 dib8000_set_output_mode(state->fe[0], state->cfg.output_mode);
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002233 for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
Olivier Grenie4c70e072011-01-03 15:33:37 -03002234 dib8000_set_output_mode(state->fe[index_frontend], OUTMODE_DIVERSITY);
2235 dib8000_set_diversity_in(state->fe[index_frontend-1], 1);
2236 }
2237
2238 /* turn off the diversity of the last chip */
2239 dib8000_set_diversity_in(state->fe[index_frontend-1], 0);
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002240
2241 return ret;
2242}
2243
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002244static u16 dib8000_read_lock(struct dvb_frontend *fe)
2245{
Olivier Grenie4c70e072011-01-03 15:33:37 -03002246 struct dib8000_state *state = fe->demodulator_priv;
2247
2248 return dib8000_read_word(state, 568);
2249}
2250
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002251static int dib8000_read_status(struct dvb_frontend *fe, fe_status_t * stat)
2252{
2253 struct dib8000_state *state = fe->demodulator_priv;
Olivier Grenie4c70e072011-01-03 15:33:37 -03002254 u16 lock_slave = 0, lock = dib8000_read_word(state, 568);
2255 u8 index_frontend;
2256
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002257 for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++)
Olivier Grenie4c70e072011-01-03 15:33:37 -03002258 lock_slave |= dib8000_read_lock(state->fe[index_frontend]);
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002259
2260 *stat = 0;
2261
Olivier Grenie4c70e072011-01-03 15:33:37 -03002262 if (((lock >> 13) & 1) || ((lock_slave >> 13) & 1))
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002263 *stat |= FE_HAS_SIGNAL;
2264
Olivier Grenie4c70e072011-01-03 15:33:37 -03002265 if (((lock >> 8) & 1) || ((lock_slave >> 8) & 1)) /* Equal */
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002266 *stat |= FE_HAS_CARRIER;
2267
Olivier Grenie4c70e072011-01-03 15:33:37 -03002268 if ((((lock >> 1) & 0xf) == 0xf) || (((lock_slave >> 1) & 0xf) == 0xf)) /* TMCC_SYNC */
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002269 *stat |= FE_HAS_SYNC;
2270
Olivier Grenie4c70e072011-01-03 15:33:37 -03002271 if ((((lock >> 12) & 1) || ((lock_slave >> 12) & 1)) && ((lock >> 5) & 7)) /* FEC MPEG */
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002272 *stat |= FE_HAS_LOCK;
2273
Olivier Grenie4c70e072011-01-03 15:33:37 -03002274 if (((lock >> 12) & 1) || ((lock_slave >> 12) & 1)) {
Olivier Grenie89dfc552009-11-30 06:38:49 -03002275 lock = dib8000_read_word(state, 554); /* Viterbi Layer A */
2276 if (lock & 0x01)
2277 *stat |= FE_HAS_VITERBI;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002278
Olivier Grenie89dfc552009-11-30 06:38:49 -03002279 lock = dib8000_read_word(state, 555); /* Viterbi Layer B */
2280 if (lock & 0x01)
2281 *stat |= FE_HAS_VITERBI;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002282
Olivier Grenie89dfc552009-11-30 06:38:49 -03002283 lock = dib8000_read_word(state, 556); /* Viterbi Layer C */
2284 if (lock & 0x01)
2285 *stat |= FE_HAS_VITERBI;
2286 }
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002287
2288 return 0;
2289}
2290
2291static int dib8000_read_ber(struct dvb_frontend *fe, u32 * ber)
2292{
2293 struct dib8000_state *state = fe->demodulator_priv;
2294 *ber = (dib8000_read_word(state, 560) << 16) | dib8000_read_word(state, 561); // 13 segments
2295 return 0;
2296}
2297
2298static int dib8000_read_unc_blocks(struct dvb_frontend *fe, u32 * unc)
2299{
2300 struct dib8000_state *state = fe->demodulator_priv;
2301 *unc = dib8000_read_word(state, 565); // packet error on 13 seg
2302 return 0;
2303}
2304
2305static int dib8000_read_signal_strength(struct dvb_frontend *fe, u16 * strength)
2306{
2307 struct dib8000_state *state = fe->demodulator_priv;
Olivier Grenie4c70e072011-01-03 15:33:37 -03002308 u8 index_frontend;
2309 u16 val;
2310
2311 *strength = 0;
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002312 for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
Olivier Grenie4c70e072011-01-03 15:33:37 -03002313 state->fe[index_frontend]->ops.read_signal_strength(state->fe[index_frontend], &val);
2314 if (val > 65535 - *strength)
2315 *strength = 65535;
2316 else
2317 *strength += val;
2318 }
2319
2320 val = 65535 - dib8000_read_word(state, 390);
2321 if (val > 65535 - *strength)
2322 *strength = 65535;
2323 else
2324 *strength += val;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002325 return 0;
2326}
2327
Olivier Grenie4c70e072011-01-03 15:33:37 -03002328static u32 dib8000_get_snr(struct dvb_frontend *fe)
2329{
2330 struct dib8000_state *state = fe->demodulator_priv;
2331 u32 n, s, exp;
2332 u16 val;
2333
2334 val = dib8000_read_word(state, 542);
2335 n = (val >> 6) & 0xff;
2336 exp = (val & 0x3f);
2337 if ((exp & 0x20) != 0)
2338 exp -= 0x40;
2339 n <<= exp+16;
2340
2341 val = dib8000_read_word(state, 543);
2342 s = (val >> 6) & 0xff;
2343 exp = (val & 0x3f);
2344 if ((exp & 0x20) != 0)
2345 exp -= 0x40;
2346 s <<= exp+16;
2347
2348 if (n > 0) {
2349 u32 t = (s/n) << 16;
2350 return t + ((s << 16) - n*t) / n;
2351 }
2352 return 0xffffffff;
2353}
2354
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002355static int dib8000_read_snr(struct dvb_frontend *fe, u16 * snr)
2356{
2357 struct dib8000_state *state = fe->demodulator_priv;
Olivier Grenie4c70e072011-01-03 15:33:37 -03002358 u8 index_frontend;
2359 u32 snr_master;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002360
Olivier Grenie4c70e072011-01-03 15:33:37 -03002361 snr_master = dib8000_get_snr(fe);
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002362 for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++)
Olivier Grenie4c70e072011-01-03 15:33:37 -03002363 snr_master += dib8000_get_snr(state->fe[index_frontend]);
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002364
Olivier Grenie4c70e072011-01-03 15:33:37 -03002365 if (snr_master != 0) {
2366 snr_master = 10*intlog10(snr_master>>16);
2367 *snr = snr_master / ((1 << 24) / 10);
2368 }
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002369 else
Olivier Grenie4c70e072011-01-03 15:33:37 -03002370 *snr = 0;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002371
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002372 return 0;
2373}
2374
Olivier Grenie4c70e072011-01-03 15:33:37 -03002375int dib8000_set_slave_frontend(struct dvb_frontend *fe, struct dvb_frontend *fe_slave)
2376{
2377 struct dib8000_state *state = fe->demodulator_priv;
2378 u8 index_frontend = 1;
2379
2380 while ((index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL))
2381 index_frontend++;
2382 if (index_frontend < MAX_NUMBER_OF_FRONTENDS) {
2383 dprintk("set slave fe %p to index %i", fe_slave, index_frontend);
2384 state->fe[index_frontend] = fe_slave;
2385 return 0;
2386 }
2387
2388 dprintk("too many slave frontend");
2389 return -ENOMEM;
2390}
2391EXPORT_SYMBOL(dib8000_set_slave_frontend);
2392
2393int dib8000_remove_slave_frontend(struct dvb_frontend *fe)
2394{
2395 struct dib8000_state *state = fe->demodulator_priv;
2396 u8 index_frontend = 1;
2397
2398 while ((index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL))
2399 index_frontend++;
2400 if (index_frontend != 1) {
2401 dprintk("remove slave fe %p (index %i)", state->fe[index_frontend-1], index_frontend-1);
2402 state->fe[index_frontend] = NULL;
2403 return 0;
2404 }
2405
2406 dprintk("no frontend to be removed");
2407 return -ENODEV;
2408}
2409EXPORT_SYMBOL(dib8000_remove_slave_frontend);
2410
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002411struct dvb_frontend *dib8000_get_slave_frontend(struct dvb_frontend *fe, int slave_index)
Olivier Grenie4c70e072011-01-03 15:33:37 -03002412{
2413 struct dib8000_state *state = fe->demodulator_priv;
2414
2415 if (slave_index >= MAX_NUMBER_OF_FRONTENDS)
2416 return NULL;
2417 return state->fe[slave_index];
2418}
2419EXPORT_SYMBOL(dib8000_get_slave_frontend);
2420
2421
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002422int dib8000_i2c_enumeration(struct i2c_adapter *host, int no_of_demods, u8 default_addr, u8 first_addr)
2423{
Olivier Grenie5a0deee2011-05-03 12:27:33 -03002424 int k = 0, ret = 0;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002425 u8 new_addr = 0;
2426 struct i2c_device client = {.adap = host };
2427
Olivier Grenie5a0deee2011-05-03 12:27:33 -03002428 client.i2c_write_buffer = kzalloc(4 * sizeof(u8), GFP_KERNEL);
2429 if (!client.i2c_write_buffer) {
2430 dprintk("%s: not enough memory", __func__);
2431 return -ENOMEM;
2432 }
2433 client.i2c_read_buffer = kzalloc(4 * sizeof(u8), GFP_KERNEL);
2434 if (!client.i2c_read_buffer) {
2435 dprintk("%s: not enough memory", __func__);
2436 ret = -ENOMEM;
2437 goto error_memory;
2438 }
2439
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002440 for (k = no_of_demods - 1; k >= 0; k--) {
2441 /* designated i2c address */
2442 new_addr = first_addr + (k << 1);
2443
2444 client.addr = new_addr;
2445 dib8000_i2c_write16(&client, 1287, 0x0003); /* sram lead in, rdy */
2446 if (dib8000_identify(&client) == 0) {
2447 dib8000_i2c_write16(&client, 1287, 0x0003); /* sram lead in, rdy */
2448 client.addr = default_addr;
2449 if (dib8000_identify(&client) == 0) {
2450 dprintk("#%d: not identified", k);
Olivier Grenie5a0deee2011-05-03 12:27:33 -03002451 ret = -EINVAL;
2452 goto error;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002453 }
2454 }
2455
2456 /* start diversity to pull_down div_str - just for i2c-enumeration */
2457 dib8000_i2c_write16(&client, 1286, (1 << 10) | (4 << 6));
2458
2459 /* set new i2c address and force divstart */
2460 dib8000_i2c_write16(&client, 1285, (new_addr << 2) | 0x2);
2461 client.addr = new_addr;
2462 dib8000_identify(&client);
2463
2464 dprintk("IC %d initialized (to i2c_address 0x%x)", k, new_addr);
2465 }
2466
2467 for (k = 0; k < no_of_demods; k++) {
2468 new_addr = first_addr | (k << 1);
2469 client.addr = new_addr;
2470
2471 // unforce divstr
2472 dib8000_i2c_write16(&client, 1285, new_addr << 2);
2473
2474 /* deactivate div - it was just for i2c-enumeration */
2475 dib8000_i2c_write16(&client, 1286, 0);
2476 }
2477
Olivier Grenie5a0deee2011-05-03 12:27:33 -03002478error:
2479 kfree(client.i2c_read_buffer);
2480error_memory:
2481 kfree(client.i2c_write_buffer);
2482
2483 return ret;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002484}
2485
2486EXPORT_SYMBOL(dib8000_i2c_enumeration);
2487static int dib8000_fe_get_tune_settings(struct dvb_frontend *fe, struct dvb_frontend_tune_settings *tune)
2488{
2489 tune->min_delay_ms = 1000;
2490 tune->step_size = 0;
2491 tune->max_drift = 0;
2492 return 0;
2493}
2494
2495static void dib8000_release(struct dvb_frontend *fe)
2496{
2497 struct dib8000_state *st = fe->demodulator_priv;
Olivier Grenie4c70e072011-01-03 15:33:37 -03002498 u8 index_frontend;
2499
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002500 for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (st->fe[index_frontend] != NULL); index_frontend++)
Olivier Grenie4c70e072011-01-03 15:33:37 -03002501 dvb_frontend_detach(st->fe[index_frontend]);
2502
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002503 dibx000_exit_i2c_master(&st->i2c_master);
Olivier Grenie4c70e072011-01-03 15:33:37 -03002504 kfree(st->fe[0]);
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002505 kfree(st);
2506}
2507
2508struct i2c_adapter *dib8000_get_i2c_master(struct dvb_frontend *fe, enum dibx000_i2c_interface intf, int gating)
2509{
2510 struct dib8000_state *st = fe->demodulator_priv;
2511 return dibx000_get_i2c_adapter(&st->i2c_master, intf, gating);
2512}
2513
2514EXPORT_SYMBOL(dib8000_get_i2c_master);
2515
Olivier Grenief8731f42009-09-18 04:08:43 -03002516int dib8000_pid_filter_ctrl(struct dvb_frontend *fe, u8 onoff)
2517{
2518 struct dib8000_state *st = fe->demodulator_priv;
Olivier Grenie4c70e072011-01-03 15:33:37 -03002519 u16 val = dib8000_read_word(st, 299) & 0xffef;
2520 val |= (onoff & 0x1) << 4;
Olivier Grenief8731f42009-09-18 04:08:43 -03002521
Olivier Grenie4c70e072011-01-03 15:33:37 -03002522 dprintk("pid filter enabled %d", onoff);
2523 return dib8000_write_word(st, 299, val);
Olivier Grenief8731f42009-09-18 04:08:43 -03002524}
2525EXPORT_SYMBOL(dib8000_pid_filter_ctrl);
2526
2527int dib8000_pid_filter(struct dvb_frontend *fe, u8 id, u16 pid, u8 onoff)
2528{
2529 struct dib8000_state *st = fe->demodulator_priv;
Olivier Grenie4c70e072011-01-03 15:33:37 -03002530 dprintk("Index %x, PID %d, OnOff %d", id, pid, onoff);
2531 return dib8000_write_word(st, 305 + id, onoff ? (1 << 13) | pid : 0);
Olivier Grenief8731f42009-09-18 04:08:43 -03002532}
2533EXPORT_SYMBOL(dib8000_pid_filter);
2534
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002535static const struct dvb_frontend_ops dib8000_ops = {
2536 .info = {
2537 .name = "DiBcom 8000 ISDB-T",
2538 .type = FE_OFDM,
2539 .frequency_min = 44250000,
2540 .frequency_max = 867250000,
2541 .frequency_stepsize = 62500,
2542 .caps = FE_CAN_INVERSION_AUTO |
2543 FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
2544 FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
2545 FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO |
2546 FE_CAN_TRANSMISSION_MODE_AUTO | FE_CAN_GUARD_INTERVAL_AUTO | FE_CAN_RECOVER | FE_CAN_HIERARCHY_AUTO,
2547 },
2548
2549 .release = dib8000_release,
2550
2551 .init = dib8000_wakeup,
2552 .sleep = dib8000_sleep,
2553
2554 .set_frontend = dib8000_set_frontend,
2555 .get_tune_settings = dib8000_fe_get_tune_settings,
2556 .get_frontend = dib8000_get_frontend,
2557
2558 .read_status = dib8000_read_status,
2559 .read_ber = dib8000_read_ber,
2560 .read_signal_strength = dib8000_read_signal_strength,
2561 .read_snr = dib8000_read_snr,
2562 .read_ucblocks = dib8000_read_unc_blocks,
2563};
2564
2565struct dvb_frontend *dib8000_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr, struct dib8000_config *cfg)
2566{
2567 struct dvb_frontend *fe;
2568 struct dib8000_state *state;
2569
2570 dprintk("dib8000_attach");
2571
2572 state = kzalloc(sizeof(struct dib8000_state), GFP_KERNEL);
2573 if (state == NULL)
2574 return NULL;
Olivier Grenie4c70e072011-01-03 15:33:37 -03002575 fe = kzalloc(sizeof(struct dvb_frontend), GFP_KERNEL);
2576 if (fe == NULL)
Dan Carpentered54c0e2011-01-19 11:27:58 -03002577 goto error;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002578
2579 memcpy(&state->cfg, cfg, sizeof(struct dib8000_config));
2580 state->i2c.adap = i2c_adap;
2581 state->i2c.addr = i2c_addr;
Olivier Grenie5a0deee2011-05-03 12:27:33 -03002582 state->i2c.i2c_write_buffer = state->i2c_write_buffer;
2583 state->i2c.i2c_read_buffer = state->i2c_read_buffer;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002584 state->gpio_val = cfg->gpio_val;
2585 state->gpio_dir = cfg->gpio_dir;
2586
2587 /* Ensure the output mode remains at the previous default if it's
2588 * not specifically set by the caller.
2589 */
2590 if ((state->cfg.output_mode != OUTMODE_MPEG2_SERIAL) && (state->cfg.output_mode != OUTMODE_MPEG2_PAR_GATED_CLK))
2591 state->cfg.output_mode = OUTMODE_MPEG2_FIFO;
2592
Olivier Grenie4c70e072011-01-03 15:33:37 -03002593 state->fe[0] = fe;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002594 fe->demodulator_priv = state;
Olivier Grenie4c70e072011-01-03 15:33:37 -03002595 memcpy(&state->fe[0]->ops, &dib8000_ops, sizeof(struct dvb_frontend_ops));
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002596
2597 state->timf_default = cfg->pll->timf;
2598
2599 if (dib8000_identify(&state->i2c) == 0)
2600 goto error;
2601
2602 dibx000_init_i2c_master(&state->i2c_master, DIB8000, state->i2c.adap, state->i2c.addr);
2603
2604 dib8000_reset(fe);
2605
2606 dib8000_write_word(state, 285, (dib8000_read_word(state, 285) & ~0x60) | (3 << 5)); /* ber_rs_len = 3 */
2607
2608 return fe;
2609
2610 error:
2611 kfree(state);
2612 return NULL;
2613}
2614
2615EXPORT_SYMBOL(dib8000_attach);
2616
2617MODULE_AUTHOR("Olivier Grenie <Olivier.Grenie@dibcom.fr, " "Patrick Boettcher <pboettcher@dibcom.fr>");
2618MODULE_DESCRIPTION("Driver for the DiBcom 8000 ISDB-T demodulator");
2619MODULE_LICENSE("GPL");