blob: fe284d5292f5422f16a846e1077c7df34c576098 [file] [log] [blame]
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001/*
2 * Linux-DVB Driver for DiBcom's DiB8000 chip (ISDB-T).
3 *
4 * Copyright (C) 2009 DiBcom (http://www.dibcom.fr/)
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License as
8 * published by the Free Software Foundation, version 2.
9 */
10#include <linux/kernel.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090011#include <linux/slab.h>
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -030012#include <linux/i2c.h>
Patrick Boettcher79fcce32011-08-03 12:08:21 -030013#include <linux/mutex.h>
14
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -030015#include "dvb_math.h"
16
17#include "dvb_frontend.h"
18
19#include "dib8000.h"
20
21#define LAYER_ALL -1
22#define LAYER_A 1
23#define LAYER_B 2
24#define LAYER_C 3
25
26#define FE_CALLBACK_TIME_NEVER 0xffffffff
Olivier Grenie4c70e072011-01-03 15:33:37 -030027#define MAX_NUMBER_OF_FRONTENDS 6
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -030028
Patrick Boettcher78f3bc62009-08-17 12:53:51 -030029static int debug;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -030030module_param(debug, int, 0644);
31MODULE_PARM_DESC(debug, "turn on debugging (default: 0)");
32
33#define dprintk(args...) do { if (debug) { printk(KERN_DEBUG "DiB8000: "); printk(args); printk("\n"); } } while (0)
34
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -030035#define FE_STATUS_TUNE_FAILED 0
36
37struct i2c_device {
38 struct i2c_adapter *adap;
39 u8 addr;
Olivier Grenie5a0deee2011-05-03 12:27:33 -030040 u8 *i2c_write_buffer;
41 u8 *i2c_read_buffer;
Patrick Boettcher79fcce32011-08-03 12:08:21 -030042 struct mutex *i2c_buffer_lock;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -030043};
44
45struct dib8000_state {
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -030046 struct dib8000_config cfg;
47
48 struct i2c_device i2c;
49
50 struct dibx000_i2c_master i2c_master;
51
52 u16 wbd_ref;
53
54 u8 current_band;
55 u32 current_bandwidth;
56 struct dibx000_agc_config *current_agc;
57 u32 timf;
58 u32 timf_default;
59
60 u8 div_force_off:1;
61 u8 div_state:1;
62 u16 div_sync_wait;
63
64 u8 agc_state;
65 u8 differential_constellation;
66 u8 diversity_onoff;
67
68 s16 ber_monitored_layer;
69 u16 gpio_dir;
70 u16 gpio_val;
71
72 u16 revision;
73 u8 isdbt_cfg_loaded;
74 enum frontend_tune_state tune_state;
75 u32 status;
Olivier Grenie4c70e072011-01-03 15:33:37 -030076
77 struct dvb_frontend *fe[MAX_NUMBER_OF_FRONTENDS];
Olivier Grenie5a0deee2011-05-03 12:27:33 -030078
79 /* for the I2C transfer */
80 struct i2c_msg msg[2];
81 u8 i2c_write_buffer[4];
82 u8 i2c_read_buffer[2];
Patrick Boettcher79fcce32011-08-03 12:08:21 -030083 struct mutex i2c_buffer_lock;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -030084};
85
86enum dib8000_power_mode {
87 DIB8000M_POWER_ALL = 0,
88 DIB8000M_POWER_INTERFACE_ONLY,
89};
90
91static u16 dib8000_i2c_read16(struct i2c_device *i2c, u16 reg)
92{
Patrick Boettcher79fcce32011-08-03 12:08:21 -030093 u16 ret;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -030094 struct i2c_msg msg[2] = {
Patrick Boettcher79fcce32011-08-03 12:08:21 -030095 {.addr = i2c->addr >> 1, .flags = 0, .len = 2},
96 {.addr = i2c->addr >> 1, .flags = I2C_M_RD, .len = 2},
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -030097 };
98
Patrick Boettcher79fcce32011-08-03 12:08:21 -030099 if (mutex_lock_interruptible(i2c->i2c_buffer_lock) < 0) {
100 dprintk("could not acquire lock");
101 return 0;
102 }
103
104 msg[0].buf = i2c->i2c_write_buffer;
Olivier Grenie5a0deee2011-05-03 12:27:33 -0300105 msg[0].buf[0] = reg >> 8;
106 msg[0].buf[1] = reg & 0xff;
Patrick Boettcher79fcce32011-08-03 12:08:21 -0300107 msg[1].buf = i2c->i2c_read_buffer;
Olivier Grenie5a0deee2011-05-03 12:27:33 -0300108
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300109 if (i2c_transfer(i2c->adap, msg, 2) != 2)
110 dprintk("i2c read error on %d", reg);
111
Patrick Boettcher79fcce32011-08-03 12:08:21 -0300112 ret = (msg[1].buf[0] << 8) | msg[1].buf[1];
113 mutex_unlock(i2c->i2c_buffer_lock);
114 return ret;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300115}
116
117static u16 dib8000_read_word(struct dib8000_state *state, u16 reg)
118{
Patrick Boettcher79fcce32011-08-03 12:08:21 -0300119 u16 ret;
120
121 if (mutex_lock_interruptible(&state->i2c_buffer_lock) < 0) {
122 dprintk("could not acquire lock");
123 return 0;
124 }
125
Olivier Grenie5a0deee2011-05-03 12:27:33 -0300126 state->i2c_write_buffer[0] = reg >> 8;
127 state->i2c_write_buffer[1] = reg & 0xff;
128
129 memset(state->msg, 0, 2 * sizeof(struct i2c_msg));
130 state->msg[0].addr = state->i2c.addr >> 1;
131 state->msg[0].flags = 0;
132 state->msg[0].buf = state->i2c_write_buffer;
133 state->msg[0].len = 2;
134 state->msg[1].addr = state->i2c.addr >> 1;
135 state->msg[1].flags = I2C_M_RD;
136 state->msg[1].buf = state->i2c_read_buffer;
137 state->msg[1].len = 2;
138
139 if (i2c_transfer(state->i2c.adap, state->msg, 2) != 2)
140 dprintk("i2c read error on %d", reg);
141
Patrick Boettcher79fcce32011-08-03 12:08:21 -0300142 ret = (state->i2c_read_buffer[0] << 8) | state->i2c_read_buffer[1];
143 mutex_unlock(&state->i2c_buffer_lock);
144
145 return ret;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300146}
147
148static u32 dib8000_read32(struct dib8000_state *state, u16 reg)
149{
150 u16 rw[2];
151
152 rw[0] = dib8000_read_word(state, reg + 0);
153 rw[1] = dib8000_read_word(state, reg + 1);
154
155 return ((rw[0] << 16) | (rw[1]));
156}
157
158static int dib8000_i2c_write16(struct i2c_device *i2c, u16 reg, u16 val)
159{
Patrick Boettcher79fcce32011-08-03 12:08:21 -0300160 struct i2c_msg msg = {.addr = i2c->addr >> 1, .flags = 0, .len = 4};
Olivier Grenie5a0deee2011-05-03 12:27:33 -0300161 int ret = 0;
162
Patrick Boettcher79fcce32011-08-03 12:08:21 -0300163 if (mutex_lock_interruptible(i2c->i2c_buffer_lock) < 0) {
164 dprintk("could not acquire lock");
165 return -EINVAL;
166 }
167
168 msg.buf = i2c->i2c_write_buffer;
Olivier Grenie5a0deee2011-05-03 12:27:33 -0300169 msg.buf[0] = (reg >> 8) & 0xff;
170 msg.buf[1] = reg & 0xff;
171 msg.buf[2] = (val >> 8) & 0xff;
172 msg.buf[3] = val & 0xff;
173
174 ret = i2c_transfer(i2c->adap, &msg, 1) != 1 ? -EREMOTEIO : 0;
Patrick Boettcher79fcce32011-08-03 12:08:21 -0300175 mutex_unlock(i2c->i2c_buffer_lock);
Olivier Grenie5a0deee2011-05-03 12:27:33 -0300176
177 return ret;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300178}
179
180static int dib8000_write_word(struct dib8000_state *state, u16 reg, u16 val)
181{
Patrick Boettcher79fcce32011-08-03 12:08:21 -0300182 int ret;
183
184 if (mutex_lock_interruptible(&state->i2c_buffer_lock) < 0) {
185 dprintk("could not acquire lock");
186 return -EINVAL;
187 }
188
Olivier Grenie5a0deee2011-05-03 12:27:33 -0300189 state->i2c_write_buffer[0] = (reg >> 8) & 0xff;
190 state->i2c_write_buffer[1] = reg & 0xff;
191 state->i2c_write_buffer[2] = (val >> 8) & 0xff;
192 state->i2c_write_buffer[3] = val & 0xff;
193
194 memset(&state->msg[0], 0, sizeof(struct i2c_msg));
195 state->msg[0].addr = state->i2c.addr >> 1;
196 state->msg[0].flags = 0;
197 state->msg[0].buf = state->i2c_write_buffer;
198 state->msg[0].len = 4;
199
Patrick Boettcher79fcce32011-08-03 12:08:21 -0300200 ret = (i2c_transfer(state->i2c.adap, state->msg, 1) != 1 ?
201 -EREMOTEIO : 0);
202 mutex_unlock(&state->i2c_buffer_lock);
203
204 return ret;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300205}
206
Olivier Grenie4c70e072011-01-03 15:33:37 -0300207static const s16 coeff_2k_sb_1seg_dqpsk[8] = {
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300208 (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 -0300209 (920 << 5) | 0x09
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300210};
211
Olivier Grenie4c70e072011-01-03 15:33:37 -0300212static const s16 coeff_2k_sb_1seg[8] = {
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300213 (692 << 5) | 0x0b, (683 << 5) | 0x01, (519 << 5) | 0x09, (692 << 5) | 0x0b, 0 | 0x1f, 0 | 0x1f, 0 | 0x1f, 0 | 0x1f
214};
215
Olivier Grenie4c70e072011-01-03 15:33:37 -0300216static const s16 coeff_2k_sb_3seg_0dqpsk_1dqpsk[8] = {
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300217 (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 -0300218 (-931 << 5) | 0x0f
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300219};
220
Olivier Grenie4c70e072011-01-03 15:33:37 -0300221static const s16 coeff_2k_sb_3seg_0dqpsk[8] = {
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300222 (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 -0300223 (982 << 5) | 0x0c
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300224};
225
Olivier Grenie4c70e072011-01-03 15:33:37 -0300226static const s16 coeff_2k_sb_3seg_1dqpsk[8] = {
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300227 (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 -0300228 (-720 << 5) | 0x0d
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300229};
230
Olivier Grenie4c70e072011-01-03 15:33:37 -0300231static const s16 coeff_2k_sb_3seg[8] = {
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300232 (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 -0300233 (-610 << 5) | 0x0a
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300234};
235
Olivier Grenie4c70e072011-01-03 15:33:37 -0300236static const s16 coeff_4k_sb_1seg_dqpsk[8] = {
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300237 (-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 -0300238 (-922 << 5) | 0x0d
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300239};
240
Olivier Grenie4c70e072011-01-03 15:33:37 -0300241static const s16 coeff_4k_sb_1seg[8] = {
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300242 (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 -0300243 (-655 << 5) | 0x0a
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300244};
245
Olivier Grenie4c70e072011-01-03 15:33:37 -0300246static const s16 coeff_4k_sb_3seg_0dqpsk_1dqpsk[8] = {
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300247 (-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 -0300248 (-958 << 5) | 0x13
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300249};
250
Olivier Grenie4c70e072011-01-03 15:33:37 -0300251static const s16 coeff_4k_sb_3seg_0dqpsk[8] = {
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300252 (-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 -0300253 (-568 << 5) | 0x0f
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300254};
255
Olivier Grenie4c70e072011-01-03 15:33:37 -0300256static const s16 coeff_4k_sb_3seg_1dqpsk[8] = {
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300257 (-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 -0300258 (-848 << 5) | 0x13
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300259};
260
Olivier Grenie4c70e072011-01-03 15:33:37 -0300261static const s16 coeff_4k_sb_3seg[8] = {
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300262 (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 -0300263 (-869 << 5) | 0x13
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300264};
265
Olivier Grenie4c70e072011-01-03 15:33:37 -0300266static const s16 coeff_8k_sb_1seg_dqpsk[8] = {
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300267 (-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 -0300268 (-598 << 5) | 0x10
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300269};
270
Olivier Grenie4c70e072011-01-03 15:33:37 -0300271static const s16 coeff_8k_sb_1seg[8] = {
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300272 (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 -0300273 (585 << 5) | 0x0f
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300274};
275
Olivier Grenie4c70e072011-01-03 15:33:37 -0300276static const s16 coeff_8k_sb_3seg_0dqpsk_1dqpsk[8] = {
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300277 (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 -0300278 (0 << 5) | 0x14
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300279};
280
Olivier Grenie4c70e072011-01-03 15:33:37 -0300281static const s16 coeff_8k_sb_3seg_0dqpsk[8] = {
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300282 (-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 -0300283 (-877 << 5) | 0x15
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300284};
285
Olivier Grenie4c70e072011-01-03 15:33:37 -0300286static const s16 coeff_8k_sb_3seg_1dqpsk[8] = {
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300287 (-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 -0300288 (-921 << 5) | 0x14
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300289};
290
Olivier Grenie4c70e072011-01-03 15:33:37 -0300291static const s16 coeff_8k_sb_3seg[8] = {
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300292 (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 -0300293 (690 << 5) | 0x14
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300294};
295
Olivier Grenie4c70e072011-01-03 15:33:37 -0300296static const s16 ana_fe_coeff_3seg[24] = {
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300297 81, 80, 78, 74, 68, 61, 54, 45, 37, 28, 19, 11, 4, 1022, 1017, 1013, 1010, 1008, 1008, 1008, 1008, 1010, 1014, 1017
298};
299
Olivier Grenie4c70e072011-01-03 15:33:37 -0300300static const s16 ana_fe_coeff_1seg[24] = {
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300301 249, 226, 164, 82, 5, 981, 970, 988, 1018, 20, 31, 26, 8, 1012, 1000, 1018, 1012, 8, 15, 14, 9, 3, 1017, 1003
302};
303
Olivier Grenie4c70e072011-01-03 15:33:37 -0300304static const s16 ana_fe_coeff_13seg[24] = {
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300305 396, 305, 105, -51, -77, -12, 41, 31, -11, -30, -11, 14, 15, -2, -13, -7, 5, 8, 1, -6, -7, -3, 0, 1
306};
307
308static u16 fft_to_mode(struct dib8000_state *state)
309{
310 u16 mode;
Olivier Grenie4c70e072011-01-03 15:33:37 -0300311 switch (state->fe[0]->dtv_property_cache.transmission_mode) {
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300312 case TRANSMISSION_MODE_2K:
313 mode = 1;
314 break;
315 case TRANSMISSION_MODE_4K:
316 mode = 2;
317 break;
318 default:
319 case TRANSMISSION_MODE_AUTO:
320 case TRANSMISSION_MODE_8K:
321 mode = 3;
322 break;
323 }
324 return mode;
325}
326
327static void dib8000_set_acquisition_mode(struct dib8000_state *state)
328{
329 u16 nud = dib8000_read_word(state, 298);
330 nud |= (1 << 3) | (1 << 0);
331 dprintk("acquisition mode activated");
332 dib8000_write_word(state, 298, nud);
333}
Olivier Grenie4c70e072011-01-03 15:33:37 -0300334static int dib8000_set_output_mode(struct dvb_frontend *fe, int mode)
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300335{
Olivier Grenie4c70e072011-01-03 15:33:37 -0300336 struct dib8000_state *state = fe->demodulator_priv;
337
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300338 u16 outreg, fifo_threshold, smo_mode, sram = 0x0205; /* by default SDRAM deintlv is enabled */
339
340 outreg = 0;
341 fifo_threshold = 1792;
342 smo_mode = (dib8000_read_word(state, 299) & 0x0050) | (1 << 1);
343
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300344 dprintk("-I- Setting output mode for demod %p to %d",
345 &state->fe[0], mode);
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300346
347 switch (mode) {
348 case OUTMODE_MPEG2_PAR_GATED_CLK: // STBs with parallel gated clock
349 outreg = (1 << 10); /* 0x0400 */
350 break;
351 case OUTMODE_MPEG2_PAR_CONT_CLK: // STBs with parallel continues clock
352 outreg = (1 << 10) | (1 << 6); /* 0x0440 */
353 break;
354 case OUTMODE_MPEG2_SERIAL: // STBs with serial input
355 outreg = (1 << 10) | (2 << 6) | (0 << 1); /* 0x0482 */
356 break;
357 case OUTMODE_DIVERSITY:
358 if (state->cfg.hostbus_diversity) {
359 outreg = (1 << 10) | (4 << 6); /* 0x0500 */
360 sram &= 0xfdff;
361 } else
362 sram |= 0x0c00;
363 break;
364 case OUTMODE_MPEG2_FIFO: // e.g. USB feeding
365 smo_mode |= (3 << 1);
366 fifo_threshold = 512;
367 outreg = (1 << 10) | (5 << 6);
368 break;
369 case OUTMODE_HIGH_Z: // disable
370 outreg = 0;
371 break;
372
373 case OUTMODE_ANALOG_ADC:
374 outreg = (1 << 10) | (3 << 6);
375 dib8000_set_acquisition_mode(state);
376 break;
377
378 default:
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300379 dprintk("Unhandled output_mode passed to be set for demod %p",
380 &state->fe[0]);
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300381 return -EINVAL;
382 }
383
384 if (state->cfg.output_mpeg2_in_188_bytes)
385 smo_mode |= (1 << 5);
386
387 dib8000_write_word(state, 299, smo_mode);
388 dib8000_write_word(state, 300, fifo_threshold); /* synchronous fread */
389 dib8000_write_word(state, 1286, outreg);
390 dib8000_write_word(state, 1291, sram);
391
392 return 0;
393}
394
395static int dib8000_set_diversity_in(struct dvb_frontend *fe, int onoff)
396{
397 struct dib8000_state *state = fe->demodulator_priv;
398 u16 sync_wait = dib8000_read_word(state, 273) & 0xfff0;
399
400 if (!state->differential_constellation) {
401 dib8000_write_word(state, 272, 1 << 9); //dvsy_off_lmod4 = 1
402 dib8000_write_word(state, 273, sync_wait | (1 << 2) | 2); // sync_enable = 1; comb_mode = 2
403 } else {
404 dib8000_write_word(state, 272, 0); //dvsy_off_lmod4 = 0
405 dib8000_write_word(state, 273, sync_wait); // sync_enable = 0; comb_mode = 0
406 }
407 state->diversity_onoff = onoff;
408
409 switch (onoff) {
410 case 0: /* only use the internal way - not the diversity input */
411 dib8000_write_word(state, 270, 1);
412 dib8000_write_word(state, 271, 0);
413 break;
414 case 1: /* both ways */
415 dib8000_write_word(state, 270, 6);
416 dib8000_write_word(state, 271, 6);
417 break;
418 case 2: /* only the diversity input */
419 dib8000_write_word(state, 270, 0);
420 dib8000_write_word(state, 271, 1);
421 break;
422 }
423 return 0;
424}
425
426static void dib8000_set_power_mode(struct dib8000_state *state, enum dib8000_power_mode mode)
427{
428 /* by default everything is going to be powered off */
429 u16 reg_774 = 0x3fff, reg_775 = 0xffff, reg_776 = 0xffff,
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300430 reg_900 = (dib8000_read_word(state, 900) & 0xfffc) | 0x3,
431 reg_1280 = (dib8000_read_word(state, 1280) & 0x00ff) | 0xff00;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300432
433 /* now, depending on the requested mode, we power on */
434 switch (mode) {
435 /* power up everything in the demod */
436 case DIB8000M_POWER_ALL:
437 reg_774 = 0x0000;
438 reg_775 = 0x0000;
439 reg_776 = 0x0000;
440 reg_900 &= 0xfffc;
441 reg_1280 &= 0x00ff;
442 break;
443 case DIB8000M_POWER_INTERFACE_ONLY:
444 reg_1280 &= 0x00ff;
445 break;
446 }
447
448 dprintk("powermode : 774 : %x ; 775 : %x; 776 : %x ; 900 : %x; 1280 : %x", reg_774, reg_775, reg_776, reg_900, reg_1280);
449 dib8000_write_word(state, 774, reg_774);
450 dib8000_write_word(state, 775, reg_775);
451 dib8000_write_word(state, 776, reg_776);
452 dib8000_write_word(state, 900, reg_900);
453 dib8000_write_word(state, 1280, reg_1280);
454}
455
456static int dib8000_set_adc_state(struct dib8000_state *state, enum dibx000_adc_states no)
457{
458 int ret = 0;
459 u16 reg_907 = dib8000_read_word(state, 907), reg_908 = dib8000_read_word(state, 908);
460
461 switch (no) {
462 case DIBX000_SLOW_ADC_ON:
463 reg_908 |= (1 << 1) | (1 << 0);
464 ret |= dib8000_write_word(state, 908, reg_908);
465 reg_908 &= ~(1 << 1);
466 break;
467
468 case DIBX000_SLOW_ADC_OFF:
469 reg_908 |= (1 << 1) | (1 << 0);
470 break;
471
472 case DIBX000_ADC_ON:
473 reg_907 &= 0x0fff;
474 reg_908 &= 0x0003;
475 break;
476
477 case DIBX000_ADC_OFF: // leave the VBG voltage on
478 reg_907 |= (1 << 14) | (1 << 13) | (1 << 12);
479 reg_908 |= (1 << 5) | (1 << 4) | (1 << 3) | (1 << 2);
480 break;
481
482 case DIBX000_VBG_ENABLE:
483 reg_907 &= ~(1 << 15);
484 break;
485
486 case DIBX000_VBG_DISABLE:
487 reg_907 |= (1 << 15);
488 break;
489
490 default:
491 break;
492 }
493
494 ret |= dib8000_write_word(state, 907, reg_907);
495 ret |= dib8000_write_word(state, 908, reg_908);
496
497 return ret;
498}
499
Olivier Grenie4c70e072011-01-03 15:33:37 -0300500static int dib8000_set_bandwidth(struct dvb_frontend *fe, u32 bw)
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300501{
Olivier Grenie4c70e072011-01-03 15:33:37 -0300502 struct dib8000_state *state = fe->demodulator_priv;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300503 u32 timf;
504
505 if (bw == 0)
506 bw = 6000;
507
508 if (state->timf == 0) {
509 dprintk("using default timf");
510 timf = state->timf_default;
511 } else {
512 dprintk("using updated timf");
513 timf = state->timf;
514 }
515
516 dib8000_write_word(state, 29, (u16) ((timf >> 16) & 0xffff));
517 dib8000_write_word(state, 30, (u16) ((timf) & 0xffff));
518
519 return 0;
520}
521
522static int dib8000_sad_calib(struct dib8000_state *state)
523{
524/* internal */
525 dib8000_write_word(state, 923, (0 << 1) | (0 << 0));
526 dib8000_write_word(state, 924, 776); // 0.625*3.3 / 4096
527
528 /* do the calibration */
529 dib8000_write_word(state, 923, (1 << 0));
530 dib8000_write_word(state, 923, (0 << 0));
531
532 msleep(1);
533 return 0;
534}
535
536int dib8000_set_wbd_ref(struct dvb_frontend *fe, u16 value)
537{
538 struct dib8000_state *state = fe->demodulator_priv;
539 if (value > 4095)
540 value = 4095;
541 state->wbd_ref = value;
542 return dib8000_write_word(state, 106, value);
543}
544
545EXPORT_SYMBOL(dib8000_set_wbd_ref);
546static void dib8000_reset_pll_common(struct dib8000_state *state, const struct dibx000_bandwidth_config *bw)
547{
548 dprintk("ifreq: %d %x, inversion: %d", bw->ifreq, bw->ifreq, bw->ifreq >> 25);
549 dib8000_write_word(state, 23, (u16) (((bw->internal * 1000) >> 16) & 0xffff)); /* P_sec_len */
550 dib8000_write_word(state, 24, (u16) ((bw->internal * 1000) & 0xffff));
551 dib8000_write_word(state, 27, (u16) ((bw->ifreq >> 16) & 0x01ff));
552 dib8000_write_word(state, 28, (u16) (bw->ifreq & 0xffff));
553 dib8000_write_word(state, 26, (u16) ((bw->ifreq >> 25) & 0x0003));
554
555 dib8000_write_word(state, 922, bw->sad_cfg);
556}
557
558static void dib8000_reset_pll(struct dib8000_state *state)
559{
560 const struct dibx000_bandwidth_config *pll = state->cfg.pll;
561 u16 clk_cfg1;
562
563 // clk_cfg0
564 dib8000_write_word(state, 901, (pll->pll_prediv << 8) | (pll->pll_ratio << 0));
565
566 // clk_cfg1
567 clk_cfg1 = (1 << 10) | (0 << 9) | (pll->IO_CLK_en_core << 8) |
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300568 (pll->bypclk_div << 5) | (pll->enable_refdiv << 4) | (1 << 3) |
569 (pll->pll_range << 1) | (pll->pll_reset << 0);
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300570
571 dib8000_write_word(state, 902, clk_cfg1);
572 clk_cfg1 = (clk_cfg1 & 0xfff7) | (pll->pll_bypass << 3);
573 dib8000_write_word(state, 902, clk_cfg1);
574
575 dprintk("clk_cfg1: 0x%04x", clk_cfg1); /* 0x507 1 0 1 000 0 0 11 1 */
576
577 /* smpl_cfg: P_refclksel=2, P_ensmplsel=1 nodivsmpl=1 */
578 if (state->cfg.pll->ADClkSrc == 0)
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300579 dib8000_write_word(state, 904, (0 << 15) | (0 << 12) | (0 << 10) |
580 (pll->modulo << 8) | (pll->ADClkSrc << 7) | (0 << 1));
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300581 else if (state->cfg.refclksel != 0)
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300582 dib8000_write_word(state, 904, (0 << 15) | (1 << 12) |
583 ((state->cfg.refclksel & 0x3) << 10) | (pll->modulo << 8) |
584 (pll->ADClkSrc << 7) | (0 << 1));
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300585 else
586 dib8000_write_word(state, 904, (0 << 15) | (1 << 12) | (3 << 10) | (pll->modulo << 8) | (pll->ADClkSrc << 7) | (0 << 1));
587
588 dib8000_reset_pll_common(state, pll);
589}
590
591static int dib8000_reset_gpio(struct dib8000_state *st)
592{
593 /* reset the GPIOs */
594 dib8000_write_word(st, 1029, st->cfg.gpio_dir);
595 dib8000_write_word(st, 1030, st->cfg.gpio_val);
596
597 /* TODO 782 is P_gpio_od */
598
599 dib8000_write_word(st, 1032, st->cfg.gpio_pwm_pos);
600
601 dib8000_write_word(st, 1037, st->cfg.pwm_freq_div);
602 return 0;
603}
604
605static int dib8000_cfg_gpio(struct dib8000_state *st, u8 num, u8 dir, u8 val)
606{
607 st->cfg.gpio_dir = dib8000_read_word(st, 1029);
608 st->cfg.gpio_dir &= ~(1 << num); /* reset the direction bit */
609 st->cfg.gpio_dir |= (dir & 0x1) << num; /* set the new direction */
610 dib8000_write_word(st, 1029, st->cfg.gpio_dir);
611
612 st->cfg.gpio_val = dib8000_read_word(st, 1030);
613 st->cfg.gpio_val &= ~(1 << num); /* reset the direction bit */
614 st->cfg.gpio_val |= (val & 0x01) << num; /* set the new value */
615 dib8000_write_word(st, 1030, st->cfg.gpio_val);
616
617 dprintk("gpio dir: %x: gpio val: %x", st->cfg.gpio_dir, st->cfg.gpio_val);
618
619 return 0;
620}
621
622int dib8000_set_gpio(struct dvb_frontend *fe, u8 num, u8 dir, u8 val)
623{
624 struct dib8000_state *state = fe->demodulator_priv;
625 return dib8000_cfg_gpio(state, num, dir, val);
626}
627
628EXPORT_SYMBOL(dib8000_set_gpio);
629static const u16 dib8000_defaults[] = {
630 /* auto search configuration - lock0 by default waiting
631 * for cpil_lock; lock1 cpil_lock; lock2 tmcc_sync_lock */
632 3, 7,
633 0x0004,
634 0x0400,
635 0x0814,
636
637 12, 11,
638 0x001b,
639 0x7740,
640 0x005b,
641 0x8d80,
642 0x01c9,
643 0xc380,
644 0x0000,
645 0x0080,
646 0x0000,
647 0x0090,
648 0x0001,
649 0xd4c0,
650
651 /*1, 32,
Olivier Grenie4c70e072011-01-03 15:33:37 -0300652 0x6680 // P_corm_thres Lock algorithms configuration */
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300653
654 11, 80, /* set ADC level to -16 */
655 (1 << 13) - 825 - 117,
656 (1 << 13) - 837 - 117,
657 (1 << 13) - 811 - 117,
658 (1 << 13) - 766 - 117,
659 (1 << 13) - 737 - 117,
660 (1 << 13) - 693 - 117,
661 (1 << 13) - 648 - 117,
662 (1 << 13) - 619 - 117,
663 (1 << 13) - 575 - 117,
664 (1 << 13) - 531 - 117,
665 (1 << 13) - 501 - 117,
666
667 4, 108,
668 0,
669 0,
670 0,
671 0,
672
673 1, 175,
674 0x0410,
675 1, 179,
676 8192, // P_fft_nb_to_cut
677
678 6, 181,
679 0x2800, // P_coff_corthres_ ( 2k 4k 8k ) 0x2800
680 0x2800,
681 0x2800,
682 0x2800, // P_coff_cpilthres_ ( 2k 4k 8k ) 0x2800
683 0x2800,
684 0x2800,
685
686 2, 193,
687 0x0666, // P_pha3_thres
688 0x0000, // P_cti_use_cpe, P_cti_use_prog
689
690 2, 205,
691 0x200f, // P_cspu_regul, P_cspu_win_cut
692 0x000f, // P_des_shift_work
693
694 5, 215,
695 0x023d, // P_adp_regul_cnt
696 0x00a4, // P_adp_noise_cnt
697 0x00a4, // P_adp_regul_ext
698 0x7ff0, // P_adp_noise_ext
699 0x3ccc, // P_adp_fil
700
701 1, 230,
702 0x0000, // P_2d_byp_ti_num
703
704 1, 263,
705 0x800, //P_equal_thres_wgn
706
707 1, 268,
708 (2 << 9) | 39, // P_equal_ctrl_synchro, P_equal_speedmode
709
710 1, 270,
711 0x0001, // P_div_lock0_wait
712 1, 285,
713 0x0020, //p_fec_
714 1, 299,
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300715 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 -0300716
717 1, 338,
718 (1 << 12) | // P_ctrl_corm_thres4pre_freq_inh=1
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300719 (1 << 10) |
720 (0 << 9) | /* P_ctrl_pre_freq_inh=0 */
721 (3 << 5) | /* P_ctrl_pre_freq_step=3 */
722 (1 << 0), /* P_pre_freq_win_len=1 */
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300723
724 1, 903,
725 (0 << 4) | 2, // P_divclksel=0 P_divbitsel=2 (was clk=3,bit=1 for MPW)
726
727 0,
728};
729
730static u16 dib8000_identify(struct i2c_device *client)
731{
732 u16 value;
733
734 //because of glitches sometimes
735 value = dib8000_i2c_read16(client, 896);
736
737 if ((value = dib8000_i2c_read16(client, 896)) != 0x01b3) {
738 dprintk("wrong Vendor ID (read=0x%x)", value);
739 return 0;
740 }
741
742 value = dib8000_i2c_read16(client, 897);
743 if (value != 0x8000 && value != 0x8001 && value != 0x8002) {
744 dprintk("wrong Device ID (%x)", value);
745 return 0;
746 }
747
748 switch (value) {
749 case 0x8000:
750 dprintk("found DiB8000A");
751 break;
752 case 0x8001:
753 dprintk("found DiB8000B");
754 break;
755 case 0x8002:
756 dprintk("found DiB8000C");
757 break;
758 }
759 return value;
760}
761
762static int dib8000_reset(struct dvb_frontend *fe)
763{
764 struct dib8000_state *state = fe->demodulator_priv;
765
766 dib8000_write_word(state, 1287, 0x0003); /* sram lead in, rdy */
767
768 if ((state->revision = dib8000_identify(&state->i2c)) == 0)
769 return -EINVAL;
770
771 if (state->revision == 0x8000)
772 dprintk("error : dib8000 MA not supported");
773
774 dibx000_reset_i2c_master(&state->i2c_master);
775
776 dib8000_set_power_mode(state, DIB8000M_POWER_ALL);
777
778 /* always leave the VBG voltage on - it consumes almost nothing but takes a long time to start */
779 dib8000_set_adc_state(state, DIBX000_VBG_ENABLE);
780
781 /* restart all parts */
782 dib8000_write_word(state, 770, 0xffff);
783 dib8000_write_word(state, 771, 0xffff);
784 dib8000_write_word(state, 772, 0xfffc);
785 dib8000_write_word(state, 898, 0x000c); // sad
786 dib8000_write_word(state, 1280, 0x004d);
787 dib8000_write_word(state, 1281, 0x000c);
788
789 dib8000_write_word(state, 770, 0x0000);
790 dib8000_write_word(state, 771, 0x0000);
791 dib8000_write_word(state, 772, 0x0000);
792 dib8000_write_word(state, 898, 0x0004); // sad
793 dib8000_write_word(state, 1280, 0x0000);
794 dib8000_write_word(state, 1281, 0x0000);
795
796 /* drives */
797 if (state->cfg.drives)
798 dib8000_write_word(state, 906, state->cfg.drives);
799 else {
800 dprintk("using standard PAD-drive-settings, please adjust settings in config-struct to be optimal.");
801 dib8000_write_word(state, 906, 0x2d98); // min drive SDRAM - not optimal - adjust
802 }
803
804 dib8000_reset_pll(state);
805
806 if (dib8000_reset_gpio(state) != 0)
807 dprintk("GPIO reset was not successful.");
808
Olivier Grenie4c70e072011-01-03 15:33:37 -0300809 if (dib8000_set_output_mode(fe, OUTMODE_HIGH_Z) != 0)
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300810 dprintk("OUTPUT_MODE could not be resetted.");
811
812 state->current_agc = NULL;
813
814 // P_iqc_alpha_pha, P_iqc_alpha_amp, P_iqc_dcc_alpha, ...
815 /* P_iqc_ca2 = 0; P_iqc_impnc_on = 0; P_iqc_mode = 0; */
816 if (state->cfg.pll->ifreq == 0)
817 dib8000_write_word(state, 40, 0x0755); /* P_iqc_corr_inh = 0 enable IQcorr block */
818 else
819 dib8000_write_word(state, 40, 0x1f55); /* P_iqc_corr_inh = 1 disable IQcorr block */
820
821 {
822 u16 l = 0, r;
823 const u16 *n;
824 n = dib8000_defaults;
825 l = *n++;
826 while (l) {
827 r = *n++;
828 do {
829 dib8000_write_word(state, r, *n++);
830 r++;
831 } while (--l);
832 l = *n++;
833 }
834 }
835 state->isdbt_cfg_loaded = 0;
836
837 //div_cfg override for special configs
838 if (state->cfg.div_cfg != 0)
839 dib8000_write_word(state, 903, state->cfg.div_cfg);
840
841 /* unforce divstr regardless whether i2c enumeration was done or not */
842 dib8000_write_word(state, 1285, dib8000_read_word(state, 1285) & ~(1 << 1));
843
Olivier Grenie4c70e072011-01-03 15:33:37 -0300844 dib8000_set_bandwidth(fe, 6000);
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300845
846 dib8000_set_adc_state(state, DIBX000_SLOW_ADC_ON);
847 dib8000_sad_calib(state);
848 dib8000_set_adc_state(state, DIBX000_SLOW_ADC_OFF);
849
850 dib8000_set_power_mode(state, DIB8000M_POWER_INTERFACE_ONLY);
851
852 return 0;
853}
854
855static void dib8000_restart_agc(struct dib8000_state *state)
856{
857 // P_restart_iqc & P_restart_agc
858 dib8000_write_word(state, 770, 0x0a00);
859 dib8000_write_word(state, 770, 0x0000);
860}
861
862static int dib8000_update_lna(struct dib8000_state *state)
863{
864 u16 dyn_gain;
865
866 if (state->cfg.update_lna) {
867 // read dyn_gain here (because it is demod-dependent and not tuner)
868 dyn_gain = dib8000_read_word(state, 390);
869
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300870 if (state->cfg.update_lna(state->fe[0], dyn_gain)) {
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300871 dib8000_restart_agc(state);
872 return 1;
873 }
874 }
875 return 0;
876}
877
878static int dib8000_set_agc_config(struct dib8000_state *state, u8 band)
879{
880 struct dibx000_agc_config *agc = NULL;
881 int i;
882 if (state->current_band == band && state->current_agc != NULL)
883 return 0;
884 state->current_band = band;
885
886 for (i = 0; i < state->cfg.agc_config_count; i++)
887 if (state->cfg.agc[i].band_caps & band) {
888 agc = &state->cfg.agc[i];
889 break;
890 }
891
892 if (agc == NULL) {
893 dprintk("no valid AGC configuration found for band 0x%02x", band);
894 return -EINVAL;
895 }
896
897 state->current_agc = agc;
898
899 /* AGC */
900 dib8000_write_word(state, 76, agc->setup);
901 dib8000_write_word(state, 77, agc->inv_gain);
902 dib8000_write_word(state, 78, agc->time_stabiliz);
903 dib8000_write_word(state, 101, (agc->alpha_level << 12) | agc->thlock);
904
905 // Demod AGC loop configuration
906 dib8000_write_word(state, 102, (agc->alpha_mant << 5) | agc->alpha_exp);
907 dib8000_write_word(state, 103, (agc->beta_mant << 6) | agc->beta_exp);
908
909 dprintk("WBD: ref: %d, sel: %d, active: %d, alpha: %d",
910 state->wbd_ref != 0 ? state->wbd_ref : agc->wbd_ref, agc->wbd_sel, !agc->perform_agc_softsplit, agc->wbd_sel);
911
912 /* AGC continued */
913 if (state->wbd_ref != 0)
914 dib8000_write_word(state, 106, state->wbd_ref);
915 else // use default
916 dib8000_write_word(state, 106, agc->wbd_ref);
917 dib8000_write_word(state, 107, (agc->wbd_alpha << 9) | (agc->perform_agc_softsplit << 8));
918 dib8000_write_word(state, 108, agc->agc1_max);
919 dib8000_write_word(state, 109, agc->agc1_min);
920 dib8000_write_word(state, 110, agc->agc2_max);
921 dib8000_write_word(state, 111, agc->agc2_min);
922 dib8000_write_word(state, 112, (agc->agc1_pt1 << 8) | agc->agc1_pt2);
923 dib8000_write_word(state, 113, (agc->agc1_slope1 << 8) | agc->agc1_slope2);
924 dib8000_write_word(state, 114, (agc->agc2_pt1 << 8) | agc->agc2_pt2);
925 dib8000_write_word(state, 115, (agc->agc2_slope1 << 8) | agc->agc2_slope2);
926
927 dib8000_write_word(state, 75, agc->agc1_pt3);
928 dib8000_write_word(state, 923, (dib8000_read_word(state, 923) & 0xffe3) | (agc->wbd_inv << 4) | (agc->wbd_sel << 2)); /*LB : 929 -> 923 */
929
930 return 0;
931}
932
Olivier Grenie03245a52009-12-04 13:27:57 -0300933void dib8000_pwm_agc_reset(struct dvb_frontend *fe)
934{
935 struct dib8000_state *state = fe->demodulator_priv;
936 dib8000_set_adc_state(state, DIBX000_ADC_ON);
937 dib8000_set_agc_config(state, (unsigned char)(BAND_OF_FREQUENCY(fe->dtv_property_cache.frequency / 1000)));
938}
939EXPORT_SYMBOL(dib8000_pwm_agc_reset);
940
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300941static int dib8000_agc_soft_split(struct dib8000_state *state)
942{
943 u16 agc, split_offset;
944
945 if (!state->current_agc || !state->current_agc->perform_agc_softsplit || state->current_agc->split.max == 0)
946 return FE_CALLBACK_TIME_NEVER;
947
948 // n_agc_global
949 agc = dib8000_read_word(state, 390);
950
951 if (agc > state->current_agc->split.min_thres)
952 split_offset = state->current_agc->split.min;
953 else if (agc < state->current_agc->split.max_thres)
954 split_offset = state->current_agc->split.max;
955 else
956 split_offset = state->current_agc->split.max *
Olivier Grenieb4d6046e2011-01-04 13:08:14 -0300957 (agc - state->current_agc->split.min_thres) /
958 (state->current_agc->split.max_thres - state->current_agc->split.min_thres);
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300959
960 dprintk("AGC split_offset: %d", split_offset);
961
962 // P_agc_force_split and P_agc_split_offset
963 dib8000_write_word(state, 107, (dib8000_read_word(state, 107) & 0xff00) | split_offset);
964 return 5000;
965}
966
967static int dib8000_agc_startup(struct dvb_frontend *fe)
968{
969 struct dib8000_state *state = fe->demodulator_priv;
970 enum frontend_tune_state *tune_state = &state->tune_state;
971
972 int ret = 0;
973
974 switch (*tune_state) {
975 case CT_AGC_START:
976 // set power-up level: interf+analog+AGC
977
978 dib8000_set_adc_state(state, DIBX000_ADC_ON);
979
980 if (dib8000_set_agc_config(state, (unsigned char)(BAND_OF_FREQUENCY(fe->dtv_property_cache.frequency / 1000))) != 0) {
981 *tune_state = CT_AGC_STOP;
982 state->status = FE_STATUS_TUNE_FAILED;
983 break;
984 }
985
986 ret = 70;
987 *tune_state = CT_AGC_STEP_0;
988 break;
989
990 case CT_AGC_STEP_0:
991 //AGC initialization
992 if (state->cfg.agc_control)
Olivier Grenie4c70e072011-01-03 15:33:37 -0300993 state->cfg.agc_control(fe, 1);
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -0300994
995 dib8000_restart_agc(state);
996
997 // wait AGC rough lock time
998 ret = 50;
999 *tune_state = CT_AGC_STEP_1;
1000 break;
1001
1002 case CT_AGC_STEP_1:
1003 // wait AGC accurate lock time
1004 ret = 70;
1005
1006 if (dib8000_update_lna(state))
1007 // wait only AGC rough lock time
1008 ret = 50;
1009 else
1010 *tune_state = CT_AGC_STEP_2;
1011 break;
1012
1013 case CT_AGC_STEP_2:
1014 dib8000_agc_soft_split(state);
1015
1016 if (state->cfg.agc_control)
Olivier Grenie4c70e072011-01-03 15:33:37 -03001017 state->cfg.agc_control(fe, 0);
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001018
1019 *tune_state = CT_AGC_STOP;
1020 break;
1021 default:
1022 ret = dib8000_agc_soft_split(state);
1023 break;
1024 }
1025 return ret;
1026
1027}
1028
Olivier Grenie4c70e072011-01-03 15:33:37 -03001029static const s32 lut_1000ln_mant[] =
Olivier Grenie03245a52009-12-04 13:27:57 -03001030{
Olivier Grenie9c783032009-12-07 07:49:40 -03001031 908, 7003, 7090, 7170, 7244, 7313, 7377, 7438, 7495, 7549, 7600
Olivier Grenie03245a52009-12-04 13:27:57 -03001032};
1033
Olivier Grenie4c70e072011-01-03 15:33:37 -03001034s32 dib8000_get_adc_power(struct dvb_frontend *fe, u8 mode)
Olivier Grenie03245a52009-12-04 13:27:57 -03001035{
Olivier Grenie4c70e072011-01-03 15:33:37 -03001036 struct dib8000_state *state = fe->demodulator_priv;
1037 u32 ix = 0, tmp_val = 0, exp = 0, mant = 0;
1038 s32 val;
Olivier Grenie03245a52009-12-04 13:27:57 -03001039
Olivier Grenie4c70e072011-01-03 15:33:37 -03001040 val = dib8000_read32(state, 384);
Olivier Grenie4c70e072011-01-03 15:33:37 -03001041 if (mode) {
1042 tmp_val = val;
1043 while (tmp_val >>= 1)
1044 exp++;
1045 mant = (val * 1000 / (1<<exp));
1046 ix = (u8)((mant-1000)/100); /* index of the LUT */
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001047 val = (lut_1000ln_mant[ix] + 693*(exp-20) - 6908);
Olivier Grenie4c70e072011-01-03 15:33:37 -03001048 val = (val*256)/1000;
1049 }
1050 return val;
Olivier Grenie03245a52009-12-04 13:27:57 -03001051}
1052EXPORT_SYMBOL(dib8000_get_adc_power);
1053
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001054static void dib8000_update_timf(struct dib8000_state *state)
1055{
1056 u32 timf = state->timf = dib8000_read32(state, 435);
1057
1058 dib8000_write_word(state, 29, (u16) (timf >> 16));
1059 dib8000_write_word(state, 30, (u16) (timf & 0xffff));
1060 dprintk("Updated timing frequency: %d (default: %d)", state->timf, state->timf_default);
1061}
1062
Olivier Grenie5a0deee2011-05-03 12:27:33 -03001063static const u16 adc_target_16dB[11] = {
1064 (1 << 13) - 825 - 117,
1065 (1 << 13) - 837 - 117,
1066 (1 << 13) - 811 - 117,
1067 (1 << 13) - 766 - 117,
1068 (1 << 13) - 737 - 117,
1069 (1 << 13) - 693 - 117,
1070 (1 << 13) - 648 - 117,
1071 (1 << 13) - 619 - 117,
1072 (1 << 13) - 575 - 117,
1073 (1 << 13) - 531 - 117,
1074 (1 << 13) - 501 - 117
1075};
1076static const u8 permu_seg[] = { 6, 5, 7, 4, 8, 3, 9, 2, 10, 1, 11, 0, 12 };
1077
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001078static void dib8000_set_channel(struct dib8000_state *state, u8 seq, u8 autosearching)
1079{
1080 u16 mode, max_constellation, seg_diff_mask = 0, nbseg_diff = 0;
1081 u8 guard, crate, constellation, timeI;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001082 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 -03001083 const s16 *ncoeff = NULL, *ana_fe;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001084 u16 tmcc_pow = 0;
1085 u16 coff_pow = 0x2800;
1086 u16 init_prbs = 0xfff;
1087 u16 ana_gain = 0;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001088
1089 if (state->ber_monitored_layer != LAYER_ALL)
1090 dib8000_write_word(state, 285, (dib8000_read_word(state, 285) & 0x60) | state->ber_monitored_layer);
1091 else
1092 dib8000_write_word(state, 285, dib8000_read_word(state, 285) & 0x60);
1093
1094 i = dib8000_read_word(state, 26) & 1; // P_dds_invspec
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001095 dib8000_write_word(state, 26, state->fe[0]->dtv_property_cache.inversion^i);
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001096
Olivier Grenie4c70e072011-01-03 15:33:37 -03001097 if (state->fe[0]->dtv_property_cache.isdbt_sb_mode) {
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001098 //compute new dds_freq for the seg and adjust prbs
1099 int seg_offset =
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001100 state->fe[0]->dtv_property_cache.isdbt_sb_segment_idx -
1101 (state->fe[0]->dtv_property_cache.isdbt_sb_segment_count / 2) -
Olivier Grenie4c70e072011-01-03 15:33:37 -03001102 (state->fe[0]->dtv_property_cache.isdbt_sb_segment_count % 2);
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001103 int clk = state->cfg.pll->internal;
1104 u32 segtodds = ((u32) (430 << 23) / clk) << 3; // segtodds = SegBW / Fclk * pow(2,26)
1105 int dds_offset = seg_offset * segtodds;
1106 int new_dds, sub_channel;
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001107 if ((state->fe[0]->dtv_property_cache.isdbt_sb_segment_count % 2) == 0)
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001108 dds_offset -= (int)(segtodds / 2);
1109
1110 if (state->cfg.pll->ifreq == 0) {
Olivier Grenie4c70e072011-01-03 15:33:37 -03001111 if ((state->fe[0]->dtv_property_cache.inversion ^ i) == 0) {
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001112 dib8000_write_word(state, 26, dib8000_read_word(state, 26) | 1);
1113 new_dds = dds_offset;
1114 } else
1115 new_dds = dds_offset;
1116
1117 // We shift tuning frequency if the wanted segment is :
1118 // - the segment of center frequency with an odd total number of segments
1119 // - the segment to the left of center frequency with an even total number of segments
1120 // - the segment to the right of center frequency with an even total number of segments
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001121 if ((state->fe[0]->dtv_property_cache.delivery_system == SYS_ISDBT)
1122 && (state->fe[0]->dtv_property_cache.isdbt_sb_mode == 1)
Olivier Grenie4c70e072011-01-03 15:33:37 -03001123 && (((state->fe[0]->dtv_property_cache.isdbt_sb_segment_count % 2)
1124 && (state->fe[0]->dtv_property_cache.isdbt_sb_segment_idx ==
1125 ((state->fe[0]->dtv_property_cache.isdbt_sb_segment_count / 2) + 1)))
1126 || (((state->fe[0]->dtv_property_cache.isdbt_sb_segment_count % 2) == 0)
1127 && (state->fe[0]->dtv_property_cache.isdbt_sb_segment_idx == (state->fe[0]->dtv_property_cache.isdbt_sb_segment_count / 2)))
1128 || (((state->fe[0]->dtv_property_cache.isdbt_sb_segment_count % 2) == 0)
1129 && (state->fe[0]->dtv_property_cache.isdbt_sb_segment_idx ==
1130 ((state->fe[0]->dtv_property_cache.isdbt_sb_segment_count / 2) + 1)))
1131 )) {
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001132 new_dds -= ((u32) (850 << 22) / clk) << 4; // new_dds = 850 (freq shift in KHz) / Fclk * pow(2,26)
1133 }
1134 } else {
Olivier Grenie4c70e072011-01-03 15:33:37 -03001135 if ((state->fe[0]->dtv_property_cache.inversion ^ i) == 0)
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001136 new_dds = state->cfg.pll->ifreq - dds_offset;
1137 else
1138 new_dds = state->cfg.pll->ifreq + dds_offset;
1139 }
1140 dib8000_write_word(state, 27, (u16) ((new_dds >> 16) & 0x01ff));
1141 dib8000_write_word(state, 28, (u16) (new_dds & 0xffff));
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001142 if (state->fe[0]->dtv_property_cache.isdbt_sb_segment_count % 2)
Olivier Grenie4c70e072011-01-03 15:33:37 -03001143 sub_channel = ((state->fe[0]->dtv_property_cache.isdbt_sb_subchannel + (3 * seg_offset) + 1) % 41) / 3;
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001144 else
Olivier Grenie4c70e072011-01-03 15:33:37 -03001145 sub_channel = ((state->fe[0]->dtv_property_cache.isdbt_sb_subchannel + (3 * seg_offset)) % 41) / 3;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001146 sub_channel -= 6;
1147
Olivier Grenie4c70e072011-01-03 15:33:37 -03001148 if (state->fe[0]->dtv_property_cache.transmission_mode == TRANSMISSION_MODE_2K
1149 || state->fe[0]->dtv_property_cache.transmission_mode == TRANSMISSION_MODE_4K) {
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001150 dib8000_write_word(state, 219, dib8000_read_word(state, 219) | 0x1); //adp_pass =1
1151 dib8000_write_word(state, 190, dib8000_read_word(state, 190) | (0x1 << 14)); //pha3_force_pha_shift = 1
1152 } else {
1153 dib8000_write_word(state, 219, dib8000_read_word(state, 219) & 0xfffe); //adp_pass =0
1154 dib8000_write_word(state, 190, dib8000_read_word(state, 190) & 0xbfff); //pha3_force_pha_shift = 0
1155 }
1156
Olivier Grenie4c70e072011-01-03 15:33:37 -03001157 switch (state->fe[0]->dtv_property_cache.transmission_mode) {
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001158 case TRANSMISSION_MODE_2K:
1159 switch (sub_channel) {
1160 case -6:
1161 init_prbs = 0x0;
1162 break; // 41, 0, 1
1163 case -5:
1164 init_prbs = 0x423;
1165 break; // 02~04
1166 case -4:
1167 init_prbs = 0x9;
1168 break; // 05~07
1169 case -3:
1170 init_prbs = 0x5C7;
1171 break; // 08~10
1172 case -2:
1173 init_prbs = 0x7A6;
1174 break; // 11~13
1175 case -1:
1176 init_prbs = 0x3D8;
1177 break; // 14~16
1178 case 0:
1179 init_prbs = 0x527;
1180 break; // 17~19
1181 case 1:
1182 init_prbs = 0x7FF;
1183 break; // 20~22
1184 case 2:
1185 init_prbs = 0x79B;
1186 break; // 23~25
1187 case 3:
1188 init_prbs = 0x3D6;
1189 break; // 26~28
1190 case 4:
1191 init_prbs = 0x3A2;
1192 break; // 29~31
1193 case 5:
1194 init_prbs = 0x53B;
1195 break; // 32~34
1196 case 6:
1197 init_prbs = 0x2F4;
1198 break; // 35~37
1199 default:
1200 case 7:
1201 init_prbs = 0x213;
1202 break; // 38~40
1203 }
1204 break;
1205
1206 case TRANSMISSION_MODE_4K:
1207 switch (sub_channel) {
1208 case -6:
1209 init_prbs = 0x0;
1210 break; // 41, 0, 1
1211 case -5:
1212 init_prbs = 0x208;
1213 break; // 02~04
1214 case -4:
1215 init_prbs = 0xC3;
1216 break; // 05~07
1217 case -3:
1218 init_prbs = 0x7B9;
1219 break; // 08~10
1220 case -2:
1221 init_prbs = 0x423;
1222 break; // 11~13
1223 case -1:
1224 init_prbs = 0x5C7;
1225 break; // 14~16
1226 case 0:
1227 init_prbs = 0x3D8;
1228 break; // 17~19
1229 case 1:
1230 init_prbs = 0x7FF;
1231 break; // 20~22
1232 case 2:
1233 init_prbs = 0x3D6;
1234 break; // 23~25
1235 case 3:
1236 init_prbs = 0x53B;
1237 break; // 26~28
1238 case 4:
1239 init_prbs = 0x213;
1240 break; // 29~31
1241 case 5:
1242 init_prbs = 0x29;
1243 break; // 32~34
1244 case 6:
1245 init_prbs = 0xD0;
1246 break; // 35~37
1247 default:
1248 case 7:
1249 init_prbs = 0x48E;
1250 break; // 38~40
1251 }
1252 break;
1253
1254 default:
1255 case TRANSMISSION_MODE_8K:
1256 switch (sub_channel) {
1257 case -6:
1258 init_prbs = 0x0;
1259 break; // 41, 0, 1
1260 case -5:
1261 init_prbs = 0x740;
1262 break; // 02~04
1263 case -4:
1264 init_prbs = 0x069;
1265 break; // 05~07
1266 case -3:
1267 init_prbs = 0x7DD;
1268 break; // 08~10
1269 case -2:
1270 init_prbs = 0x208;
1271 break; // 11~13
1272 case -1:
1273 init_prbs = 0x7B9;
1274 break; // 14~16
1275 case 0:
1276 init_prbs = 0x5C7;
1277 break; // 17~19
1278 case 1:
1279 init_prbs = 0x7FF;
1280 break; // 20~22
1281 case 2:
1282 init_prbs = 0x53B;
1283 break; // 23~25
1284 case 3:
1285 init_prbs = 0x29;
1286 break; // 26~28
1287 case 4:
1288 init_prbs = 0x48E;
1289 break; // 29~31
1290 case 5:
1291 init_prbs = 0x4C4;
1292 break; // 32~34
1293 case 6:
1294 init_prbs = 0x367;
1295 break; // 33~37
1296 default:
1297 case 7:
1298 init_prbs = 0x684;
1299 break; // 38~40
1300 }
1301 break;
1302 }
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001303 } else {
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001304 dib8000_write_word(state, 27, (u16) ((state->cfg.pll->ifreq >> 16) & 0x01ff));
1305 dib8000_write_word(state, 28, (u16) (state->cfg.pll->ifreq & 0xffff));
1306 dib8000_write_word(state, 26, (u16) ((state->cfg.pll->ifreq >> 25) & 0x0003));
1307 }
1308 /*P_mode == ?? */
1309 dib8000_write_word(state, 10, (seq << 4));
1310 // dib8000_write_word(state, 287, (dib8000_read_word(state, 287) & 0xe000) | 0x1000);
1311
Olivier Grenie4c70e072011-01-03 15:33:37 -03001312 switch (state->fe[0]->dtv_property_cache.guard_interval) {
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001313 case GUARD_INTERVAL_1_32:
1314 guard = 0;
1315 break;
1316 case GUARD_INTERVAL_1_16:
1317 guard = 1;
1318 break;
1319 case GUARD_INTERVAL_1_8:
1320 guard = 2;
1321 break;
1322 case GUARD_INTERVAL_1_4:
1323 default:
1324 guard = 3;
1325 break;
1326 }
1327
1328 dib8000_write_word(state, 1, (init_prbs << 2) | (guard & 0x3)); // ADDR 1
1329
1330 max_constellation = DQPSK;
1331 for (i = 0; i < 3; i++) {
Olivier Grenie4c70e072011-01-03 15:33:37 -03001332 switch (state->fe[0]->dtv_property_cache.layer[i].modulation) {
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001333 case DQPSK:
1334 constellation = 0;
1335 break;
1336 case QPSK:
1337 constellation = 1;
1338 break;
1339 case QAM_16:
1340 constellation = 2;
1341 break;
1342 case QAM_64:
1343 default:
1344 constellation = 3;
1345 break;
1346 }
1347
Olivier Grenie4c70e072011-01-03 15:33:37 -03001348 switch (state->fe[0]->dtv_property_cache.layer[i].fec) {
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001349 case FEC_1_2:
1350 crate = 1;
1351 break;
1352 case FEC_2_3:
1353 crate = 2;
1354 break;
1355 case FEC_3_4:
1356 crate = 3;
1357 break;
1358 case FEC_5_6:
1359 crate = 5;
1360 break;
1361 case FEC_7_8:
1362 default:
1363 crate = 7;
1364 break;
1365 }
1366
Olivier Grenie4c70e072011-01-03 15:33:37 -03001367 if ((state->fe[0]->dtv_property_cache.layer[i].interleaving > 0) &&
1368 ((state->fe[0]->dtv_property_cache.layer[i].interleaving <= 3) ||
1369 (state->fe[0]->dtv_property_cache.layer[i].interleaving == 4 && state->fe[0]->dtv_property_cache.isdbt_sb_mode == 1))
1370 )
1371 timeI = state->fe[0]->dtv_property_cache.layer[i].interleaving;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001372 else
1373 timeI = 0;
Olivier Grenie4c70e072011-01-03 15:33:37 -03001374 dib8000_write_word(state, 2 + i, (constellation << 10) | ((state->fe[0]->dtv_property_cache.layer[i].segment_count & 0xf) << 6) |
1375 (crate << 3) | timeI);
1376 if (state->fe[0]->dtv_property_cache.layer[i].segment_count > 0) {
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001377 switch (max_constellation) {
1378 case DQPSK:
1379 case QPSK:
Olivier Grenie4c70e072011-01-03 15:33:37 -03001380 if (state->fe[0]->dtv_property_cache.layer[i].modulation == QAM_16 ||
1381 state->fe[0]->dtv_property_cache.layer[i].modulation == QAM_64)
1382 max_constellation = state->fe[0]->dtv_property_cache.layer[i].modulation;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001383 break;
1384 case QAM_16:
Olivier Grenie4c70e072011-01-03 15:33:37 -03001385 if (state->fe[0]->dtv_property_cache.layer[i].modulation == QAM_64)
1386 max_constellation = state->fe[0]->dtv_property_cache.layer[i].modulation;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001387 break;
1388 }
1389 }
1390 }
1391
1392 mode = fft_to_mode(state);
1393
1394 //dib8000_write_word(state, 5, 13); /*p_last_seg = 13*/
1395
1396 dib8000_write_word(state, 274, (dib8000_read_word(state, 274) & 0xffcf) |
Olivier Grenie4c70e072011-01-03 15:33:37 -03001397 ((state->fe[0]->dtv_property_cache.isdbt_partial_reception & 1) << 5) | ((state->fe[0]->dtv_property_cache.
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001398 isdbt_sb_mode & 1) << 4));
1399
Olivier Grenie4c70e072011-01-03 15:33:37 -03001400 dprintk("mode = %d ; guard = %d", mode, state->fe[0]->dtv_property_cache.guard_interval);
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001401
1402 /* signal optimization parameter */
1403
Olivier Grenie4c70e072011-01-03 15:33:37 -03001404 if (state->fe[0]->dtv_property_cache.isdbt_partial_reception) {
1405 seg_diff_mask = (state->fe[0]->dtv_property_cache.layer[0].modulation == DQPSK) << permu_seg[0];
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001406 for (i = 1; i < 3; i++)
1407 nbseg_diff +=
Olivier Grenie4c70e072011-01-03 15:33:37 -03001408 (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 -03001409 for (i = 0; i < nbseg_diff; i++)
1410 seg_diff_mask |= 1 << permu_seg[i + 1];
1411 } else {
1412 for (i = 0; i < 3; i++)
1413 nbseg_diff +=
Olivier Grenie4c70e072011-01-03 15:33:37 -03001414 (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 -03001415 for (i = 0; i < nbseg_diff; i++)
1416 seg_diff_mask |= 1 << permu_seg[i];
1417 }
1418 dprintk("nbseg_diff = %X (%d)", seg_diff_mask, seg_diff_mask);
1419
1420 state->differential_constellation = (seg_diff_mask != 0);
Olivier Grenie4c70e072011-01-03 15:33:37 -03001421 dib8000_set_diversity_in(state->fe[0], state->diversity_onoff);
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001422
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001423 if (state->fe[0]->dtv_property_cache.isdbt_sb_mode == 1) {
1424 if (state->fe[0]->dtv_property_cache.isdbt_partial_reception == 1)
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001425 seg_mask13 = 0x00E0;
1426 else // 1-segment
1427 seg_mask13 = 0x0040;
1428 } else
1429 seg_mask13 = 0x1fff;
1430
1431 // WRITE: Mode & Diff mask
1432 dib8000_write_word(state, 0, (mode << 13) | seg_diff_mask);
1433
Olivier Grenie4c70e072011-01-03 15:33:37 -03001434 if ((seg_diff_mask) || (state->fe[0]->dtv_property_cache.isdbt_sb_mode))
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001435 dib8000_write_word(state, 268, (dib8000_read_word(state, 268) & 0xF9FF) | 0x0200);
1436 else
1437 dib8000_write_word(state, 268, (2 << 9) | 39); //init value
1438
1439 // ---- SMALL ----
1440 // P_small_seg_diff
1441 dib8000_write_word(state, 352, seg_diff_mask); // ADDR 352
1442
1443 dib8000_write_word(state, 353, seg_mask13); // ADDR 353
1444
Olivier Grenie4c70e072011-01-03 15:33:37 -03001445/* // P_small_narrow_band=0, P_small_last_seg=13, P_small_offset_num_car=5 */
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001446
1447 // ---- SMALL ----
Olivier Grenie4c70e072011-01-03 15:33:37 -03001448 if (state->fe[0]->dtv_property_cache.isdbt_sb_mode == 1) {
1449 switch (state->fe[0]->dtv_property_cache.transmission_mode) {
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001450 case TRANSMISSION_MODE_2K:
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001451 if (state->fe[0]->dtv_property_cache.isdbt_partial_reception == 0) {
1452 if (state->fe[0]->dtv_property_cache.layer[0].modulation == DQPSK)
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001453 ncoeff = coeff_2k_sb_1seg_dqpsk;
1454 else // QPSK or QAM
1455 ncoeff = coeff_2k_sb_1seg;
1456 } else { // 3-segments
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001457 if (state->fe[0]->dtv_property_cache.layer[0].modulation == DQPSK) {
1458 if (state->fe[0]->dtv_property_cache.layer[1].modulation == DQPSK)
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001459 ncoeff = coeff_2k_sb_3seg_0dqpsk_1dqpsk;
1460 else // QPSK or QAM on external segments
1461 ncoeff = coeff_2k_sb_3seg_0dqpsk;
1462 } else { // QPSK or QAM on central segment
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001463 if (state->fe[0]->dtv_property_cache.layer[1].modulation == DQPSK)
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001464 ncoeff = coeff_2k_sb_3seg_1dqpsk;
1465 else // QPSK or QAM on external segments
1466 ncoeff = coeff_2k_sb_3seg;
1467 }
1468 }
1469 break;
1470
1471 case TRANSMISSION_MODE_4K:
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001472 if (state->fe[0]->dtv_property_cache.isdbt_partial_reception == 0) {
1473 if (state->fe[0]->dtv_property_cache.layer[0].modulation == DQPSK)
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001474 ncoeff = coeff_4k_sb_1seg_dqpsk;
1475 else // QPSK or QAM
1476 ncoeff = coeff_4k_sb_1seg;
1477 } else { // 3-segments
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001478 if (state->fe[0]->dtv_property_cache.layer[0].modulation == DQPSK) {
1479 if (state->fe[0]->dtv_property_cache.layer[1].modulation == DQPSK) {
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001480 ncoeff = coeff_4k_sb_3seg_0dqpsk_1dqpsk;
1481 } else { // QPSK or QAM on external segments
1482 ncoeff = coeff_4k_sb_3seg_0dqpsk;
1483 }
1484 } else { // QPSK or QAM on central segment
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001485 if (state->fe[0]->dtv_property_cache.layer[1].modulation == DQPSK) {
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001486 ncoeff = coeff_4k_sb_3seg_1dqpsk;
1487 } else // QPSK or QAM on external segments
1488 ncoeff = coeff_4k_sb_3seg;
1489 }
1490 }
1491 break;
1492
1493 case TRANSMISSION_MODE_AUTO:
1494 case TRANSMISSION_MODE_8K:
1495 default:
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001496 if (state->fe[0]->dtv_property_cache.isdbt_partial_reception == 0) {
1497 if (state->fe[0]->dtv_property_cache.layer[0].modulation == DQPSK)
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001498 ncoeff = coeff_8k_sb_1seg_dqpsk;
1499 else // QPSK or QAM
1500 ncoeff = coeff_8k_sb_1seg;
1501 } else { // 3-segments
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001502 if (state->fe[0]->dtv_property_cache.layer[0].modulation == DQPSK) {
1503 if (state->fe[0]->dtv_property_cache.layer[1].modulation == DQPSK) {
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001504 ncoeff = coeff_8k_sb_3seg_0dqpsk_1dqpsk;
1505 } else { // QPSK or QAM on external segments
1506 ncoeff = coeff_8k_sb_3seg_0dqpsk;
1507 }
1508 } else { // QPSK or QAM on central segment
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001509 if (state->fe[0]->dtv_property_cache.layer[1].modulation == DQPSK) {
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001510 ncoeff = coeff_8k_sb_3seg_1dqpsk;
1511 } else // QPSK or QAM on external segments
1512 ncoeff = coeff_8k_sb_3seg;
1513 }
1514 }
1515 break;
1516 }
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001517 for (i = 0; i < 8; i++)
1518 dib8000_write_word(state, 343 + i, ncoeff[i]);
Márton Németh6e8fdbd2009-11-22 18:52:37 -03001519 }
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001520
1521 // P_small_coef_ext_enable=ISDB-Tsb, P_small_narrow_band=ISDB-Tsb, P_small_last_seg=13, P_small_offset_num_car=5
1522 dib8000_write_word(state, 351,
Olivier Grenie4c70e072011-01-03 15:33:37 -03001523 (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 -03001524
1525 // ---- COFF ----
1526 // Carloff, the most robust
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001527 if (state->fe[0]->dtv_property_cache.isdbt_sb_mode == 1) {
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001528
1529 // P_coff_cpil_alpha=4, P_coff_inh=0, P_coff_cpil_winlen=64
1530 // 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
1531 dib8000_write_word(state, 187,
Olivier Grenie4c70e072011-01-03 15:33:37 -03001532 (4 << 12) | (0 << 11) | (63 << 5) | (0x3 << 3) | ((~state->fe[0]->dtv_property_cache.isdbt_partial_reception & 1) << 2)
1533 | 0x3);
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001534
Olivier Grenie4c70e072011-01-03 15:33:37 -03001535/* // P_small_coef_ext_enable = 1 */
1536/* dib8000_write_word(state, 351, dib8000_read_word(state, 351) | 0x200); */
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001537
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001538 if (state->fe[0]->dtv_property_cache.isdbt_partial_reception == 0) {
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001539
1540 // 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)
1541 if (mode == 3)
1542 dib8000_write_word(state, 180, 0x1fcf | ((mode - 1) << 14));
1543 else
1544 dib8000_write_word(state, 180, 0x0fcf | ((mode - 1) << 14));
1545 // P_ctrl_corm_thres4pre_freq_inh=1,P_ctrl_pre_freq_mode_sat=1,
1546 // P_ctrl_pre_freq_inh=0, P_ctrl_pre_freq_step = 5, P_pre_freq_win_len=4
1547 dib8000_write_word(state, 338, (1 << 12) | (1 << 10) | (0 << 9) | (5 << 5) | 4);
1548 // P_ctrl_pre_freq_win_len=16, P_ctrl_pre_freq_thres_lockin=8
1549 dib8000_write_word(state, 340, (16 << 6) | (8 << 0));
1550 // P_ctrl_pre_freq_thres_lockout=6, P_small_use_tmcc/ac/cp=1
1551 dib8000_write_word(state, 341, (6 << 3) | (1 << 2) | (1 << 1) | (1 << 0));
1552
1553 // P_coff_corthres_8k, 4k, 2k and P_coff_cpilthres_8k, 4k, 2k
1554 dib8000_write_word(state, 181, 300);
1555 dib8000_write_word(state, 182, 150);
1556 dib8000_write_word(state, 183, 80);
1557 dib8000_write_word(state, 184, 300);
1558 dib8000_write_word(state, 185, 150);
1559 dib8000_write_word(state, 186, 80);
1560 } else { // Sound Broadcasting mode 3 seg
1561 // 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 -03001562 /* if (mode == 3) */
1563 /* dib8000_write_word(state, 180, 0x2fca | ((0) << 14)); */
1564 /* else */
1565 /* dib8000_write_word(state, 180, 0x2fca | ((1) << 14)); */
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001566 dib8000_write_word(state, 180, 0x1fcf | (1 << 14));
1567
1568 // P_ctrl_corm_thres4pre_freq_inh = 1, P_ctrl_pre_freq_mode_sat=1,
1569 // P_ctrl_pre_freq_inh=0, P_ctrl_pre_freq_step = 4, P_pre_freq_win_len=4
1570 dib8000_write_word(state, 338, (1 << 12) | (1 << 10) | (0 << 9) | (4 << 5) | 4);
1571 // P_ctrl_pre_freq_win_len=16, P_ctrl_pre_freq_thres_lockin=8
1572 dib8000_write_word(state, 340, (16 << 6) | (8 << 0));
1573 //P_ctrl_pre_freq_thres_lockout=6, P_small_use_tmcc/ac/cp=1
1574 dib8000_write_word(state, 341, (6 << 3) | (1 << 2) | (1 << 1) | (1 << 0));
1575
1576 // P_coff_corthres_8k, 4k, 2k and P_coff_cpilthres_8k, 4k, 2k
1577 dib8000_write_word(state, 181, 350);
1578 dib8000_write_word(state, 182, 300);
1579 dib8000_write_word(state, 183, 250);
1580 dib8000_write_word(state, 184, 350);
1581 dib8000_write_word(state, 185, 300);
1582 dib8000_write_word(state, 186, 250);
1583 }
1584
1585 } else if (state->isdbt_cfg_loaded == 0) { // if not Sound Broadcasting mode : put default values for 13 segments
1586 dib8000_write_word(state, 180, (16 << 6) | 9);
1587 dib8000_write_word(state, 187, (4 << 12) | (8 << 5) | 0x2);
1588 coff_pow = 0x2800;
1589 for (i = 0; i < 6; i++)
1590 dib8000_write_word(state, 181 + i, coff_pow);
1591
1592 // P_ctrl_corm_thres4pre_freq_inh=1, P_ctrl_pre_freq_mode_sat=1,
1593 // 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
1594 dib8000_write_word(state, 338, (1 << 12) | (1 << 10) | (0 << 9) | (3 << 5) | 1);
1595
1596 // P_ctrl_pre_freq_win_len=8, P_ctrl_pre_freq_thres_lockin=6
1597 dib8000_write_word(state, 340, (8 << 6) | (6 << 0));
1598 // P_ctrl_pre_freq_thres_lockout=4, P_small_use_tmcc/ac/cp=1
1599 dib8000_write_word(state, 341, (4 << 3) | (1 << 2) | (1 << 1) | (1 << 0));
1600 }
1601 // ---- FFT ----
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001602 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 -03001603 dib8000_write_word(state, 178, 64); // P_fft_powrange=64
1604 else
1605 dib8000_write_word(state, 178, 32); // P_fft_powrange=32
1606
1607 /* make the cpil_coff_lock more robust but slower p_coff_winlen
1608 * 6bits; p_coff_thres_lock 6bits (for coff lock if needed)
1609 */
1610 /* if ( ( nbseg_diff>0)&&(nbseg_diff<13))
Olivier Grenie4c70e072011-01-03 15:33:37 -03001611 dib8000_write_word(state, 187, (dib8000_read_word(state, 187) & 0xfffb) | (1 << 3)); */
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001612
1613 dib8000_write_word(state, 189, ~seg_mask13 | seg_diff_mask); /* P_lmod4_seg_inh */
1614 dib8000_write_word(state, 192, ~seg_mask13 | seg_diff_mask); /* P_pha3_seg_inh */
1615 dib8000_write_word(state, 225, ~seg_mask13 | seg_diff_mask); /* P_tac_seg_inh */
Olivier Grenie4c70e072011-01-03 15:33:37 -03001616 if ((!state->fe[0]->dtv_property_cache.isdbt_sb_mode) && (state->cfg.pll->ifreq == 0))
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001617 dib8000_write_word(state, 266, ~seg_mask13 | seg_diff_mask | 0x40); /* P_equal_noise_seg_inh */
1618 else
1619 dib8000_write_word(state, 266, ~seg_mask13 | seg_diff_mask); /* P_equal_noise_seg_inh */
1620 dib8000_write_word(state, 287, ~seg_mask13 | 0x1000); /* P_tmcc_seg_inh */
1621 //dib8000_write_word(state, 288, ~seg_mask13 | seg_diff_mask); /* P_tmcc_seg_eq_inh */
1622 if (!autosearching)
1623 dib8000_write_word(state, 288, (~seg_mask13 | seg_diff_mask) & 0x1fff); /* P_tmcc_seg_eq_inh */
1624 else
1625 dib8000_write_word(state, 288, 0x1fff); //disable equalisation of the tmcc when autosearch to be able to find the DQPSK channels.
1626 dprintk("287 = %X (%d)", ~seg_mask13 | 0x1000, ~seg_mask13 | 0x1000);
1627
1628 dib8000_write_word(state, 211, seg_mask13 & (~seg_diff_mask)); /* P_des_seg_enabled */
1629
1630 /* offset loop parameters */
Olivier Grenie4c70e072011-01-03 15:33:37 -03001631 if (state->fe[0]->dtv_property_cache.isdbt_sb_mode == 1) {
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001632 if (state->fe[0]->dtv_property_cache.isdbt_partial_reception == 0)
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001633 /* P_timf_alpha = (11-P_mode), P_corm_alpha=6, P_corm_thres=0x80 */
1634 dib8000_write_word(state, 32, ((11 - mode) << 12) | (6 << 8) | 0x40);
1635
1636 else // Sound Broadcasting mode 3 seg
1637 /* P_timf_alpha = (10-P_mode), P_corm_alpha=6, P_corm_thres=0x80 */
1638 dib8000_write_word(state, 32, ((10 - mode) << 12) | (6 << 8) | 0x60);
1639 } else
1640 // TODO in 13 seg, timf_alpha can always be the same or not ?
1641 /* P_timf_alpha = (9-P_mode, P_corm_alpha=6, P_corm_thres=0x80 */
1642 dib8000_write_word(state, 32, ((9 - mode) << 12) | (6 << 8) | 0x80);
1643
Olivier Grenie4c70e072011-01-03 15:33:37 -03001644 if (state->fe[0]->dtv_property_cache.isdbt_sb_mode == 1) {
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001645 if (state->fe[0]->dtv_property_cache.isdbt_partial_reception == 0)
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001646 /* P_ctrl_pha_off_max=3 P_ctrl_sfreq_inh =0 P_ctrl_sfreq_step = (11-P_mode) */
1647 dib8000_write_word(state, 37, (3 << 5) | (0 << 4) | (10 - mode));
1648
1649 else // Sound Broadcasting mode 3 seg
1650 /* P_ctrl_pha_off_max=3 P_ctrl_sfreq_inh =0 P_ctrl_sfreq_step = (10-P_mode) */
1651 dib8000_write_word(state, 37, (3 << 5) | (0 << 4) | (9 - mode));
1652 } else
1653 /* P_ctrl_pha_off_max=3 P_ctrl_sfreq_inh =0 P_ctrl_sfreq_step = 9 */
1654 dib8000_write_word(state, 37, (3 << 5) | (0 << 4) | (8 - mode));
1655
1656 /* P_dvsy_sync_wait - reuse mode */
Olivier Grenie4c70e072011-01-03 15:33:37 -03001657 switch (state->fe[0]->dtv_property_cache.transmission_mode) {
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001658 case TRANSMISSION_MODE_8K:
1659 mode = 256;
1660 break;
1661 case TRANSMISSION_MODE_4K:
1662 mode = 128;
1663 break;
1664 default:
1665 case TRANSMISSION_MODE_2K:
1666 mode = 64;
1667 break;
1668 }
1669 if (state->cfg.diversity_delay == 0)
1670 mode = (mode * (1 << (guard)) * 3) / 2 + 48; // add 50% SFN margin + compensate for one DVSY-fifo
1671 else
1672 mode = (mode * (1 << (guard)) * 3) / 2 + state->cfg.diversity_delay; // add 50% SFN margin + compensate for DVSY-fifo
1673 mode <<= 4;
1674 dib8000_write_word(state, 273, (dib8000_read_word(state, 273) & 0x000f) | mode);
1675
1676 /* channel estimation fine configuration */
1677 switch (max_constellation) {
1678 case QAM_64:
1679 ana_gain = 0x7; // -1 : avoid def_est saturation when ADC target is -16dB
1680 coeff[0] = 0x0148; /* P_adp_regul_cnt 0.04 */
1681 coeff[1] = 0xfff0; /* P_adp_noise_cnt -0.002 */
1682 coeff[2] = 0x00a4; /* P_adp_regul_ext 0.02 */
1683 coeff[3] = 0xfff8; /* P_adp_noise_ext -0.001 */
1684 //if (!state->cfg.hostbus_diversity) //if diversity, we should prehaps use the configuration of the max_constallation -1
1685 break;
1686 case QAM_16:
1687 ana_gain = 0x7; // -1 : avoid def_est saturation when ADC target is -16dB
1688 coeff[0] = 0x023d; /* P_adp_regul_cnt 0.07 */
1689 coeff[1] = 0xffdf; /* P_adp_noise_cnt -0.004 */
1690 coeff[2] = 0x00a4; /* P_adp_regul_ext 0.02 */
1691 coeff[3] = 0xfff0; /* P_adp_noise_ext -0.002 */
1692 //if (!((state->cfg.hostbus_diversity) && (max_constellation == QAM_16)))
1693 break;
1694 default:
1695 ana_gain = 0; // 0 : goes along with ADC target at -22dB to keep good mobile performance and lock at sensitivity level
1696 coeff[0] = 0x099a; /* P_adp_regul_cnt 0.3 */
1697 coeff[1] = 0xffae; /* P_adp_noise_cnt -0.01 */
1698 coeff[2] = 0x0333; /* P_adp_regul_ext 0.1 */
1699 coeff[3] = 0xfff8; /* P_adp_noise_ext -0.002 */
1700 break;
1701 }
1702 for (mode = 0; mode < 4; mode++)
1703 dib8000_write_word(state, 215 + mode, coeff[mode]);
1704
1705 // update ana_gain depending on max constellation
1706 dib8000_write_word(state, 116, ana_gain);
1707 // update ADC target depending on ana_gain
1708 if (ana_gain) { // set -16dB ADC target for ana_gain=-1
1709 for (i = 0; i < 10; i++)
1710 dib8000_write_word(state, 80 + i, adc_target_16dB[i]);
1711 } else { // set -22dB ADC target for ana_gain=0
1712 for (i = 0; i < 10; i++)
1713 dib8000_write_word(state, 80 + i, adc_target_16dB[i] - 355);
1714 }
1715
1716 // ---- ANA_FE ----
Olivier Grenie4c70e072011-01-03 15:33:37 -03001717 if (state->fe[0]->dtv_property_cache.isdbt_sb_mode) {
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001718 if (state->fe[0]->dtv_property_cache.isdbt_partial_reception == 1)
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001719 ana_fe = ana_fe_coeff_3seg;
1720 else // 1-segment
1721 ana_fe = ana_fe_coeff_1seg;
1722 } else
1723 ana_fe = ana_fe_coeff_13seg;
1724
Olivier Grenie4c70e072011-01-03 15:33:37 -03001725 if (state->fe[0]->dtv_property_cache.isdbt_sb_mode == 1 || state->isdbt_cfg_loaded == 0)
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001726 for (mode = 0; mode < 24; mode++)
1727 dib8000_write_word(state, 117 + mode, ana_fe[mode]);
1728
1729 // ---- CHAN_BLK ----
1730 for (i = 0; i < 13; i++) {
1731 if ((((~seg_diff_mask) >> i) & 1) == 1) {
1732 P_cfr_left_edge += (1 << i) * ((i == 0) || ((((seg_mask13 & (~seg_diff_mask)) >> (i - 1)) & 1) == 0));
1733 P_cfr_right_edge += (1 << i) * ((i == 12) || ((((seg_mask13 & (~seg_diff_mask)) >> (i + 1)) & 1) == 0));
1734 }
1735 }
1736 dib8000_write_word(state, 222, P_cfr_left_edge); // P_cfr_left_edge
1737 dib8000_write_word(state, 223, P_cfr_right_edge); // P_cfr_right_edge
1738 // "P_cspu_left_edge" not used => do not care
1739 // "P_cspu_right_edge" not used => do not care
1740
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001741 if (state->fe[0]->dtv_property_cache.isdbt_sb_mode == 1) {
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001742 dib8000_write_word(state, 228, 1); // P_2d_mode_byp=1
1743 dib8000_write_word(state, 205, dib8000_read_word(state, 205) & 0xfff0); // P_cspu_win_cut = 0
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001744 if (state->fe[0]->dtv_property_cache.isdbt_partial_reception == 0
Olivier Grenie4c70e072011-01-03 15:33:37 -03001745 && state->fe[0]->dtv_property_cache.transmission_mode == TRANSMISSION_MODE_2K) {
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001746 //dib8000_write_word(state, 219, dib8000_read_word(state, 219) & 0xfffe); // P_adp_pass = 0
1747 dib8000_write_word(state, 265, 15); // P_equal_noise_sel = 15
1748 }
1749 } else if (state->isdbt_cfg_loaded == 0) {
1750 dib8000_write_word(state, 228, 0); // default value
1751 dib8000_write_word(state, 265, 31); // default value
1752 dib8000_write_word(state, 205, 0x200f); // init value
1753 }
1754 // ---- TMCC ----
1755 for (i = 0; i < 3; i++)
1756 tmcc_pow +=
Olivier Grenie4c70e072011-01-03 15:33:37 -03001757 (((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 -03001758 // Quantif of "P_tmcc_dec_thres_?k" is (0, 5+mode, 9);
1759 // Threshold is set at 1/4 of max power.
1760 tmcc_pow *= (1 << (9 - 2));
1761
1762 dib8000_write_word(state, 290, tmcc_pow); // P_tmcc_dec_thres_2k
1763 dib8000_write_word(state, 291, tmcc_pow); // P_tmcc_dec_thres_4k
1764 dib8000_write_word(state, 292, tmcc_pow); // P_tmcc_dec_thres_8k
1765 //dib8000_write_word(state, 287, (1 << 13) | 0x1000 );
1766 // ---- PHA3 ----
1767
1768 if (state->isdbt_cfg_loaded == 0)
1769 dib8000_write_word(state, 250, 3285); /*p_2d_hspeed_thr0 */
1770
Olivier Grenie4c70e072011-01-03 15:33:37 -03001771 if (state->fe[0]->dtv_property_cache.isdbt_sb_mode == 1)
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001772 state->isdbt_cfg_loaded = 0;
1773 else
1774 state->isdbt_cfg_loaded = 1;
1775
1776}
1777
1778static int dib8000_autosearch_start(struct dvb_frontend *fe)
1779{
1780 u8 factor;
1781 u32 value;
1782 struct dib8000_state *state = fe->demodulator_priv;
1783
1784 int slist = 0;
1785
Olivier Grenie4c70e072011-01-03 15:33:37 -03001786 state->fe[0]->dtv_property_cache.inversion = 0;
1787 if (!state->fe[0]->dtv_property_cache.isdbt_sb_mode)
1788 state->fe[0]->dtv_property_cache.layer[0].segment_count = 13;
1789 state->fe[0]->dtv_property_cache.layer[0].modulation = QAM_64;
1790 state->fe[0]->dtv_property_cache.layer[0].fec = FEC_2_3;
1791 state->fe[0]->dtv_property_cache.layer[0].interleaving = 0;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001792
1793 //choose the right list, in sb, always do everything
Olivier Grenie4c70e072011-01-03 15:33:37 -03001794 if (state->fe[0]->dtv_property_cache.isdbt_sb_mode) {
1795 state->fe[0]->dtv_property_cache.transmission_mode = TRANSMISSION_MODE_8K;
1796 state->fe[0]->dtv_property_cache.guard_interval = GUARD_INTERVAL_1_8;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001797 slist = 7;
1798 dib8000_write_word(state, 0, (dib8000_read_word(state, 0) & 0x9fff) | (1 << 13));
1799 } else {
Olivier Grenie4c70e072011-01-03 15:33:37 -03001800 if (state->fe[0]->dtv_property_cache.guard_interval == GUARD_INTERVAL_AUTO) {
1801 if (state->fe[0]->dtv_property_cache.transmission_mode == TRANSMISSION_MODE_AUTO) {
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001802 slist = 7;
1803 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 -03001804 } else
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001805 slist = 3;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001806 } else {
Olivier Grenie4c70e072011-01-03 15:33:37 -03001807 if (state->fe[0]->dtv_property_cache.transmission_mode == TRANSMISSION_MODE_AUTO) {
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001808 slist = 2;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001809 dib8000_write_word(state, 0, (dib8000_read_word(state, 0) & 0x9fff) | (1 << 13)); // P_mode = 1
Patrick Boettcher78f3bc62009-08-17 12:53:51 -03001810 } else
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001811 slist = 0;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001812 }
1813
Olivier Grenie4c70e072011-01-03 15:33:37 -03001814 if (state->fe[0]->dtv_property_cache.transmission_mode == TRANSMISSION_MODE_AUTO)
1815 state->fe[0]->dtv_property_cache.transmission_mode = TRANSMISSION_MODE_8K;
1816 if (state->fe[0]->dtv_property_cache.guard_interval == GUARD_INTERVAL_AUTO)
1817 state->fe[0]->dtv_property_cache.guard_interval = GUARD_INTERVAL_1_8;
Patrick Boettcher78f3bc62009-08-17 12:53:51 -03001818
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001819 dprintk("using list for autosearch : %d", slist);
1820 dib8000_set_channel(state, (unsigned char)slist, 1);
1821 //dib8000_write_word(state, 0, (dib8000_read_word(state, 0) & 0x9fff) | (1 << 13)); // P_mode = 1
1822
1823 factor = 1;
1824
1825 //set lock_mask values
1826 dib8000_write_word(state, 6, 0x4);
1827 dib8000_write_word(state, 7, 0x8);
1828 dib8000_write_word(state, 8, 0x1000);
1829
1830 //set lock_mask wait time values
1831 value = 50 * state->cfg.pll->internal * factor;
1832 dib8000_write_word(state, 11, (u16) ((value >> 16) & 0xffff)); // lock0 wait time
1833 dib8000_write_word(state, 12, (u16) (value & 0xffff)); // lock0 wait time
1834 value = 100 * state->cfg.pll->internal * factor;
1835 dib8000_write_word(state, 13, (u16) ((value >> 16) & 0xffff)); // lock1 wait time
1836 dib8000_write_word(state, 14, (u16) (value & 0xffff)); // lock1 wait time
1837 value = 1000 * state->cfg.pll->internal * factor;
1838 dib8000_write_word(state, 15, (u16) ((value >> 16) & 0xffff)); // lock2 wait time
1839 dib8000_write_word(state, 16, (u16) (value & 0xffff)); // lock2 wait time
1840
1841 value = dib8000_read_word(state, 0);
1842 dib8000_write_word(state, 0, (u16) ((1 << 15) | value));
1843 dib8000_read_word(state, 1284); // reset the INT. n_irq_pending
1844 dib8000_write_word(state, 0, (u16) value);
Patrick Boettcher78f3bc62009-08-17 12:53:51 -03001845
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001846 }
1847
1848 return 0;
1849}
1850
1851static int dib8000_autosearch_irq(struct dvb_frontend *fe)
1852{
1853 struct dib8000_state *state = fe->demodulator_priv;
1854 u16 irq_pending = dib8000_read_word(state, 1284);
1855
1856 if (irq_pending & 0x1) { // failed
1857 dprintk("dib8000_autosearch_irq failed");
1858 return 1;
1859 }
1860
1861 if (irq_pending & 0x2) { // succeeded
1862 dprintk("dib8000_autosearch_irq succeeded");
1863 return 2;
1864 }
1865
1866 return 0; // still pending
1867}
1868
1869static int dib8000_tune(struct dvb_frontend *fe)
1870{
1871 struct dib8000_state *state = fe->demodulator_priv;
1872 int ret = 0;
1873 u16 value, mode = fft_to_mode(state);
1874
1875 // we are already tuned - just resuming from suspend
1876 if (state == NULL)
1877 return -EINVAL;
1878
Olivier Grenie4c70e072011-01-03 15:33:37 -03001879 dib8000_set_bandwidth(fe, state->fe[0]->dtv_property_cache.bandwidth_hz / 1000);
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001880 dib8000_set_channel(state, 0, 0);
1881
1882 // restart demod
1883 ret |= dib8000_write_word(state, 770, 0x4000);
1884 ret |= dib8000_write_word(state, 770, 0x0000);
1885 msleep(45);
1886
1887 /* P_ctrl_inh_cor=0, P_ctrl_alpha_cor=4, P_ctrl_inh_isi=0, P_ctrl_alpha_isi=3 */
1888 /* ret |= dib8000_write_word(state, 29, (0 << 9) | (4 << 5) | (0 << 4) | (3 << 0) ); workaround inh_isi stays at 1 */
1889
1890 // never achieved a lock before - wait for timfreq to update
1891 if (state->timf == 0) {
Olivier Grenie4c70e072011-01-03 15:33:37 -03001892 if (state->fe[0]->dtv_property_cache.isdbt_sb_mode == 1) {
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001893 if (state->fe[0]->dtv_property_cache.isdbt_partial_reception == 0)
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001894 msleep(300);
1895 else // Sound Broadcasting mode 3 seg
1896 msleep(500);
1897 } else // 13 seg
1898 msleep(200);
1899 }
Olivier Grenie4c70e072011-01-03 15:33:37 -03001900 if (state->fe[0]->dtv_property_cache.isdbt_sb_mode == 1) {
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001901 if (state->fe[0]->dtv_property_cache.isdbt_partial_reception == 0) {
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001902
1903 /* P_timf_alpha = (13-P_mode) , P_corm_alpha=6, P_corm_thres=0x40 alpha to check on board */
1904 dib8000_write_word(state, 32, ((13 - mode) << 12) | (6 << 8) | 0x40);
1905 //dib8000_write_word(state, 32, (8 << 12) | (6 << 8) | 0x80);
1906
1907 /* P_ctrl_sfreq_step= (12-P_mode) P_ctrl_sfreq_inh =0 P_ctrl_pha_off_max */
1908 ret |= dib8000_write_word(state, 37, (12 - mode) | ((5 + mode) << 5));
1909
1910 } else { // Sound Broadcasting mode 3 seg
1911
1912 /* P_timf_alpha = (12-P_mode) , P_corm_alpha=6, P_corm_thres=0x60 alpha to check on board */
1913 dib8000_write_word(state, 32, ((12 - mode) << 12) | (6 << 8) | 0x60);
1914
1915 ret |= dib8000_write_word(state, 37, (11 - mode) | ((5 + mode) << 5));
1916 }
1917
1918 } else { // 13 seg
1919 /* P_timf_alpha = 8 , P_corm_alpha=6, P_corm_thres=0x80 alpha to check on board */
1920 dib8000_write_word(state, 32, ((11 - mode) << 12) | (6 << 8) | 0x80);
1921
1922 ret |= dib8000_write_word(state, 37, (10 - mode) | ((5 + mode) << 5));
1923
1924 }
1925
1926 // we achieved a coff_cpil_lock - it's time to update the timf
1927 if ((dib8000_read_word(state, 568) >> 11) & 0x1)
1928 dib8000_update_timf(state);
1929
1930 //now that tune is finished, lock0 should lock on fec_mpeg to output this lock on MP_LOCK. It's changed in autosearch start
1931 dib8000_write_word(state, 6, 0x200);
1932
1933 if (state->revision == 0x8002) {
1934 value = dib8000_read_word(state, 903);
1935 dib8000_write_word(state, 903, value & ~(1 << 3));
1936 msleep(1);
1937 dib8000_write_word(state, 903, value | (1 << 3));
1938 }
1939
1940 return ret;
1941}
1942
1943static int dib8000_wakeup(struct dvb_frontend *fe)
1944{
1945 struct dib8000_state *state = fe->demodulator_priv;
Olivier Grenie4c70e072011-01-03 15:33:37 -03001946 u8 index_frontend;
1947 int ret;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001948
1949 dib8000_set_power_mode(state, DIB8000M_POWER_ALL);
1950 dib8000_set_adc_state(state, DIBX000_ADC_ON);
1951 if (dib8000_set_adc_state(state, DIBX000_SLOW_ADC_ON) != 0)
1952 dprintk("could not start Slow ADC");
1953
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001954 for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
Olivier Grenie4c70e072011-01-03 15:33:37 -03001955 ret = state->fe[index_frontend]->ops.init(state->fe[index_frontend]);
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001956 if (ret < 0)
Olivier Grenie4c70e072011-01-03 15:33:37 -03001957 return ret;
1958 }
1959
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001960 return 0;
1961}
1962
1963static int dib8000_sleep(struct dvb_frontend *fe)
1964{
Olivier Grenie4c70e072011-01-03 15:33:37 -03001965 struct dib8000_state *state = fe->demodulator_priv;
1966 u8 index_frontend;
1967 int ret;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001968
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03001969 for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
Olivier Grenie4c70e072011-01-03 15:33:37 -03001970 ret = state->fe[index_frontend]->ops.sleep(state->fe[index_frontend]);
1971 if (ret < 0)
1972 return ret;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001973 }
Olivier Grenie4c70e072011-01-03 15:33:37 -03001974
1975 dib8000_set_output_mode(fe, OUTMODE_HIGH_Z);
1976 dib8000_set_power_mode(state, DIB8000M_POWER_INTERFACE_ONLY);
1977 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 -03001978}
1979
Olivier Grenie9c783032009-12-07 07:49:40 -03001980enum frontend_tune_state dib8000_get_tune_state(struct dvb_frontend *fe)
Olivier Grenie03245a52009-12-04 13:27:57 -03001981{
1982 struct dib8000_state *state = fe->demodulator_priv;
1983 return state->tune_state;
1984}
1985EXPORT_SYMBOL(dib8000_get_tune_state);
1986
Olivier Grenie9c783032009-12-07 07:49:40 -03001987int dib8000_set_tune_state(struct dvb_frontend *fe, enum frontend_tune_state tune_state)
Olivier Grenie03245a52009-12-04 13:27:57 -03001988{
1989 struct dib8000_state *state = fe->demodulator_priv;
1990 state->tune_state = tune_state;
1991 return 0;
1992}
1993EXPORT_SYMBOL(dib8000_set_tune_state);
1994
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03001995static int dib8000_get_frontend(struct dvb_frontend *fe, struct dvb_frontend_parameters *fep)
1996{
1997 struct dib8000_state *state = fe->demodulator_priv;
1998 u16 i, val = 0;
Olivier Grenie4c70e072011-01-03 15:33:37 -03001999 fe_status_t stat;
2000 u8 index_frontend, sub_index_frontend;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002001
2002 fe->dtv_property_cache.bandwidth_hz = 6000000;
2003
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002004 for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
Olivier Grenie4c70e072011-01-03 15:33:37 -03002005 state->fe[index_frontend]->ops.read_status(state->fe[index_frontend], &stat);
2006 if (stat&FE_HAS_SYNC) {
2007 dprintk("TMCC lock on the slave%i", index_frontend);
2008 /* synchronize the cache with the other frontends */
2009 state->fe[index_frontend]->ops.get_frontend(state->fe[index_frontend], fep);
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002010 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 -03002011 if (sub_index_frontend != index_frontend) {
2012 state->fe[sub_index_frontend]->dtv_property_cache.isdbt_sb_mode = state->fe[index_frontend]->dtv_property_cache.isdbt_sb_mode;
2013 state->fe[sub_index_frontend]->dtv_property_cache.inversion = state->fe[index_frontend]->dtv_property_cache.inversion;
2014 state->fe[sub_index_frontend]->dtv_property_cache.transmission_mode = state->fe[index_frontend]->dtv_property_cache.transmission_mode;
2015 state->fe[sub_index_frontend]->dtv_property_cache.guard_interval = state->fe[index_frontend]->dtv_property_cache.guard_interval;
2016 state->fe[sub_index_frontend]->dtv_property_cache.isdbt_partial_reception = state->fe[index_frontend]->dtv_property_cache.isdbt_partial_reception;
2017 for (i = 0; i < 3; i++) {
2018 state->fe[sub_index_frontend]->dtv_property_cache.layer[i].segment_count = state->fe[index_frontend]->dtv_property_cache.layer[i].segment_count;
2019 state->fe[sub_index_frontend]->dtv_property_cache.layer[i].interleaving = state->fe[index_frontend]->dtv_property_cache.layer[i].interleaving;
2020 state->fe[sub_index_frontend]->dtv_property_cache.layer[i].fec = state->fe[index_frontend]->dtv_property_cache.layer[i].fec;
2021 state->fe[sub_index_frontend]->dtv_property_cache.layer[i].modulation = state->fe[index_frontend]->dtv_property_cache.layer[i].modulation;
2022 }
2023 }
2024 }
2025 return 0;
2026 }
2027 }
2028
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002029 fe->dtv_property_cache.isdbt_sb_mode = dib8000_read_word(state, 508) & 0x1;
2030
2031 val = dib8000_read_word(state, 570);
2032 fe->dtv_property_cache.inversion = (val & 0x40) >> 6;
2033 switch ((val & 0x30) >> 4) {
2034 case 1:
2035 fe->dtv_property_cache.transmission_mode = TRANSMISSION_MODE_2K;
2036 break;
2037 case 3:
2038 default:
2039 fe->dtv_property_cache.transmission_mode = TRANSMISSION_MODE_8K;
2040 break;
2041 }
2042
2043 switch (val & 0x3) {
2044 case 0:
2045 fe->dtv_property_cache.guard_interval = GUARD_INTERVAL_1_32;
2046 dprintk("dib8000_get_frontend GI = 1/32 ");
2047 break;
2048 case 1:
2049 fe->dtv_property_cache.guard_interval = GUARD_INTERVAL_1_16;
2050 dprintk("dib8000_get_frontend GI = 1/16 ");
2051 break;
2052 case 2:
2053 dprintk("dib8000_get_frontend GI = 1/8 ");
2054 fe->dtv_property_cache.guard_interval = GUARD_INTERVAL_1_8;
2055 break;
2056 case 3:
2057 dprintk("dib8000_get_frontend GI = 1/4 ");
2058 fe->dtv_property_cache.guard_interval = GUARD_INTERVAL_1_4;
2059 break;
2060 }
2061
2062 val = dib8000_read_word(state, 505);
2063 fe->dtv_property_cache.isdbt_partial_reception = val & 1;
2064 dprintk("dib8000_get_frontend : partial_reception = %d ", fe->dtv_property_cache.isdbt_partial_reception);
2065
2066 for (i = 0; i < 3; i++) {
2067 val = dib8000_read_word(state, 493 + i);
2068 fe->dtv_property_cache.layer[i].segment_count = val & 0x0F;
2069 dprintk("dib8000_get_frontend : Layer %d segments = %d ", i, fe->dtv_property_cache.layer[i].segment_count);
2070
2071 val = dib8000_read_word(state, 499 + i);
2072 fe->dtv_property_cache.layer[i].interleaving = val & 0x3;
2073 dprintk("dib8000_get_frontend : Layer %d time_intlv = %d ", i, fe->dtv_property_cache.layer[i].interleaving);
2074
2075 val = dib8000_read_word(state, 481 + i);
2076 switch (val & 0x7) {
2077 case 1:
2078 fe->dtv_property_cache.layer[i].fec = FEC_1_2;
2079 dprintk("dib8000_get_frontend : Layer %d Code Rate = 1/2 ", i);
2080 break;
2081 case 2:
2082 fe->dtv_property_cache.layer[i].fec = FEC_2_3;
2083 dprintk("dib8000_get_frontend : Layer %d Code Rate = 2/3 ", i);
2084 break;
2085 case 3:
2086 fe->dtv_property_cache.layer[i].fec = FEC_3_4;
2087 dprintk("dib8000_get_frontend : Layer %d Code Rate = 3/4 ", i);
2088 break;
2089 case 5:
2090 fe->dtv_property_cache.layer[i].fec = FEC_5_6;
2091 dprintk("dib8000_get_frontend : Layer %d Code Rate = 5/6 ", i);
2092 break;
2093 default:
2094 fe->dtv_property_cache.layer[i].fec = FEC_7_8;
2095 dprintk("dib8000_get_frontend : Layer %d Code Rate = 7/8 ", i);
2096 break;
2097 }
2098
2099 val = dib8000_read_word(state, 487 + i);
2100 switch (val & 0x3) {
2101 case 0:
2102 dprintk("dib8000_get_frontend : Layer %d DQPSK ", i);
2103 fe->dtv_property_cache.layer[i].modulation = DQPSK;
2104 break;
2105 case 1:
2106 fe->dtv_property_cache.layer[i].modulation = QPSK;
2107 dprintk("dib8000_get_frontend : Layer %d QPSK ", i);
2108 break;
2109 case 2:
2110 fe->dtv_property_cache.layer[i].modulation = QAM_16;
2111 dprintk("dib8000_get_frontend : Layer %d QAM16 ", i);
2112 break;
2113 case 3:
2114 default:
2115 dprintk("dib8000_get_frontend : Layer %d QAM64 ", i);
2116 fe->dtv_property_cache.layer[i].modulation = QAM_64;
2117 break;
2118 }
2119 }
Olivier Grenie4c70e072011-01-03 15:33:37 -03002120
2121 /* synchronize the cache with the other frontends */
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002122 for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
Olivier Grenie4c70e072011-01-03 15:33:37 -03002123 state->fe[index_frontend]->dtv_property_cache.isdbt_sb_mode = fe->dtv_property_cache.isdbt_sb_mode;
2124 state->fe[index_frontend]->dtv_property_cache.inversion = fe->dtv_property_cache.inversion;
2125 state->fe[index_frontend]->dtv_property_cache.transmission_mode = fe->dtv_property_cache.transmission_mode;
2126 state->fe[index_frontend]->dtv_property_cache.guard_interval = fe->dtv_property_cache.guard_interval;
2127 state->fe[index_frontend]->dtv_property_cache.isdbt_partial_reception = fe->dtv_property_cache.isdbt_partial_reception;
2128 for (i = 0; i < 3; i++) {
2129 state->fe[index_frontend]->dtv_property_cache.layer[i].segment_count = fe->dtv_property_cache.layer[i].segment_count;
2130 state->fe[index_frontend]->dtv_property_cache.layer[i].interleaving = fe->dtv_property_cache.layer[i].interleaving;
2131 state->fe[index_frontend]->dtv_property_cache.layer[i].fec = fe->dtv_property_cache.layer[i].fec;
2132 state->fe[index_frontend]->dtv_property_cache.layer[i].modulation = fe->dtv_property_cache.layer[i].modulation;
2133 }
2134 }
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002135 return 0;
2136}
2137
2138static int dib8000_set_frontend(struct dvb_frontend *fe, struct dvb_frontend_parameters *fep)
2139{
2140 struct dib8000_state *state = fe->demodulator_priv;
Olivier Grenie4c70e072011-01-03 15:33:37 -03002141 u8 nbr_pending, exit_condition, index_frontend;
2142 s8 index_frontend_success = -1;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002143 int time, ret;
Olivier Grenie4c70e072011-01-03 15:33:37 -03002144 int time_slave = FE_CALLBACK_TIME_NEVER;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002145
Olivier Grenie4c70e072011-01-03 15:33:37 -03002146 if (state->fe[0]->dtv_property_cache.frequency == 0) {
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002147 dprintk("dib8000: must at least specify frequency ");
2148 return 0;
2149 }
2150
Olivier Grenie4c70e072011-01-03 15:33:37 -03002151 if (state->fe[0]->dtv_property_cache.bandwidth_hz == 0) {
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002152 dprintk("dib8000: no bandwidth specified, set to default ");
Olivier Grenie4c70e072011-01-03 15:33:37 -03002153 state->fe[0]->dtv_property_cache.bandwidth_hz = 6000000;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002154 }
2155
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002156 for (index_frontend = 0; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
Olivier Grenie4c70e072011-01-03 15:33:37 -03002157 /* synchronization of the cache */
2158 state->fe[index_frontend]->dtv_property_cache.delivery_system = SYS_ISDBT;
2159 memcpy(&state->fe[index_frontend]->dtv_property_cache, &fe->dtv_property_cache, sizeof(struct dtv_frontend_properties));
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002160
Olivier Grenie4c70e072011-01-03 15:33:37 -03002161 dib8000_set_output_mode(state->fe[index_frontend], OUTMODE_HIGH_Z);
2162 if (state->fe[index_frontend]->ops.tuner_ops.set_params)
2163 state->fe[index_frontend]->ops.tuner_ops.set_params(state->fe[index_frontend], fep);
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002164
Olivier Grenie4c70e072011-01-03 15:33:37 -03002165 dib8000_set_tune_state(state->fe[index_frontend], CT_AGC_START);
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002166 }
2167
Olivier Grenie4c70e072011-01-03 15:33:37 -03002168 /* start up the AGC */
2169 do {
2170 time = dib8000_agc_startup(state->fe[0]);
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002171 for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
Olivier Grenie4c70e072011-01-03 15:33:37 -03002172 time_slave = dib8000_agc_startup(state->fe[index_frontend]);
2173 if (time == FE_CALLBACK_TIME_NEVER)
2174 time = time_slave;
2175 else if ((time_slave != FE_CALLBACK_TIME_NEVER) && (time_slave > time))
2176 time = time_slave;
2177 }
2178 if (time != FE_CALLBACK_TIME_NEVER)
2179 msleep(time / 10);
2180 else
2181 break;
2182 exit_condition = 1;
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002183 for (index_frontend = 0; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
Olivier Grenie4c70e072011-01-03 15:33:37 -03002184 if (dib8000_get_tune_state(state->fe[index_frontend]) != CT_AGC_STOP) {
2185 exit_condition = 0;
2186 break;
2187 }
2188 }
2189 } while (exit_condition == 0);
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002190
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002191 for (index_frontend = 0; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++)
Olivier Grenie4c70e072011-01-03 15:33:37 -03002192 dib8000_set_tune_state(state->fe[index_frontend], CT_DEMOD_START);
2193
2194 if ((state->fe[0]->dtv_property_cache.delivery_system != SYS_ISDBT) ||
2195 (state->fe[0]->dtv_property_cache.inversion == INVERSION_AUTO) ||
2196 (state->fe[0]->dtv_property_cache.transmission_mode == TRANSMISSION_MODE_AUTO) ||
2197 (state->fe[0]->dtv_property_cache.guard_interval == GUARD_INTERVAL_AUTO) ||
2198 (((state->fe[0]->dtv_property_cache.isdbt_layer_enabled & (1 << 0)) != 0) &&
2199 (state->fe[0]->dtv_property_cache.layer[0].segment_count != 0xff) &&
2200 (state->fe[0]->dtv_property_cache.layer[0].segment_count != 0) &&
2201 ((state->fe[0]->dtv_property_cache.layer[0].modulation == QAM_AUTO) ||
2202 (state->fe[0]->dtv_property_cache.layer[0].fec == FEC_AUTO))) ||
2203 (((state->fe[0]->dtv_property_cache.isdbt_layer_enabled & (1 << 1)) != 0) &&
2204 (state->fe[0]->dtv_property_cache.layer[1].segment_count != 0xff) &&
2205 (state->fe[0]->dtv_property_cache.layer[1].segment_count != 0) &&
2206 ((state->fe[0]->dtv_property_cache.layer[1].modulation == QAM_AUTO) ||
2207 (state->fe[0]->dtv_property_cache.layer[1].fec == FEC_AUTO))) ||
2208 (((state->fe[0]->dtv_property_cache.isdbt_layer_enabled & (1 << 2)) != 0) &&
2209 (state->fe[0]->dtv_property_cache.layer[2].segment_count != 0xff) &&
2210 (state->fe[0]->dtv_property_cache.layer[2].segment_count != 0) &&
2211 ((state->fe[0]->dtv_property_cache.layer[2].modulation == QAM_AUTO) ||
2212 (state->fe[0]->dtv_property_cache.layer[2].fec == FEC_AUTO))) ||
2213 (((state->fe[0]->dtv_property_cache.layer[0].segment_count == 0) ||
2214 ((state->fe[0]->dtv_property_cache.isdbt_layer_enabled & (1 << 0)) == 0)) &&
2215 ((state->fe[0]->dtv_property_cache.layer[1].segment_count == 0) ||
2216 ((state->fe[0]->dtv_property_cache.isdbt_layer_enabled & (2 << 0)) == 0)) &&
2217 ((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 -02002218 int i = 80000;
2219 u8 found = 0;
2220 u8 tune_failed = 0;
Olivier Grenie4c70e072011-01-03 15:33:37 -03002221
Mauro Carvalho Chehab2c2c4412011-01-16 13:02:52 -02002222 for (index_frontend = 0; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
2223 dib8000_set_bandwidth(state->fe[index_frontend], fe->dtv_property_cache.bandwidth_hz / 1000);
2224 dib8000_autosearch_start(state->fe[index_frontend]);
2225 }
Olivier Grenie4c70e072011-01-03 15:33:37 -03002226
Mauro Carvalho Chehab2c2c4412011-01-16 13:02:52 -02002227 do {
2228 msleep(20);
2229 nbr_pending = 0;
2230 exit_condition = 0; /* 0: tune pending; 1: tune failed; 2:tune success */
2231 for (index_frontend = 0; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
2232 if (((tune_failed >> index_frontend) & 0x1) == 0) {
2233 found = dib8000_autosearch_irq(state->fe[index_frontend]);
2234 switch (found) {
2235 case 0: /* tune pending */
2236 nbr_pending++;
2237 break;
2238 case 2:
2239 dprintk("autosearch succeed on the frontend%i", index_frontend);
2240 exit_condition = 2;
2241 index_frontend_success = index_frontend;
2242 break;
2243 default:
2244 dprintk("unhandled autosearch result");
2245 case 1:
2246 dprintk("autosearch failed for the frontend%i", index_frontend);
2247 break;
2248 }
2249 }
2250 }
Olivier Grenie4c70e072011-01-03 15:33:37 -03002251
Mauro Carvalho Chehab2c2c4412011-01-16 13:02:52 -02002252 /* if all tune are done and no success, exit: tune failed */
2253 if ((nbr_pending == 0) && (exit_condition == 0))
2254 exit_condition = 1;
2255 } while ((exit_condition == 0) && i--);
Olivier Grenie4c70e072011-01-03 15:33:37 -03002256
Mauro Carvalho Chehab2c2c4412011-01-16 13:02:52 -02002257 if (exit_condition == 1) { /* tune failed */
2258 dprintk("tune failed");
2259 return 0;
2260 }
Olivier Grenie4c70e072011-01-03 15:33:37 -03002261
Mauro Carvalho Chehab2c2c4412011-01-16 13:02:52 -02002262 dprintk("tune success on frontend%i", index_frontend_success);
Olivier Grenie4c70e072011-01-03 15:33:37 -03002263
Mauro Carvalho Chehab2c2c4412011-01-16 13:02:52 -02002264 dib8000_get_frontend(fe, fep);
2265 }
Olivier Grenie4c70e072011-01-03 15:33:37 -03002266
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002267 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 -03002268 ret = dib8000_tune(state->fe[index_frontend]);
Olivier Grenie4c70e072011-01-03 15:33:37 -03002269
2270 /* set output mode and diversity input */
2271 dib8000_set_output_mode(state->fe[0], state->cfg.output_mode);
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002272 for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
Olivier Grenie4c70e072011-01-03 15:33:37 -03002273 dib8000_set_output_mode(state->fe[index_frontend], OUTMODE_DIVERSITY);
2274 dib8000_set_diversity_in(state->fe[index_frontend-1], 1);
2275 }
2276
2277 /* turn off the diversity of the last chip */
2278 dib8000_set_diversity_in(state->fe[index_frontend-1], 0);
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002279
2280 return ret;
2281}
2282
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002283static u16 dib8000_read_lock(struct dvb_frontend *fe)
2284{
Olivier Grenie4c70e072011-01-03 15:33:37 -03002285 struct dib8000_state *state = fe->demodulator_priv;
2286
2287 return dib8000_read_word(state, 568);
2288}
2289
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002290static int dib8000_read_status(struct dvb_frontend *fe, fe_status_t * stat)
2291{
2292 struct dib8000_state *state = fe->demodulator_priv;
Olivier Grenie4c70e072011-01-03 15:33:37 -03002293 u16 lock_slave = 0, lock = dib8000_read_word(state, 568);
2294 u8 index_frontend;
2295
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002296 for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++)
Olivier Grenie4c70e072011-01-03 15:33:37 -03002297 lock_slave |= dib8000_read_lock(state->fe[index_frontend]);
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002298
2299 *stat = 0;
2300
Olivier Grenie4c70e072011-01-03 15:33:37 -03002301 if (((lock >> 13) & 1) || ((lock_slave >> 13) & 1))
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002302 *stat |= FE_HAS_SIGNAL;
2303
Olivier Grenie4c70e072011-01-03 15:33:37 -03002304 if (((lock >> 8) & 1) || ((lock_slave >> 8) & 1)) /* Equal */
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002305 *stat |= FE_HAS_CARRIER;
2306
Olivier Grenie4c70e072011-01-03 15:33:37 -03002307 if ((((lock >> 1) & 0xf) == 0xf) || (((lock_slave >> 1) & 0xf) == 0xf)) /* TMCC_SYNC */
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002308 *stat |= FE_HAS_SYNC;
2309
Olivier Grenie4c70e072011-01-03 15:33:37 -03002310 if ((((lock >> 12) & 1) || ((lock_slave >> 12) & 1)) && ((lock >> 5) & 7)) /* FEC MPEG */
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002311 *stat |= FE_HAS_LOCK;
2312
Olivier Grenie4c70e072011-01-03 15:33:37 -03002313 if (((lock >> 12) & 1) || ((lock_slave >> 12) & 1)) {
Olivier Grenie89dfc552009-11-30 06:38:49 -03002314 lock = dib8000_read_word(state, 554); /* Viterbi Layer A */
2315 if (lock & 0x01)
2316 *stat |= FE_HAS_VITERBI;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002317
Olivier Grenie89dfc552009-11-30 06:38:49 -03002318 lock = dib8000_read_word(state, 555); /* Viterbi Layer B */
2319 if (lock & 0x01)
2320 *stat |= FE_HAS_VITERBI;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002321
Olivier Grenie89dfc552009-11-30 06:38:49 -03002322 lock = dib8000_read_word(state, 556); /* Viterbi Layer C */
2323 if (lock & 0x01)
2324 *stat |= FE_HAS_VITERBI;
2325 }
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002326
2327 return 0;
2328}
2329
2330static int dib8000_read_ber(struct dvb_frontend *fe, u32 * ber)
2331{
2332 struct dib8000_state *state = fe->demodulator_priv;
2333 *ber = (dib8000_read_word(state, 560) << 16) | dib8000_read_word(state, 561); // 13 segments
2334 return 0;
2335}
2336
2337static int dib8000_read_unc_blocks(struct dvb_frontend *fe, u32 * unc)
2338{
2339 struct dib8000_state *state = fe->demodulator_priv;
2340 *unc = dib8000_read_word(state, 565); // packet error on 13 seg
2341 return 0;
2342}
2343
2344static int dib8000_read_signal_strength(struct dvb_frontend *fe, u16 * strength)
2345{
2346 struct dib8000_state *state = fe->demodulator_priv;
Olivier Grenie4c70e072011-01-03 15:33:37 -03002347 u8 index_frontend;
2348 u16 val;
2349
2350 *strength = 0;
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002351 for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
Olivier Grenie4c70e072011-01-03 15:33:37 -03002352 state->fe[index_frontend]->ops.read_signal_strength(state->fe[index_frontend], &val);
2353 if (val > 65535 - *strength)
2354 *strength = 65535;
2355 else
2356 *strength += val;
2357 }
2358
2359 val = 65535 - dib8000_read_word(state, 390);
2360 if (val > 65535 - *strength)
2361 *strength = 65535;
2362 else
2363 *strength += val;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002364 return 0;
2365}
2366
Olivier Grenie4c70e072011-01-03 15:33:37 -03002367static u32 dib8000_get_snr(struct dvb_frontend *fe)
2368{
2369 struct dib8000_state *state = fe->demodulator_priv;
2370 u32 n, s, exp;
2371 u16 val;
2372
2373 val = dib8000_read_word(state, 542);
2374 n = (val >> 6) & 0xff;
2375 exp = (val & 0x3f);
2376 if ((exp & 0x20) != 0)
2377 exp -= 0x40;
2378 n <<= exp+16;
2379
2380 val = dib8000_read_word(state, 543);
2381 s = (val >> 6) & 0xff;
2382 exp = (val & 0x3f);
2383 if ((exp & 0x20) != 0)
2384 exp -= 0x40;
2385 s <<= exp+16;
2386
2387 if (n > 0) {
2388 u32 t = (s/n) << 16;
2389 return t + ((s << 16) - n*t) / n;
2390 }
2391 return 0xffffffff;
2392}
2393
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002394static int dib8000_read_snr(struct dvb_frontend *fe, u16 * snr)
2395{
2396 struct dib8000_state *state = fe->demodulator_priv;
Olivier Grenie4c70e072011-01-03 15:33:37 -03002397 u8 index_frontend;
2398 u32 snr_master;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002399
Olivier Grenie4c70e072011-01-03 15:33:37 -03002400 snr_master = dib8000_get_snr(fe);
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002401 for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++)
Olivier Grenie4c70e072011-01-03 15:33:37 -03002402 snr_master += dib8000_get_snr(state->fe[index_frontend]);
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002403
Olivier Grenie4c70e072011-01-03 15:33:37 -03002404 if (snr_master != 0) {
2405 snr_master = 10*intlog10(snr_master>>16);
2406 *snr = snr_master / ((1 << 24) / 10);
2407 }
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002408 else
Olivier Grenie4c70e072011-01-03 15:33:37 -03002409 *snr = 0;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002410
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002411 return 0;
2412}
2413
Olivier Grenie4c70e072011-01-03 15:33:37 -03002414int dib8000_set_slave_frontend(struct dvb_frontend *fe, struct dvb_frontend *fe_slave)
2415{
2416 struct dib8000_state *state = fe->demodulator_priv;
2417 u8 index_frontend = 1;
2418
2419 while ((index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL))
2420 index_frontend++;
2421 if (index_frontend < MAX_NUMBER_OF_FRONTENDS) {
2422 dprintk("set slave fe %p to index %i", fe_slave, index_frontend);
2423 state->fe[index_frontend] = fe_slave;
2424 return 0;
2425 }
2426
2427 dprintk("too many slave frontend");
2428 return -ENOMEM;
2429}
2430EXPORT_SYMBOL(dib8000_set_slave_frontend);
2431
2432int dib8000_remove_slave_frontend(struct dvb_frontend *fe)
2433{
2434 struct dib8000_state *state = fe->demodulator_priv;
2435 u8 index_frontend = 1;
2436
2437 while ((index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL))
2438 index_frontend++;
2439 if (index_frontend != 1) {
2440 dprintk("remove slave fe %p (index %i)", state->fe[index_frontend-1], index_frontend-1);
2441 state->fe[index_frontend] = NULL;
2442 return 0;
2443 }
2444
2445 dprintk("no frontend to be removed");
2446 return -ENODEV;
2447}
2448EXPORT_SYMBOL(dib8000_remove_slave_frontend);
2449
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002450struct dvb_frontend *dib8000_get_slave_frontend(struct dvb_frontend *fe, int slave_index)
Olivier Grenie4c70e072011-01-03 15:33:37 -03002451{
2452 struct dib8000_state *state = fe->demodulator_priv;
2453
2454 if (slave_index >= MAX_NUMBER_OF_FRONTENDS)
2455 return NULL;
2456 return state->fe[slave_index];
2457}
2458EXPORT_SYMBOL(dib8000_get_slave_frontend);
2459
2460
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002461int dib8000_i2c_enumeration(struct i2c_adapter *host, int no_of_demods, u8 default_addr, u8 first_addr)
2462{
Olivier Grenie5a0deee2011-05-03 12:27:33 -03002463 int k = 0, ret = 0;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002464 u8 new_addr = 0;
2465 struct i2c_device client = {.adap = host };
2466
Olivier Grenie5a0deee2011-05-03 12:27:33 -03002467 client.i2c_write_buffer = kzalloc(4 * sizeof(u8), GFP_KERNEL);
2468 if (!client.i2c_write_buffer) {
2469 dprintk("%s: not enough memory", __func__);
2470 return -ENOMEM;
2471 }
2472 client.i2c_read_buffer = kzalloc(4 * sizeof(u8), GFP_KERNEL);
2473 if (!client.i2c_read_buffer) {
2474 dprintk("%s: not enough memory", __func__);
2475 ret = -ENOMEM;
Patrick Boettcher79fcce32011-08-03 12:08:21 -03002476 goto error_memory_read;
Olivier Grenie5a0deee2011-05-03 12:27:33 -03002477 }
Patrick Boettcher79fcce32011-08-03 12:08:21 -03002478 client.i2c_buffer_lock = kzalloc(sizeof(struct mutex), GFP_KERNEL);
2479 if (!client.i2c_buffer_lock) {
2480 dprintk("%s: not enough memory", __func__);
2481 ret = -ENOMEM;
2482 goto error_memory_lock;
2483 }
2484 mutex_init(client.i2c_buffer_lock);
Olivier Grenie5a0deee2011-05-03 12:27:33 -03002485
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002486 for (k = no_of_demods - 1; k >= 0; k--) {
2487 /* designated i2c address */
2488 new_addr = first_addr + (k << 1);
2489
2490 client.addr = new_addr;
2491 dib8000_i2c_write16(&client, 1287, 0x0003); /* sram lead in, rdy */
2492 if (dib8000_identify(&client) == 0) {
2493 dib8000_i2c_write16(&client, 1287, 0x0003); /* sram lead in, rdy */
2494 client.addr = default_addr;
2495 if (dib8000_identify(&client) == 0) {
2496 dprintk("#%d: not identified", k);
Olivier Grenie5a0deee2011-05-03 12:27:33 -03002497 ret = -EINVAL;
2498 goto error;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002499 }
2500 }
2501
2502 /* start diversity to pull_down div_str - just for i2c-enumeration */
2503 dib8000_i2c_write16(&client, 1286, (1 << 10) | (4 << 6));
2504
2505 /* set new i2c address and force divstart */
2506 dib8000_i2c_write16(&client, 1285, (new_addr << 2) | 0x2);
2507 client.addr = new_addr;
2508 dib8000_identify(&client);
2509
2510 dprintk("IC %d initialized (to i2c_address 0x%x)", k, new_addr);
2511 }
2512
2513 for (k = 0; k < no_of_demods; k++) {
2514 new_addr = first_addr | (k << 1);
2515 client.addr = new_addr;
2516
2517 // unforce divstr
2518 dib8000_i2c_write16(&client, 1285, new_addr << 2);
2519
2520 /* deactivate div - it was just for i2c-enumeration */
2521 dib8000_i2c_write16(&client, 1286, 0);
2522 }
2523
Olivier Grenie5a0deee2011-05-03 12:27:33 -03002524error:
Patrick Boettcher79fcce32011-08-03 12:08:21 -03002525 kfree(client.i2c_buffer_lock);
2526error_memory_lock:
Olivier Grenie5a0deee2011-05-03 12:27:33 -03002527 kfree(client.i2c_read_buffer);
Patrick Boettcher79fcce32011-08-03 12:08:21 -03002528error_memory_read:
Olivier Grenie5a0deee2011-05-03 12:27:33 -03002529 kfree(client.i2c_write_buffer);
2530
2531 return ret;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002532}
2533
2534EXPORT_SYMBOL(dib8000_i2c_enumeration);
2535static int dib8000_fe_get_tune_settings(struct dvb_frontend *fe, struct dvb_frontend_tune_settings *tune)
2536{
2537 tune->min_delay_ms = 1000;
2538 tune->step_size = 0;
2539 tune->max_drift = 0;
2540 return 0;
2541}
2542
2543static void dib8000_release(struct dvb_frontend *fe)
2544{
2545 struct dib8000_state *st = fe->demodulator_priv;
Olivier Grenie4c70e072011-01-03 15:33:37 -03002546 u8 index_frontend;
2547
Olivier Grenieb4d6046e2011-01-04 13:08:14 -03002548 for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (st->fe[index_frontend] != NULL); index_frontend++)
Olivier Grenie4c70e072011-01-03 15:33:37 -03002549 dvb_frontend_detach(st->fe[index_frontend]);
2550
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002551 dibx000_exit_i2c_master(&st->i2c_master);
Olivier Grenie4c70e072011-01-03 15:33:37 -03002552 kfree(st->fe[0]);
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002553 kfree(st);
2554}
2555
2556struct i2c_adapter *dib8000_get_i2c_master(struct dvb_frontend *fe, enum dibx000_i2c_interface intf, int gating)
2557{
2558 struct dib8000_state *st = fe->demodulator_priv;
2559 return dibx000_get_i2c_adapter(&st->i2c_master, intf, gating);
2560}
2561
2562EXPORT_SYMBOL(dib8000_get_i2c_master);
2563
Olivier Grenief8731f42009-09-18 04:08:43 -03002564int dib8000_pid_filter_ctrl(struct dvb_frontend *fe, u8 onoff)
2565{
2566 struct dib8000_state *st = fe->demodulator_priv;
Olivier Grenie4c70e072011-01-03 15:33:37 -03002567 u16 val = dib8000_read_word(st, 299) & 0xffef;
2568 val |= (onoff & 0x1) << 4;
Olivier Grenief8731f42009-09-18 04:08:43 -03002569
Olivier Grenie4c70e072011-01-03 15:33:37 -03002570 dprintk("pid filter enabled %d", onoff);
2571 return dib8000_write_word(st, 299, val);
Olivier Grenief8731f42009-09-18 04:08:43 -03002572}
2573EXPORT_SYMBOL(dib8000_pid_filter_ctrl);
2574
2575int dib8000_pid_filter(struct dvb_frontend *fe, u8 id, u16 pid, u8 onoff)
2576{
2577 struct dib8000_state *st = fe->demodulator_priv;
Olivier Grenie4c70e072011-01-03 15:33:37 -03002578 dprintk("Index %x, PID %d, OnOff %d", id, pid, onoff);
2579 return dib8000_write_word(st, 305 + id, onoff ? (1 << 13) | pid : 0);
Olivier Grenief8731f42009-09-18 04:08:43 -03002580}
2581EXPORT_SYMBOL(dib8000_pid_filter);
2582
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002583static const struct dvb_frontend_ops dib8000_ops = {
2584 .info = {
2585 .name = "DiBcom 8000 ISDB-T",
2586 .type = FE_OFDM,
2587 .frequency_min = 44250000,
2588 .frequency_max = 867250000,
2589 .frequency_stepsize = 62500,
2590 .caps = FE_CAN_INVERSION_AUTO |
2591 FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
2592 FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
2593 FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO |
2594 FE_CAN_TRANSMISSION_MODE_AUTO | FE_CAN_GUARD_INTERVAL_AUTO | FE_CAN_RECOVER | FE_CAN_HIERARCHY_AUTO,
2595 },
2596
2597 .release = dib8000_release,
2598
2599 .init = dib8000_wakeup,
2600 .sleep = dib8000_sleep,
2601
2602 .set_frontend = dib8000_set_frontend,
2603 .get_tune_settings = dib8000_fe_get_tune_settings,
2604 .get_frontend = dib8000_get_frontend,
2605
2606 .read_status = dib8000_read_status,
2607 .read_ber = dib8000_read_ber,
2608 .read_signal_strength = dib8000_read_signal_strength,
2609 .read_snr = dib8000_read_snr,
2610 .read_ucblocks = dib8000_read_unc_blocks,
2611};
2612
2613struct dvb_frontend *dib8000_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr, struct dib8000_config *cfg)
2614{
2615 struct dvb_frontend *fe;
2616 struct dib8000_state *state;
2617
2618 dprintk("dib8000_attach");
2619
2620 state = kzalloc(sizeof(struct dib8000_state), GFP_KERNEL);
2621 if (state == NULL)
2622 return NULL;
Olivier Grenie4c70e072011-01-03 15:33:37 -03002623 fe = kzalloc(sizeof(struct dvb_frontend), GFP_KERNEL);
2624 if (fe == NULL)
Dan Carpentered54c0e2011-01-19 11:27:58 -03002625 goto error;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002626
2627 memcpy(&state->cfg, cfg, sizeof(struct dib8000_config));
2628 state->i2c.adap = i2c_adap;
2629 state->i2c.addr = i2c_addr;
Olivier Grenie5a0deee2011-05-03 12:27:33 -03002630 state->i2c.i2c_write_buffer = state->i2c_write_buffer;
2631 state->i2c.i2c_read_buffer = state->i2c_read_buffer;
Patrick Boettcher79fcce32011-08-03 12:08:21 -03002632 mutex_init(&state->i2c_buffer_lock);
2633 state->i2c.i2c_buffer_lock = &state->i2c_buffer_lock;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002634 state->gpio_val = cfg->gpio_val;
2635 state->gpio_dir = cfg->gpio_dir;
2636
2637 /* Ensure the output mode remains at the previous default if it's
2638 * not specifically set by the caller.
2639 */
2640 if ((state->cfg.output_mode != OUTMODE_MPEG2_SERIAL) && (state->cfg.output_mode != OUTMODE_MPEG2_PAR_GATED_CLK))
2641 state->cfg.output_mode = OUTMODE_MPEG2_FIFO;
2642
Olivier Grenie4c70e072011-01-03 15:33:37 -03002643 state->fe[0] = fe;
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002644 fe->demodulator_priv = state;
Olivier Grenie4c70e072011-01-03 15:33:37 -03002645 memcpy(&state->fe[0]->ops, &dib8000_ops, sizeof(struct dvb_frontend_ops));
Patrick Boettcher77e2c0f2009-08-17 07:01:10 -03002646
2647 state->timf_default = cfg->pll->timf;
2648
2649 if (dib8000_identify(&state->i2c) == 0)
2650 goto error;
2651
2652 dibx000_init_i2c_master(&state->i2c_master, DIB8000, state->i2c.adap, state->i2c.addr);
2653
2654 dib8000_reset(fe);
2655
2656 dib8000_write_word(state, 285, (dib8000_read_word(state, 285) & ~0x60) | (3 << 5)); /* ber_rs_len = 3 */
2657
2658 return fe;
2659
2660 error:
2661 kfree(state);
2662 return NULL;
2663}
2664
2665EXPORT_SYMBOL(dib8000_attach);
2666
2667MODULE_AUTHOR("Olivier Grenie <Olivier.Grenie@dibcom.fr, " "Patrick Boettcher <pboettcher@dibcom.fr>");
2668MODULE_DESCRIPTION("Driver for the DiBcom 8000 ISDB-T demodulator");
2669MODULE_LICENSE("GPL");