diff options
author | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
commit | 1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (patch) | |
tree | 0bba044c4ce775e45a88a51686b5d9f90697ea9d /drivers/media/dvb/frontends |
Linux-2.6.12-rc2v2.6.12-rc2
Initial git repository build. I'm not bothering with the full history,
even though we have it. We can create a separate "historical" git
archive of that later if we want to, and in the meantime it's about
3.2GB when imported into git - space that would just make the early
git days unnecessarily complicated, when we don't have a lot of good
infrastructure for it.
Let it rip!
Diffstat (limited to 'drivers/media/dvb/frontends')
58 files changed, 18297 insertions, 0 deletions
diff --git a/drivers/media/dvb/frontends/Kconfig b/drivers/media/dvb/frontends/Kconfig new file mode 100644 index 000000000000..0bfd4df17d08 --- /dev/null +++ b/drivers/media/dvb/frontends/Kconfig | |||
@@ -0,0 +1,172 @@ | |||
1 | menu "Customise DVB Frontends" | ||
2 | depends on DVB_CORE | ||
3 | |||
4 | comment "DVB-S (satellite) frontends" | ||
5 | depends on DVB_CORE | ||
6 | |||
7 | config DVB_STV0299 | ||
8 | tristate "ST STV0299 based" | ||
9 | depends on DVB_CORE | ||
10 | help | ||
11 | A DVB-S tuner module. Say Y when you want to support this frontend. | ||
12 | |||
13 | config DVB_CX24110 | ||
14 | tristate "Conexant CX24110 based" | ||
15 | depends on DVB_CORE | ||
16 | help | ||
17 | A DVB-S tuner module. Say Y when you want to support this frontend. | ||
18 | |||
19 | config DVB_TDA8083 | ||
20 | tristate "Philips TDA8083 based" | ||
21 | depends on DVB_CORE | ||
22 | help | ||
23 | A DVB-S tuner module. Say Y when you want to support this frontend. | ||
24 | |||
25 | config DVB_TDA80XX | ||
26 | tristate "Philips TDA8044 or TDA8083 based" | ||
27 | depends on DVB_CORE | ||
28 | help | ||
29 | A DVB-S tuner module. Say Y when you want to support this frontend. | ||
30 | |||
31 | config DVB_MT312 | ||
32 | tristate "Zarlink MT312 based" | ||
33 | depends on DVB_CORE | ||
34 | help | ||
35 | A DVB-S tuner module. Say Y when you want to support this frontend. | ||
36 | |||
37 | config DVB_VES1X93 | ||
38 | tristate "VLSI VES1893 or VES1993 based" | ||
39 | depends on DVB_CORE | ||
40 | help | ||
41 | A DVB-S tuner module. Say Y when you want to support this frontend. | ||
42 | |||
43 | comment "DVB-T (terrestrial) frontends" | ||
44 | depends on DVB_CORE | ||
45 | |||
46 | config DVB_SP8870 | ||
47 | tristate "Spase sp8870 based" | ||
48 | depends on DVB_CORE | ||
49 | select FW_LOADER | ||
50 | help | ||
51 | A DVB-T tuner module. Say Y when you want to support this frontend. | ||
52 | |||
53 | This driver needs external firmware. Please use the command | ||
54 | "<kerneldir>/Documentation/dvb/get_dvb_firmware sp8870" to | ||
55 | download/extract it, and then copy it to /usr/lib/hotplug/firmware. | ||
56 | |||
57 | config DVB_SP887X | ||
58 | tristate "Spase sp887x based" | ||
59 | depends on DVB_CORE | ||
60 | select FW_LOADER | ||
61 | help | ||
62 | A DVB-T tuner module. Say Y when you want to support this frontend. | ||
63 | |||
64 | This driver needs external firmware. Please use the command | ||
65 | "<kerneldir>/Documentation/dvb/get_dvb_firmware sp887x" to | ||
66 | download/extract it, and then copy it to /usr/lib/hotplug/firmware. | ||
67 | |||
68 | config DVB_CX22700 | ||
69 | tristate "Conexant CX22700 based" | ||
70 | depends on DVB_CORE | ||
71 | help | ||
72 | A DVB-T tuner module. Say Y when you want to support this frontend. | ||
73 | |||
74 | config DVB_CX22702 | ||
75 | tristate "Conexant cx22702 demodulator (OFDM)" | ||
76 | depends on DVB_CORE | ||
77 | help | ||
78 | A DVB-T tuner module. Say Y when you want to support this frontend. | ||
79 | |||
80 | config DVB_L64781 | ||
81 | tristate "LSI L64781" | ||
82 | depends on DVB_CORE | ||
83 | help | ||
84 | A DVB-T tuner module. Say Y when you want to support this frontend. | ||
85 | |||
86 | config DVB_TDA1004X | ||
87 | tristate "Philips TDA10045H/TDA10046H based" | ||
88 | depends on DVB_CORE | ||
89 | select FW_LOADER | ||
90 | help | ||
91 | A DVB-T tuner module. Say Y when you want to support this frontend. | ||
92 | |||
93 | This driver needs external firmware. Please use the commands | ||
94 | "<kerneldir>/Documentation/dvb/get_dvb_firmware tda10045", | ||
95 | "<kerneldir>/Documentation/dvb/get_dvb_firmware tda10046" to | ||
96 | download/extract them, and then copy them to /usr/lib/hotplug/firmware. | ||
97 | |||
98 | config DVB_NXT6000 | ||
99 | tristate "NxtWave Communications NXT6000 based" | ||
100 | depends on DVB_CORE | ||
101 | help | ||
102 | A DVB-T tuner module. Say Y when you want to support this frontend. | ||
103 | |||
104 | config DVB_MT352 | ||
105 | tristate "Zarlink MT352 based" | ||
106 | depends on DVB_CORE | ||
107 | help | ||
108 | A DVB-T tuner module. Say Y when you want to support this frontend. | ||
109 | |||
110 | config DVB_DIB3000MB | ||
111 | tristate "DiBcom 3000M-B" | ||
112 | depends on DVB_CORE | ||
113 | help | ||
114 | A DVB-T tuner module. Designed for mobile usage. Say Y when you want | ||
115 | to support this frontend. | ||
116 | |||
117 | config DVB_DIB3000MC | ||
118 | tristate "DiBcom 3000P/M-C" | ||
119 | depends on DVB_CORE | ||
120 | help | ||
121 | A DVB-T tuner module. Designed for mobile usage. Say Y when you want | ||
122 | to support this frontend. | ||
123 | |||
124 | comment "DVB-C (cable) frontends" | ||
125 | depends on DVB_CORE | ||
126 | |||
127 | config DVB_ATMEL_AT76C651 | ||
128 | tristate "Atmel AT76C651 based" | ||
129 | depends on DVB_CORE | ||
130 | help | ||
131 | A DVB-C tuner module. Say Y when you want to support this frontend. | ||
132 | |||
133 | config DVB_VES1820 | ||
134 | tristate "VLSI VES1820 based" | ||
135 | depends on DVB_CORE | ||
136 | help | ||
137 | A DVB-C tuner module. Say Y when you want to support this frontend. | ||
138 | |||
139 | config DVB_TDA10021 | ||
140 | tristate "Philips TDA10021 based" | ||
141 | depends on DVB_CORE | ||
142 | help | ||
143 | A DVB-C tuner module. Say Y when you want to support this frontend. | ||
144 | |||
145 | config DVB_STV0297 | ||
146 | tristate "ST STV0297 based" | ||
147 | depends on DVB_CORE | ||
148 | help | ||
149 | A DVB-C tuner module. Say Y when you want to support this frontend. | ||
150 | |||
151 | comment "ATSC (North American/Korean Terresterial DTV) frontends" | ||
152 | depends on DVB_CORE | ||
153 | |||
154 | config DVB_NXT2002 | ||
155 | tristate "Nxt2002 based" | ||
156 | depends on DVB_CORE | ||
157 | select FW_LOADER | ||
158 | help | ||
159 | An ATSC 8VSB tuner module. Say Y when you want to support this frontend. | ||
160 | |||
161 | config DVB_OR51132 | ||
162 | tristate "OR51132 based (pcHDTV)" | ||
163 | depends on DVB_CORE | ||
164 | |||
165 | config DVB_OR51211 | ||
166 | tristate "or51211 based (pcHDTV HD2000 card)" | ||
167 | depends on DVB_CORE | ||
168 | select FW_LOADER | ||
169 | help | ||
170 | An ATSC 8VSB tuner module. Say Y when you want to support this frontend. | ||
171 | |||
172 | endmenu | ||
diff --git a/drivers/media/dvb/frontends/Makefile b/drivers/media/dvb/frontends/Makefile new file mode 100644 index 000000000000..7f8784870eab --- /dev/null +++ b/drivers/media/dvb/frontends/Makefile | |||
@@ -0,0 +1,30 @@ | |||
1 | # | ||
2 | # Makefile for the kernel DVB frontend device drivers. | ||
3 | # | ||
4 | |||
5 | EXTRA_CFLAGS = -Idrivers/media/dvb/dvb-core/ | ||
6 | |||
7 | obj-$(CONFIG_DVB_CORE) += dvb-pll.o | ||
8 | obj-$(CONFIG_DVB_STV0299) += stv0299.o | ||
9 | obj-$(CONFIG_DVB_SP8870) += sp8870.o | ||
10 | obj-$(CONFIG_DVB_CX22700) += cx22700.o | ||
11 | obj-$(CONFIG_DVB_ATMEL_AT76C651) += at76c651.o | ||
12 | obj-$(CONFIG_DVB_CX24110) += cx24110.o | ||
13 | obj-$(CONFIG_DVB_TDA8083) += tda8083.o | ||
14 | obj-$(CONFIG_DVB_L64781) += l64781.o | ||
15 | obj-$(CONFIG_DVB_DIB3000MB) += dib3000mb.o dib3000-common.o | ||
16 | obj-$(CONFIG_DVB_DIB3000MC) += dib3000mc.o dib3000-common.o | ||
17 | obj-$(CONFIG_DVB_MT312) += mt312.o | ||
18 | obj-$(CONFIG_DVB_VES1820) += ves1820.o | ||
19 | obj-$(CONFIG_DVB_VES1X93) += ves1x93.o | ||
20 | obj-$(CONFIG_DVB_TDA1004X) += tda1004x.o | ||
21 | obj-$(CONFIG_DVB_SP887X) += sp887x.o | ||
22 | obj-$(CONFIG_DVB_NXT6000) += nxt6000.o | ||
23 | obj-$(CONFIG_DVB_MT352) += mt352.o | ||
24 | obj-$(CONFIG_DVB_CX22702) += cx22702.o | ||
25 | obj-$(CONFIG_DVB_TDA80XX) += tda80xx.o | ||
26 | obj-$(CONFIG_DVB_TDA10021) += tda10021.o | ||
27 | obj-$(CONFIG_DVB_STV0297) += stv0297.o | ||
28 | obj-$(CONFIG_DVB_NXT2002) += nxt2002.o | ||
29 | obj-$(CONFIG_DVB_OR51211) += or51211.o | ||
30 | obj-$(CONFIG_DVB_OR51132) += or51132.o | ||
diff --git a/drivers/media/dvb/frontends/at76c651.c b/drivers/media/dvb/frontends/at76c651.c new file mode 100644 index 000000000000..ce2eaa1640e8 --- /dev/null +++ b/drivers/media/dvb/frontends/at76c651.c | |||
@@ -0,0 +1,450 @@ | |||
1 | /* | ||
2 | * at76c651.c | ||
3 | * | ||
4 | * Atmel DVB-C Frontend Driver (at76c651/tua6010xs) | ||
5 | * | ||
6 | * Copyright (C) 2001 fnbrd <fnbrd@gmx.de> | ||
7 | * & 2002-2004 Andreas Oberritter <obi@linuxtv.org> | ||
8 | * & 2003 Wolfram Joost <dbox2@frokaschwei.de> | ||
9 | * | ||
10 | * This program is free software; you can redistribute it and/or modify | ||
11 | * it under the terms of the GNU General Public License as published by | ||
12 | * the Free Software Foundation; either version 2 of the License, or | ||
13 | * (at your option) any later version. | ||
14 | * | ||
15 | * This program is distributed in the hope that it will be useful, | ||
16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
18 | * GNU General Public License for more details. | ||
19 | * | ||
20 | * You should have received a copy of the GNU General Public License | ||
21 | * along with this program; if not, write to the Free Software | ||
22 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
23 | * | ||
24 | * AT76C651 | ||
25 | * http://www.nalanda.nitc.ac.in/industry/datasheets/atmel/acrobat/doc1293.pdf | ||
26 | * http://www.atmel.com/atmel/acrobat/doc1320.pdf | ||
27 | */ | ||
28 | |||
29 | #include <linux/init.h> | ||
30 | #include <linux/module.h> | ||
31 | #include <linux/moduleparam.h> | ||
32 | #include <linux/kernel.h> | ||
33 | #include <linux/string.h> | ||
34 | #include <linux/slab.h> | ||
35 | #include <linux/bitops.h> | ||
36 | #include "dvb_frontend.h" | ||
37 | #include "at76c651.h" | ||
38 | |||
39 | |||
40 | struct at76c651_state { | ||
41 | |||
42 | struct i2c_adapter* i2c; | ||
43 | |||
44 | struct dvb_frontend_ops ops; | ||
45 | |||
46 | const struct at76c651_config* config; | ||
47 | |||
48 | struct dvb_frontend frontend; | ||
49 | |||
50 | /* revision of the chip */ | ||
51 | u8 revision; | ||
52 | |||
53 | /* last QAM value set */ | ||
54 | u8 qam; | ||
55 | }; | ||
56 | |||
57 | static int debug; | ||
58 | #define dprintk(args...) \ | ||
59 | do { \ | ||
60 | if (debug) printk(KERN_DEBUG "at76c651: " args); \ | ||
61 | } while (0) | ||
62 | |||
63 | |||
64 | #if ! defined(__powerpc__) | ||
65 | static __inline__ int __ilog2(unsigned long x) | ||
66 | { | ||
67 | int i; | ||
68 | |||
69 | if (x == 0) | ||
70 | return -1; | ||
71 | |||
72 | for (i = 0; x != 0; i++) | ||
73 | x >>= 1; | ||
74 | |||
75 | return i - 1; | ||
76 | } | ||
77 | #endif | ||
78 | |||
79 | static int at76c651_writereg(struct at76c651_state* state, u8 reg, u8 data) | ||
80 | { | ||
81 | int ret; | ||
82 | u8 buf[] = { reg, data }; | ||
83 | struct i2c_msg msg = | ||
84 | { .addr = state->config->demod_address, .flags = 0, .buf = buf, .len = 2 }; | ||
85 | |||
86 | ret = i2c_transfer(state->i2c, &msg, 1); | ||
87 | |||
88 | if (ret != 1) | ||
89 | dprintk("%s: writereg error " | ||
90 | "(reg == 0x%02x, val == 0x%02x, ret == %i)\n", | ||
91 | __FUNCTION__, reg, data, ret); | ||
92 | |||
93 | msleep(10); | ||
94 | |||
95 | return (ret != 1) ? -EREMOTEIO : 0; | ||
96 | } | ||
97 | |||
98 | static u8 at76c651_readreg(struct at76c651_state* state, u8 reg) | ||
99 | { | ||
100 | int ret; | ||
101 | u8 val; | ||
102 | struct i2c_msg msg[] = { | ||
103 | { .addr = state->config->demod_address, .flags = 0, .buf = ®, .len = 1 }, | ||
104 | { .addr = state->config->demod_address, .flags = I2C_M_RD, .buf = &val, .len = 1 } | ||
105 | }; | ||
106 | |||
107 | ret = i2c_transfer(state->i2c, msg, 2); | ||
108 | |||
109 | if (ret != 2) | ||
110 | dprintk("%s: readreg error (ret == %i)\n", __FUNCTION__, ret); | ||
111 | |||
112 | return val; | ||
113 | } | ||
114 | |||
115 | static int at76c651_reset(struct at76c651_state* state) | ||
116 | { | ||
117 | return at76c651_writereg(state, 0x07, 0x01); | ||
118 | } | ||
119 | |||
120 | static void at76c651_disable_interrupts(struct at76c651_state* state) | ||
121 | { | ||
122 | at76c651_writereg(state, 0x0b, 0x00); | ||
123 | } | ||
124 | |||
125 | static int at76c651_set_auto_config(struct at76c651_state *state) | ||
126 | { | ||
127 | /* | ||
128 | * Autoconfig | ||
129 | */ | ||
130 | |||
131 | at76c651_writereg(state, 0x06, 0x01); | ||
132 | |||
133 | /* | ||
134 | * Performance optimizations, should be done after autoconfig | ||
135 | */ | ||
136 | |||
137 | at76c651_writereg(state, 0x10, 0x06); | ||
138 | at76c651_writereg(state, 0x11, ((state->qam == 5) || (state->qam == 7)) ? 0x12 : 0x10); | ||
139 | at76c651_writereg(state, 0x15, 0x28); | ||
140 | at76c651_writereg(state, 0x20, 0x09); | ||
141 | at76c651_writereg(state, 0x24, ((state->qam == 5) || (state->qam == 7)) ? 0xC0 : 0x90); | ||
142 | at76c651_writereg(state, 0x30, 0x90); | ||
143 | if (state->qam == 5) | ||
144 | at76c651_writereg(state, 0x35, 0x2A); | ||
145 | |||
146 | /* | ||
147 | * Initialize A/D-converter | ||
148 | */ | ||
149 | |||
150 | if (state->revision == 0x11) { | ||
151 | at76c651_writereg(state, 0x2E, 0x38); | ||
152 | at76c651_writereg(state, 0x2F, 0x13); | ||
153 | } | ||
154 | |||
155 | at76c651_disable_interrupts(state); | ||
156 | |||
157 | /* | ||
158 | * Restart operation | ||
159 | */ | ||
160 | |||
161 | at76c651_reset(state); | ||
162 | |||
163 | return 0; | ||
164 | } | ||
165 | |||
166 | static void at76c651_set_bbfreq(struct at76c651_state* state) | ||
167 | { | ||
168 | at76c651_writereg(state, 0x04, 0x3f); | ||
169 | at76c651_writereg(state, 0x05, 0xee); | ||
170 | } | ||
171 | |||
172 | static int at76c651_set_symbol_rate(struct at76c651_state* state, u32 symbol_rate) | ||
173 | { | ||
174 | u8 exponent; | ||
175 | u32 mantissa; | ||
176 | |||
177 | if (symbol_rate > 9360000) | ||
178 | return -EINVAL; | ||
179 | |||
180 | /* | ||
181 | * FREF = 57800 kHz | ||
182 | * exponent = 10 + floor (log2(symbol_rate / FREF)) | ||
183 | * mantissa = (symbol_rate / FREF) * (1 << (30 - exponent)) | ||
184 | */ | ||
185 | |||
186 | exponent = __ilog2((symbol_rate << 4) / 903125); | ||
187 | mantissa = ((symbol_rate / 3125) * (1 << (24 - exponent))) / 289; | ||
188 | |||
189 | at76c651_writereg(state, 0x00, mantissa >> 13); | ||
190 | at76c651_writereg(state, 0x01, mantissa >> 5); | ||
191 | at76c651_writereg(state, 0x02, (mantissa << 3) | exponent); | ||
192 | |||
193 | return 0; | ||
194 | } | ||
195 | |||
196 | static int at76c651_set_qam(struct at76c651_state *state, fe_modulation_t qam) | ||
197 | { | ||
198 | switch (qam) { | ||
199 | case QPSK: | ||
200 | state->qam = 0x02; | ||
201 | break; | ||
202 | case QAM_16: | ||
203 | state->qam = 0x04; | ||
204 | break; | ||
205 | case QAM_32: | ||
206 | state->qam = 0x05; | ||
207 | break; | ||
208 | case QAM_64: | ||
209 | state->qam = 0x06; | ||
210 | break; | ||
211 | case QAM_128: | ||
212 | state->qam = 0x07; | ||
213 | break; | ||
214 | case QAM_256: | ||
215 | state->qam = 0x08; | ||
216 | break; | ||
217 | #if 0 | ||
218 | case QAM_512: | ||
219 | state->qam = 0x09; | ||
220 | break; | ||
221 | case QAM_1024: | ||
222 | state->qam = 0x0A; | ||
223 | break; | ||
224 | #endif | ||
225 | default: | ||
226 | return -EINVAL; | ||
227 | |||
228 | } | ||
229 | |||
230 | return at76c651_writereg(state, 0x03, state->qam); | ||
231 | } | ||
232 | |||
233 | static int at76c651_set_inversion(struct at76c651_state* state, fe_spectral_inversion_t inversion) | ||
234 | { | ||
235 | u8 feciqinv = at76c651_readreg(state, 0x60); | ||
236 | |||
237 | switch (inversion) { | ||
238 | case INVERSION_OFF: | ||
239 | feciqinv |= 0x02; | ||
240 | feciqinv &= 0xFE; | ||
241 | break; | ||
242 | |||
243 | case INVERSION_ON: | ||
244 | feciqinv |= 0x03; | ||
245 | break; | ||
246 | |||
247 | case INVERSION_AUTO: | ||
248 | feciqinv &= 0xFC; | ||
249 | break; | ||
250 | |||
251 | default: | ||
252 | return -EINVAL; | ||
253 | } | ||
254 | |||
255 | return at76c651_writereg(state, 0x60, feciqinv); | ||
256 | } | ||
257 | |||
258 | static int at76c651_set_parameters(struct dvb_frontend* fe, | ||
259 | struct dvb_frontend_parameters *p) | ||
260 | { | ||
261 | int ret; | ||
262 | struct at76c651_state* state = (struct at76c651_state*) fe->demodulator_priv; | ||
263 | |||
264 | at76c651_writereg(state, 0x0c, 0xc3); | ||
265 | state->config->pll_set(fe, p); | ||
266 | at76c651_writereg(state, 0x0c, 0xc2); | ||
267 | |||
268 | if ((ret = at76c651_set_symbol_rate(state, p->u.qam.symbol_rate))) | ||
269 | return ret; | ||
270 | |||
271 | if ((ret = at76c651_set_inversion(state, p->inversion))) | ||
272 | return ret; | ||
273 | |||
274 | return at76c651_set_auto_config(state); | ||
275 | } | ||
276 | |||
277 | static int at76c651_set_defaults(struct dvb_frontend* fe) | ||
278 | { | ||
279 | struct at76c651_state* state = (struct at76c651_state*) fe->demodulator_priv; | ||
280 | |||
281 | at76c651_set_symbol_rate(state, 6900000); | ||
282 | at76c651_set_qam(state, QAM_64); | ||
283 | at76c651_set_bbfreq(state); | ||
284 | at76c651_set_auto_config(state); | ||
285 | |||
286 | if (state->config->pll_init) { | ||
287 | at76c651_writereg(state, 0x0c, 0xc3); | ||
288 | state->config->pll_init(fe); | ||
289 | at76c651_writereg(state, 0x0c, 0xc2); | ||
290 | } | ||
291 | |||
292 | return 0; | ||
293 | } | ||
294 | |||
295 | static int at76c651_read_status(struct dvb_frontend* fe, fe_status_t* status) | ||
296 | { | ||
297 | struct at76c651_state* state = (struct at76c651_state*) fe->demodulator_priv; | ||
298 | u8 sync; | ||
299 | |||
300 | /* | ||
301 | * Bits: FEC, CAR, EQU, TIM, AGC2, AGC1, ADC, PLL (PLL=0) | ||
302 | */ | ||
303 | sync = at76c651_readreg(state, 0x80); | ||
304 | *status = 0; | ||
305 | |||
306 | if (sync & (0x04 | 0x10)) /* AGC1 || TIM */ | ||
307 | *status |= FE_HAS_SIGNAL; | ||
308 | if (sync & 0x10) /* TIM */ | ||
309 | *status |= FE_HAS_CARRIER; | ||
310 | if (sync & 0x80) /* FEC */ | ||
311 | *status |= FE_HAS_VITERBI; | ||
312 | if (sync & 0x40) /* CAR */ | ||
313 | *status |= FE_HAS_SYNC; | ||
314 | if ((sync & 0xF0) == 0xF0) /* TIM && EQU && CAR && FEC */ | ||
315 | *status |= FE_HAS_LOCK; | ||
316 | |||
317 | return 0; | ||
318 | } | ||
319 | |||
320 | static int at76c651_read_ber(struct dvb_frontend* fe, u32* ber) | ||
321 | { | ||
322 | struct at76c651_state* state = (struct at76c651_state*) fe->demodulator_priv; | ||
323 | |||
324 | *ber = (at76c651_readreg(state, 0x81) & 0x0F) << 16; | ||
325 | *ber |= at76c651_readreg(state, 0x82) << 8; | ||
326 | *ber |= at76c651_readreg(state, 0x83); | ||
327 | *ber *= 10; | ||
328 | |||
329 | return 0; | ||
330 | } | ||
331 | |||
332 | static int at76c651_read_signal_strength(struct dvb_frontend* fe, u16* strength) | ||
333 | { | ||
334 | struct at76c651_state* state = (struct at76c651_state*) fe->demodulator_priv; | ||
335 | |||
336 | u8 gain = ~at76c651_readreg(state, 0x91); | ||
337 | *strength = (gain << 8) | gain; | ||
338 | |||
339 | return 0; | ||
340 | } | ||
341 | |||
342 | static int at76c651_read_snr(struct dvb_frontend* fe, u16* snr) | ||
343 | { | ||
344 | struct at76c651_state* state = (struct at76c651_state*) fe->demodulator_priv; | ||
345 | |||
346 | *snr = 0xFFFF - | ||
347 | ((at76c651_readreg(state, 0x8F) << 8) | | ||
348 | at76c651_readreg(state, 0x90)); | ||
349 | |||
350 | return 0; | ||
351 | } | ||
352 | |||
353 | static int at76c651_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks) | ||
354 | { | ||
355 | struct at76c651_state* state = (struct at76c651_state*) fe->demodulator_priv; | ||
356 | |||
357 | *ucblocks = at76c651_readreg(state, 0x82); | ||
358 | |||
359 | return 0; | ||
360 | } | ||
361 | |||
362 | static int at76c651_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings *fesettings) | ||
363 | { | ||
364 | fesettings->min_delay_ms = 50; | ||
365 | fesettings->step_size = 0; | ||
366 | fesettings->max_drift = 0; | ||
367 | return 0; | ||
368 | } | ||
369 | |||
370 | static void at76c651_release(struct dvb_frontend* fe) | ||
371 | { | ||
372 | struct at76c651_state* state = (struct at76c651_state*) fe->demodulator_priv; | ||
373 | kfree(state); | ||
374 | } | ||
375 | |||
376 | static struct dvb_frontend_ops at76c651_ops; | ||
377 | |||
378 | struct dvb_frontend* at76c651_attach(const struct at76c651_config* config, | ||
379 | struct i2c_adapter* i2c) | ||
380 | { | ||
381 | struct at76c651_state* state = NULL; | ||
382 | |||
383 | /* allocate memory for the internal state */ | ||
384 | state = (struct at76c651_state*) kmalloc(sizeof(struct at76c651_state), GFP_KERNEL); | ||
385 | if (state == NULL) goto error; | ||
386 | |||
387 | /* setup the state */ | ||
388 | state->config = config; | ||
389 | state->qam = 0; | ||
390 | |||
391 | /* check if the demod is there */ | ||
392 | if (at76c651_readreg(state, 0x0e) != 0x65) goto error; | ||
393 | |||
394 | /* finalise state setup */ | ||
395 | state->i2c = i2c; | ||
396 | state->revision = at76c651_readreg(state, 0x0f) & 0xfe; | ||
397 | memcpy(&state->ops, &at76c651_ops, sizeof(struct dvb_frontend_ops)); | ||
398 | |||
399 | /* create dvb_frontend */ | ||
400 | state->frontend.ops = &state->ops; | ||
401 | state->frontend.demodulator_priv = state; | ||
402 | return &state->frontend; | ||
403 | |||
404 | error: | ||
405 | kfree(state); | ||
406 | return NULL; | ||
407 | } | ||
408 | |||
409 | static struct dvb_frontend_ops at76c651_ops = { | ||
410 | |||
411 | .info = { | ||
412 | .name = "Atmel AT76C651B DVB-C", | ||
413 | .type = FE_QAM, | ||
414 | .frequency_min = 48250000, | ||
415 | .frequency_max = 863250000, | ||
416 | .frequency_stepsize = 62500, | ||
417 | /*.frequency_tolerance = */ /* FIXME: 12% of SR */ | ||
418 | .symbol_rate_min = 0, /* FIXME */ | ||
419 | .symbol_rate_max = 9360000, /* FIXME */ | ||
420 | .symbol_rate_tolerance = 4000, | ||
421 | .caps = FE_CAN_INVERSION_AUTO | | ||
422 | FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | | ||
423 | FE_CAN_FEC_4_5 | FE_CAN_FEC_5_6 | FE_CAN_FEC_6_7 | | ||
424 | FE_CAN_FEC_7_8 | FE_CAN_FEC_8_9 | FE_CAN_FEC_AUTO | | ||
425 | FE_CAN_QAM_16 | FE_CAN_QAM_32 | FE_CAN_QAM_64 | FE_CAN_QAM_128 | | ||
426 | FE_CAN_MUTE_TS | FE_CAN_QAM_256 | FE_CAN_RECOVER | ||
427 | }, | ||
428 | |||
429 | .release = at76c651_release, | ||
430 | |||
431 | .init = at76c651_set_defaults, | ||
432 | |||
433 | .set_frontend = at76c651_set_parameters, | ||
434 | .get_tune_settings = at76c651_get_tune_settings, | ||
435 | |||
436 | .read_status = at76c651_read_status, | ||
437 | .read_ber = at76c651_read_ber, | ||
438 | .read_signal_strength = at76c651_read_signal_strength, | ||
439 | .read_snr = at76c651_read_snr, | ||
440 | .read_ucblocks = at76c651_read_ucblocks, | ||
441 | }; | ||
442 | |||
443 | module_param(debug, int, 0644); | ||
444 | MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off)."); | ||
445 | |||
446 | MODULE_DESCRIPTION("Atmel AT76C651 DVB-C Demodulator Driver"); | ||
447 | MODULE_AUTHOR("Andreas Oberritter <obi@linuxtv.org>"); | ||
448 | MODULE_LICENSE("GPL"); | ||
449 | |||
450 | EXPORT_SYMBOL(at76c651_attach); | ||
diff --git a/drivers/media/dvb/frontends/at76c651.h b/drivers/media/dvb/frontends/at76c651.h new file mode 100644 index 000000000000..34054df93608 --- /dev/null +++ b/drivers/media/dvb/frontends/at76c651.h | |||
@@ -0,0 +1,47 @@ | |||
1 | /* | ||
2 | * at76c651.c | ||
3 | * | ||
4 | * Atmel DVB-C Frontend Driver (at76c651) | ||
5 | * | ||
6 | * Copyright (C) 2001 fnbrd <fnbrd@gmx.de> | ||
7 | * & 2002-2004 Andreas Oberritter <obi@linuxtv.org> | ||
8 | * & 2003 Wolfram Joost <dbox2@frokaschwei.de> | ||
9 | * | ||
10 | * This program is free software; you can redistribute it and/or modify | ||
11 | * it under the terms of the GNU General Public License as published by | ||
12 | * the Free Software Foundation; either version 2 of the License, or | ||
13 | * (at your option) any later version. | ||
14 | * | ||
15 | * This program is distributed in the hope that it will be useful, | ||
16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
18 | * GNU General Public License for more details. | ||
19 | * | ||
20 | * You should have received a copy of the GNU General Public License | ||
21 | * along with this program; if not, write to the Free Software | ||
22 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
23 | * | ||
24 | * AT76C651 | ||
25 | * http://www.nalanda.nitc.ac.in/industry/datasheets/atmel/acrobat/doc1293.pdf | ||
26 | * http://www.atmel.com/atmel/acrobat/doc1320.pdf | ||
27 | */ | ||
28 | |||
29 | #ifndef AT76C651_H | ||
30 | #define AT76C651_H | ||
31 | |||
32 | #include <linux/dvb/frontend.h> | ||
33 | |||
34 | struct at76c651_config | ||
35 | { | ||
36 | /* the demodulator's i2c address */ | ||
37 | u8 demod_address; | ||
38 | |||
39 | /* PLL maintenance */ | ||
40 | int (*pll_init)(struct dvb_frontend* fe); | ||
41 | int (*pll_set)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params); | ||
42 | }; | ||
43 | |||
44 | extern struct dvb_frontend* at76c651_attach(const struct at76c651_config* config, | ||
45 | struct i2c_adapter* i2c); | ||
46 | |||
47 | #endif // AT76C651_H | ||
diff --git a/drivers/media/dvb/frontends/cx22700.c b/drivers/media/dvb/frontends/cx22700.c new file mode 100644 index 000000000000..a212279042b8 --- /dev/null +++ b/drivers/media/dvb/frontends/cx22700.c | |||
@@ -0,0 +1,435 @@ | |||
1 | /* | ||
2 | Conexant cx22700 DVB OFDM demodulator driver | ||
3 | |||
4 | Copyright (C) 2001-2002 Convergence Integrated Media GmbH | ||
5 | Holger Waechtler <holger@convergence.de> | ||
6 | |||
7 | This program is free software; you can redistribute it and/or modify | ||
8 | it under the terms of the GNU General Public License as published by | ||
9 | the Free Software Foundation; either version 2 of the License, or | ||
10 | (at your option) any later version. | ||
11 | |||
12 | This program is distributed in the hope that it will be useful, | ||
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | GNU General Public License for more details. | ||
16 | |||
17 | You should have received a copy of the GNU General Public License | ||
18 | along with this program; if not, write to the Free Software | ||
19 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
20 | |||
21 | */ | ||
22 | |||
23 | #include <linux/kernel.h> | ||
24 | #include <linux/init.h> | ||
25 | #include <linux/module.h> | ||
26 | #include <linux/moduleparam.h> | ||
27 | #include <linux/string.h> | ||
28 | #include <linux/slab.h> | ||
29 | #include "dvb_frontend.h" | ||
30 | #include "cx22700.h" | ||
31 | |||
32 | |||
33 | struct cx22700_state { | ||
34 | |||
35 | struct i2c_adapter* i2c; | ||
36 | |||
37 | struct dvb_frontend_ops ops; | ||
38 | |||
39 | const struct cx22700_config* config; | ||
40 | |||
41 | struct dvb_frontend frontend; | ||
42 | }; | ||
43 | |||
44 | |||
45 | static int debug; | ||
46 | #define dprintk(args...) \ | ||
47 | do { \ | ||
48 | if (debug) printk(KERN_DEBUG "cx22700: " args); \ | ||
49 | } while (0) | ||
50 | |||
51 | static u8 init_tab [] = { | ||
52 | 0x04, 0x10, | ||
53 | 0x05, 0x09, | ||
54 | 0x06, 0x00, | ||
55 | 0x08, 0x04, | ||
56 | 0x09, 0x00, | ||
57 | 0x0a, 0x01, | ||
58 | 0x15, 0x40, | ||
59 | 0x16, 0x10, | ||
60 | 0x17, 0x87, | ||
61 | 0x18, 0x17, | ||
62 | 0x1a, 0x10, | ||
63 | 0x25, 0x04, | ||
64 | 0x2e, 0x00, | ||
65 | 0x39, 0x00, | ||
66 | 0x3a, 0x04, | ||
67 | 0x45, 0x08, | ||
68 | 0x46, 0x02, | ||
69 | 0x47, 0x05, | ||
70 | }; | ||
71 | |||
72 | |||
73 | static int cx22700_writereg (struct cx22700_state* state, u8 reg, u8 data) | ||
74 | { | ||
75 | int ret; | ||
76 | u8 buf [] = { reg, data }; | ||
77 | struct i2c_msg msg = { .addr = state->config->demod_address, .flags = 0, .buf = buf, .len = 2 }; | ||
78 | |||
79 | dprintk ("%s\n", __FUNCTION__); | ||
80 | |||
81 | ret = i2c_transfer (state->i2c, &msg, 1); | ||
82 | |||
83 | if (ret != 1) | ||
84 | printk("%s: writereg error (reg == 0x%02x, val == 0x%02x, ret == %i)\n", | ||
85 | __FUNCTION__, reg, data, ret); | ||
86 | |||
87 | return (ret != 1) ? -1 : 0; | ||
88 | } | ||
89 | |||
90 | static int cx22700_readreg (struct cx22700_state* state, u8 reg) | ||
91 | { | ||
92 | int ret; | ||
93 | u8 b0 [] = { reg }; | ||
94 | u8 b1 [] = { 0 }; | ||
95 | struct i2c_msg msg [] = { { .addr = state->config->demod_address, .flags = 0, .buf = b0, .len = 1 }, | ||
96 | { .addr = state->config->demod_address, .flags = I2C_M_RD, .buf = b1, .len = 1 } }; | ||
97 | |||
98 | dprintk ("%s\n", __FUNCTION__); | ||
99 | |||
100 | ret = i2c_transfer (state->i2c, msg, 2); | ||
101 | |||
102 | if (ret != 2) return -EIO; | ||
103 | |||
104 | return b1[0]; | ||
105 | } | ||
106 | |||
107 | static int cx22700_set_inversion (struct cx22700_state* state, int inversion) | ||
108 | { | ||
109 | u8 val; | ||
110 | |||
111 | dprintk ("%s\n", __FUNCTION__); | ||
112 | |||
113 | switch (inversion) { | ||
114 | case INVERSION_AUTO: | ||
115 | return -EOPNOTSUPP; | ||
116 | case INVERSION_ON: | ||
117 | val = cx22700_readreg (state, 0x09); | ||
118 | return cx22700_writereg (state, 0x09, val | 0x01); | ||
119 | case INVERSION_OFF: | ||
120 | val = cx22700_readreg (state, 0x09); | ||
121 | return cx22700_writereg (state, 0x09, val & 0xfe); | ||
122 | default: | ||
123 | return -EINVAL; | ||
124 | } | ||
125 | } | ||
126 | |||
127 | static int cx22700_set_tps (struct cx22700_state *state, struct dvb_ofdm_parameters *p) | ||
128 | { | ||
129 | static const u8 qam_tab [4] = { 0, 1, 0, 2 }; | ||
130 | static const u8 fec_tab [6] = { 0, 1, 2, 0, 3, 4 }; | ||
131 | u8 val; | ||
132 | |||
133 | dprintk ("%s\n", __FUNCTION__); | ||
134 | |||
135 | if (p->code_rate_HP < FEC_1_2 || p->code_rate_HP > FEC_7_8) | ||
136 | return -EINVAL; | ||
137 | |||
138 | if (p->code_rate_LP < FEC_1_2 || p->code_rate_LP > FEC_7_8) | ||
139 | |||
140 | if (p->code_rate_HP == FEC_4_5 || p->code_rate_LP == FEC_4_5) | ||
141 | return -EINVAL; | ||
142 | |||
143 | if (p->guard_interval < GUARD_INTERVAL_1_32 || | ||
144 | p->guard_interval > GUARD_INTERVAL_1_4) | ||
145 | return -EINVAL; | ||
146 | |||
147 | if (p->transmission_mode != TRANSMISSION_MODE_2K && | ||
148 | p->transmission_mode != TRANSMISSION_MODE_8K) | ||
149 | return -EINVAL; | ||
150 | |||
151 | if (p->constellation != QPSK && | ||
152 | p->constellation != QAM_16 && | ||
153 | p->constellation != QAM_64) | ||
154 | return -EINVAL; | ||
155 | |||
156 | if (p->hierarchy_information < HIERARCHY_NONE || | ||
157 | p->hierarchy_information > HIERARCHY_4) | ||
158 | return -EINVAL; | ||
159 | |||
160 | if (p->bandwidth < BANDWIDTH_8_MHZ && p->bandwidth > BANDWIDTH_6_MHZ) | ||
161 | return -EINVAL; | ||
162 | |||
163 | if (p->bandwidth == BANDWIDTH_7_MHZ) | ||
164 | cx22700_writereg (state, 0x09, cx22700_readreg (state, 0x09 | 0x10)); | ||
165 | else | ||
166 | cx22700_writereg (state, 0x09, cx22700_readreg (state, 0x09 & ~0x10)); | ||
167 | |||
168 | val = qam_tab[p->constellation - QPSK]; | ||
169 | val |= p->hierarchy_information - HIERARCHY_NONE; | ||
170 | |||
171 | cx22700_writereg (state, 0x04, val); | ||
172 | |||
173 | val = fec_tab[p->code_rate_HP - FEC_1_2] << 3; | ||
174 | val |= fec_tab[p->code_rate_LP - FEC_1_2]; | ||
175 | |||
176 | cx22700_writereg (state, 0x05, val); | ||
177 | |||
178 | val = (p->guard_interval - GUARD_INTERVAL_1_32) << 2; | ||
179 | val |= p->transmission_mode - TRANSMISSION_MODE_2K; | ||
180 | |||
181 | cx22700_writereg (state, 0x06, val); | ||
182 | |||
183 | cx22700_writereg (state, 0x08, 0x04 | 0x02); /* use user tps parameters */ | ||
184 | cx22700_writereg (state, 0x08, 0x04); /* restart aquisition */ | ||
185 | |||
186 | return 0; | ||
187 | } | ||
188 | |||
189 | static int cx22700_get_tps (struct cx22700_state* state, struct dvb_ofdm_parameters *p) | ||
190 | { | ||
191 | static const fe_modulation_t qam_tab [3] = { QPSK, QAM_16, QAM_64 }; | ||
192 | static const fe_code_rate_t fec_tab [5] = { FEC_1_2, FEC_2_3, FEC_3_4, | ||
193 | FEC_5_6, FEC_7_8 }; | ||
194 | u8 val; | ||
195 | |||
196 | dprintk ("%s\n", __FUNCTION__); | ||
197 | |||
198 | if (!(cx22700_readreg(state, 0x07) & 0x20)) /* tps valid? */ | ||
199 | return -EAGAIN; | ||
200 | |||
201 | val = cx22700_readreg (state, 0x01); | ||
202 | |||
203 | if ((val & 0x7) > 4) | ||
204 | p->hierarchy_information = HIERARCHY_AUTO; | ||
205 | else | ||
206 | p->hierarchy_information = HIERARCHY_NONE + (val & 0x7); | ||
207 | |||
208 | if (((val >> 3) & 0x3) > 2) | ||
209 | p->constellation = QAM_AUTO; | ||
210 | else | ||
211 | p->constellation = qam_tab[(val >> 3) & 0x3]; | ||
212 | |||
213 | val = cx22700_readreg (state, 0x02); | ||
214 | |||
215 | if (((val >> 3) & 0x07) > 4) | ||
216 | p->code_rate_HP = FEC_AUTO; | ||
217 | else | ||
218 | p->code_rate_HP = fec_tab[(val >> 3) & 0x07]; | ||
219 | |||
220 | if ((val & 0x07) > 4) | ||
221 | p->code_rate_LP = FEC_AUTO; | ||
222 | else | ||
223 | p->code_rate_LP = fec_tab[val & 0x07]; | ||
224 | |||
225 | val = cx22700_readreg (state, 0x03); | ||
226 | |||
227 | p->guard_interval = GUARD_INTERVAL_1_32 + ((val >> 6) & 0x3); | ||
228 | p->transmission_mode = TRANSMISSION_MODE_2K + ((val >> 5) & 0x1); | ||
229 | |||
230 | return 0; | ||
231 | } | ||
232 | |||
233 | static int cx22700_init (struct dvb_frontend* fe) | ||
234 | |||
235 | { struct cx22700_state* state = (struct cx22700_state*) fe->demodulator_priv; | ||
236 | int i; | ||
237 | |||
238 | dprintk("cx22700_init: init chip\n"); | ||
239 | |||
240 | cx22700_writereg (state, 0x00, 0x02); /* soft reset */ | ||
241 | cx22700_writereg (state, 0x00, 0x00); | ||
242 | |||
243 | msleep(10); | ||
244 | |||
245 | for (i=0; i<sizeof(init_tab); i+=2) | ||
246 | cx22700_writereg (state, init_tab[i], init_tab[i+1]); | ||
247 | |||
248 | cx22700_writereg (state, 0x00, 0x01); | ||
249 | |||
250 | if (state->config->pll_init) { | ||
251 | cx22700_writereg (state, 0x0a, 0x00); /* open i2c bus switch */ | ||
252 | state->config->pll_init(fe); | ||
253 | cx22700_writereg (state, 0x0a, 0x01); /* close i2c bus switch */ | ||
254 | } | ||
255 | |||
256 | return 0; | ||
257 | } | ||
258 | |||
259 | static int cx22700_read_status(struct dvb_frontend* fe, fe_status_t* status) | ||
260 | { | ||
261 | struct cx22700_state* state = (struct cx22700_state*) fe->demodulator_priv; | ||
262 | |||
263 | u16 rs_ber = (cx22700_readreg (state, 0x0d) << 9) | ||
264 | | (cx22700_readreg (state, 0x0e) << 1); | ||
265 | u8 sync = cx22700_readreg (state, 0x07); | ||
266 | |||
267 | *status = 0; | ||
268 | |||
269 | if (rs_ber < 0xff00) | ||
270 | *status |= FE_HAS_SIGNAL; | ||
271 | |||
272 | if (sync & 0x20) | ||
273 | *status |= FE_HAS_CARRIER; | ||
274 | |||
275 | if (sync & 0x10) | ||
276 | *status |= FE_HAS_VITERBI; | ||
277 | |||
278 | if (sync & 0x10) | ||
279 | *status |= FE_HAS_SYNC; | ||
280 | |||
281 | if (*status == 0x0f) | ||
282 | *status |= FE_HAS_LOCK; | ||
283 | |||
284 | return 0; | ||
285 | } | ||
286 | |||
287 | static int cx22700_read_ber(struct dvb_frontend* fe, u32* ber) | ||
288 | { | ||
289 | struct cx22700_state* state = (struct cx22700_state*) fe->demodulator_priv; | ||
290 | |||
291 | *ber = cx22700_readreg (state, 0x0c) & 0x7f; | ||
292 | cx22700_writereg (state, 0x0c, 0x00); | ||
293 | |||
294 | return 0; | ||
295 | } | ||
296 | |||
297 | static int cx22700_read_signal_strength(struct dvb_frontend* fe, u16* signal_strength) | ||
298 | { | ||
299 | struct cx22700_state* state = (struct cx22700_state*) fe->demodulator_priv; | ||
300 | |||
301 | u16 rs_ber = (cx22700_readreg (state, 0x0d) << 9) | ||
302 | | (cx22700_readreg (state, 0x0e) << 1); | ||
303 | *signal_strength = ~rs_ber; | ||
304 | |||
305 | return 0; | ||
306 | } | ||
307 | |||
308 | static int cx22700_read_snr(struct dvb_frontend* fe, u16* snr) | ||
309 | { | ||
310 | struct cx22700_state* state = (struct cx22700_state*) fe->demodulator_priv; | ||
311 | |||
312 | u16 rs_ber = (cx22700_readreg (state, 0x0d) << 9) | ||
313 | | (cx22700_readreg (state, 0x0e) << 1); | ||
314 | *snr = ~rs_ber; | ||
315 | |||
316 | return 0; | ||
317 | } | ||
318 | |||
319 | static int cx22700_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks) | ||
320 | { | ||
321 | struct cx22700_state* state = (struct cx22700_state*) fe->demodulator_priv; | ||
322 | |||
323 | *ucblocks = cx22700_readreg (state, 0x0f); | ||
324 | cx22700_writereg (state, 0x0f, 0x00); | ||
325 | |||
326 | return 0; | ||
327 | } | ||
328 | |||
329 | static int cx22700_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p) | ||
330 | { | ||
331 | struct cx22700_state* state = (struct cx22700_state*) fe->demodulator_priv; | ||
332 | |||
333 | cx22700_writereg (state, 0x00, 0x02); /* XXX CHECKME: soft reset*/ | ||
334 | cx22700_writereg (state, 0x00, 0x00); | ||
335 | |||
336 | cx22700_writereg (state, 0x0a, 0x00); /* open i2c bus switch */ | ||
337 | state->config->pll_set(fe, p); | ||
338 | cx22700_writereg (state, 0x0a, 0x01); /* close i2c bus switch */ | ||
339 | cx22700_set_inversion (state, p->inversion); | ||
340 | cx22700_set_tps (state, &p->u.ofdm); | ||
341 | cx22700_writereg (state, 0x37, 0x01); /* PAL loop filter off */ | ||
342 | cx22700_writereg (state, 0x00, 0x01); /* restart acquire */ | ||
343 | |||
344 | return 0; | ||
345 | } | ||
346 | |||
347 | static int cx22700_get_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p) | ||
348 | { | ||
349 | struct cx22700_state* state = (struct cx22700_state*) fe->demodulator_priv; | ||
350 | u8 reg09 = cx22700_readreg (state, 0x09); | ||
351 | |||
352 | p->inversion = reg09 & 0x1 ? INVERSION_ON : INVERSION_OFF; | ||
353 | return cx22700_get_tps (state, &p->u.ofdm); | ||
354 | } | ||
355 | |||
356 | static int cx22700_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings* fesettings) | ||
357 | { | ||
358 | fesettings->min_delay_ms = 150; | ||
359 | fesettings->step_size = 166667; | ||
360 | fesettings->max_drift = 166667*2; | ||
361 | return 0; | ||
362 | } | ||
363 | |||
364 | static void cx22700_release(struct dvb_frontend* fe) | ||
365 | { | ||
366 | struct cx22700_state* state = (struct cx22700_state*) fe->demodulator_priv; | ||
367 | kfree(state); | ||
368 | } | ||
369 | |||
370 | static struct dvb_frontend_ops cx22700_ops; | ||
371 | |||
372 | struct dvb_frontend* cx22700_attach(const struct cx22700_config* config, | ||
373 | struct i2c_adapter* i2c) | ||
374 | { | ||
375 | struct cx22700_state* state = NULL; | ||
376 | |||
377 | /* allocate memory for the internal state */ | ||
378 | state = (struct cx22700_state*) kmalloc(sizeof(struct cx22700_state), GFP_KERNEL); | ||
379 | if (state == NULL) goto error; | ||
380 | |||
381 | /* setup the state */ | ||
382 | state->config = config; | ||
383 | state->i2c = i2c; | ||
384 | memcpy(&state->ops, &cx22700_ops, sizeof(struct dvb_frontend_ops)); | ||
385 | |||
386 | /* check if the demod is there */ | ||
387 | if (cx22700_readreg(state, 0x07) < 0) goto error; | ||
388 | |||
389 | /* create dvb_frontend */ | ||
390 | state->frontend.ops = &state->ops; | ||
391 | state->frontend.demodulator_priv = state; | ||
392 | return &state->frontend; | ||
393 | |||
394 | error: | ||
395 | kfree(state); | ||
396 | return NULL; | ||
397 | } | ||
398 | |||
399 | static struct dvb_frontend_ops cx22700_ops = { | ||
400 | |||
401 | .info = { | ||
402 | .name = "Conexant CX22700 DVB-T", | ||
403 | .type = FE_OFDM, | ||
404 | .frequency_min = 470000000, | ||
405 | .frequency_max = 860000000, | ||
406 | .frequency_stepsize = 166667, | ||
407 | .caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | | ||
408 | FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO | | ||
409 | FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | | ||
410 | FE_CAN_RECOVER | ||
411 | }, | ||
412 | |||
413 | .release = cx22700_release, | ||
414 | |||
415 | .init = cx22700_init, | ||
416 | |||
417 | .set_frontend = cx22700_set_frontend, | ||
418 | .get_frontend = cx22700_get_frontend, | ||
419 | .get_tune_settings = cx22700_get_tune_settings, | ||
420 | |||
421 | .read_status = cx22700_read_status, | ||
422 | .read_ber = cx22700_read_ber, | ||
423 | .read_signal_strength = cx22700_read_signal_strength, | ||
424 | .read_snr = cx22700_read_snr, | ||
425 | .read_ucblocks = cx22700_read_ucblocks, | ||
426 | }; | ||
427 | |||
428 | module_param(debug, int, 0644); | ||
429 | MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off)."); | ||
430 | |||
431 | MODULE_DESCRIPTION("Conexant CX22700 DVB-T Demodulator driver"); | ||
432 | MODULE_AUTHOR("Holger Waechtler"); | ||
433 | MODULE_LICENSE("GPL"); | ||
434 | |||
435 | EXPORT_SYMBOL(cx22700_attach); | ||
diff --git a/drivers/media/dvb/frontends/cx22700.h b/drivers/media/dvb/frontends/cx22700.h new file mode 100644 index 000000000000..c9145b45874b --- /dev/null +++ b/drivers/media/dvb/frontends/cx22700.h | |||
@@ -0,0 +1,41 @@ | |||
1 | /* | ||
2 | Conexant CX22700 DVB OFDM demodulator driver | ||
3 | |||
4 | Copyright (C) 2001-2002 Convergence Integrated Media GmbH | ||
5 | Holger Waechtler <holger@convergence.de> | ||
6 | |||
7 | This program is free software; you can redistribute it and/or modify | ||
8 | it under the terms of the GNU General Public License as published by | ||
9 | the Free Software Foundation; either version 2 of the License, or | ||
10 | (at your option) any later version. | ||
11 | |||
12 | This program is distributed in the hope that it will be useful, | ||
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | GNU General Public License for more details. | ||
16 | |||
17 | You should have received a copy of the GNU General Public License | ||
18 | along with this program; if not, write to the Free Software | ||
19 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
20 | |||
21 | */ | ||
22 | |||
23 | #ifndef CX22700_H | ||
24 | #define CX22700_H | ||
25 | |||
26 | #include <linux/dvb/frontend.h> | ||
27 | |||
28 | struct cx22700_config | ||
29 | { | ||
30 | /* the demodulator's i2c address */ | ||
31 | u8 demod_address; | ||
32 | |||
33 | /* PLL maintenance */ | ||
34 | int (*pll_init)(struct dvb_frontend* fe); | ||
35 | int (*pll_set)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params); | ||
36 | }; | ||
37 | |||
38 | extern struct dvb_frontend* cx22700_attach(const struct cx22700_config* config, | ||
39 | struct i2c_adapter* i2c); | ||
40 | |||
41 | #endif // CX22700_H | ||
diff --git a/drivers/media/dvb/frontends/cx22702.c b/drivers/media/dvb/frontends/cx22702.c new file mode 100644 index 000000000000..1930b513eefa --- /dev/null +++ b/drivers/media/dvb/frontends/cx22702.c | |||
@@ -0,0 +1,519 @@ | |||
1 | /* | ||
2 | Conexant 22702 DVB OFDM demodulator driver | ||
3 | |||
4 | based on: | ||
5 | Alps TDMB7 DVB OFDM demodulator driver | ||
6 | |||
7 | Copyright (C) 2001-2002 Convergence Integrated Media GmbH | ||
8 | Holger Waechtler <holger@convergence.de> | ||
9 | |||
10 | Copyright (C) 2004 Steven Toth <steve@toth.demon.co.uk> | ||
11 | |||
12 | This program is free software; you can redistribute it and/or modify | ||
13 | it under the terms of the GNU General Public License as published by | ||
14 | the Free Software Foundation; either version 2 of the License, or | ||
15 | (at your option) any later version. | ||
16 | |||
17 | This program is distributed in the hope that it will be useful, | ||
18 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
19 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
20 | GNU General Public License for more details. | ||
21 | |||
22 | You should have received a copy of the GNU General Public License | ||
23 | along with this program; if not, write to the Free Software | ||
24 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
25 | |||
26 | */ | ||
27 | |||
28 | #include <linux/kernel.h> | ||
29 | #include <linux/init.h> | ||
30 | #include <linux/module.h> | ||
31 | #include <linux/string.h> | ||
32 | #include <linux/slab.h> | ||
33 | #include <linux/delay.h> | ||
34 | #include "dvb_frontend.h" | ||
35 | #include "cx22702.h" | ||
36 | |||
37 | |||
38 | struct cx22702_state { | ||
39 | |||
40 | struct i2c_adapter* i2c; | ||
41 | |||
42 | struct dvb_frontend_ops ops; | ||
43 | |||
44 | /* configuration settings */ | ||
45 | const struct cx22702_config* config; | ||
46 | |||
47 | struct dvb_frontend frontend; | ||
48 | |||
49 | /* previous uncorrected block counter */ | ||
50 | u8 prevUCBlocks; | ||
51 | }; | ||
52 | |||
53 | static int debug = 0; | ||
54 | #define dprintk if (debug) printk | ||
55 | |||
56 | /* Register values to initialise the demod */ | ||
57 | static u8 init_tab [] = { | ||
58 | 0x00, 0x00, /* Stop aquisition */ | ||
59 | 0x0B, 0x06, | ||
60 | 0x09, 0x01, | ||
61 | 0x0D, 0x41, | ||
62 | 0x16, 0x32, | ||
63 | 0x20, 0x0A, | ||
64 | 0x21, 0x17, | ||
65 | 0x24, 0x3e, | ||
66 | 0x26, 0xff, | ||
67 | 0x27, 0x10, | ||
68 | 0x28, 0x00, | ||
69 | 0x29, 0x00, | ||
70 | 0x2a, 0x10, | ||
71 | 0x2b, 0x00, | ||
72 | 0x2c, 0x10, | ||
73 | 0x2d, 0x00, | ||
74 | 0x48, 0xd4, | ||
75 | 0x49, 0x56, | ||
76 | 0x6b, 0x1e, | ||
77 | 0xc8, 0x02, | ||
78 | 0xf8, 0x02, | ||
79 | 0xf9, 0x00, | ||
80 | 0xfa, 0x00, | ||
81 | 0xfb, 0x00, | ||
82 | 0xfc, 0x00, | ||
83 | 0xfd, 0x00, | ||
84 | }; | ||
85 | |||
86 | static int cx22702_writereg (struct cx22702_state* state, u8 reg, u8 data) | ||
87 | { | ||
88 | int ret; | ||
89 | u8 buf [] = { reg, data }; | ||
90 | struct i2c_msg msg = { .addr = state->config->demod_address, .flags = 0, .buf = buf, .len = 2 }; | ||
91 | |||
92 | ret = i2c_transfer(state->i2c, &msg, 1); | ||
93 | |||
94 | if (ret != 1) | ||
95 | printk("%s: writereg error (reg == 0x%02x, val == 0x%02x, ret == %i)\n", | ||
96 | __FUNCTION__, reg, data, ret); | ||
97 | |||
98 | return (ret != 1) ? -1 : 0; | ||
99 | } | ||
100 | |||
101 | static u8 cx22702_readreg (struct cx22702_state* state, u8 reg) | ||
102 | { | ||
103 | int ret; | ||
104 | u8 b0 [] = { reg }; | ||
105 | u8 b1 [] = { 0 }; | ||
106 | |||
107 | struct i2c_msg msg [] = { | ||
108 | { .addr = state->config->demod_address, .flags = 0, .buf = b0, .len = 1 }, | ||
109 | { .addr = state->config->demod_address, .flags = I2C_M_RD, .buf = b1, .len = 1 } }; | ||
110 | |||
111 | ret = i2c_transfer(state->i2c, msg, 2); | ||
112 | |||
113 | if (ret != 2) | ||
114 | printk("%s: readreg error (ret == %i)\n", __FUNCTION__, ret); | ||
115 | |||
116 | return b1[0]; | ||
117 | } | ||
118 | |||
119 | static int cx22702_set_inversion (struct cx22702_state *state, int inversion) | ||
120 | { | ||
121 | u8 val; | ||
122 | |||
123 | switch (inversion) { | ||
124 | |||
125 | case INVERSION_AUTO: | ||
126 | return -EOPNOTSUPP; | ||
127 | |||
128 | case INVERSION_ON: | ||
129 | val = cx22702_readreg (state, 0x0C); | ||
130 | return cx22702_writereg (state, 0x0C, val | 0x01); | ||
131 | |||
132 | case INVERSION_OFF: | ||
133 | val = cx22702_readreg (state, 0x0C); | ||
134 | return cx22702_writereg (state, 0x0C, val & 0xfe); | ||
135 | |||
136 | default: | ||
137 | return -EINVAL; | ||
138 | |||
139 | } | ||
140 | |||
141 | } | ||
142 | |||
143 | /* Retrieve the demod settings */ | ||
144 | static int cx22702_get_tps (struct cx22702_state *state, struct dvb_ofdm_parameters *p) | ||
145 | { | ||
146 | u8 val; | ||
147 | |||
148 | /* Make sure the TPS regs are valid */ | ||
149 | if (!(cx22702_readreg(state, 0x0A) & 0x20)) | ||
150 | return -EAGAIN; | ||
151 | |||
152 | val = cx22702_readreg (state, 0x01); | ||
153 | switch( (val&0x18)>>3) { | ||
154 | case 0: p->constellation = QPSK; break; | ||
155 | case 1: p->constellation = QAM_16; break; | ||
156 | case 2: p->constellation = QAM_64; break; | ||
157 | } | ||
158 | switch( val&0x07 ) { | ||
159 | case 0: p->hierarchy_information = HIERARCHY_NONE; break; | ||
160 | case 1: p->hierarchy_information = HIERARCHY_1; break; | ||
161 | case 2: p->hierarchy_information = HIERARCHY_2; break; | ||
162 | case 3: p->hierarchy_information = HIERARCHY_4; break; | ||
163 | } | ||
164 | |||
165 | |||
166 | val = cx22702_readreg (state, 0x02); | ||
167 | switch( (val&0x38)>>3 ) { | ||
168 | case 0: p->code_rate_HP = FEC_1_2; break; | ||
169 | case 1: p->code_rate_HP = FEC_2_3; break; | ||
170 | case 2: p->code_rate_HP = FEC_3_4; break; | ||
171 | case 3: p->code_rate_HP = FEC_5_6; break; | ||
172 | case 4: p->code_rate_HP = FEC_7_8; break; | ||
173 | } | ||
174 | switch( val&0x07 ) { | ||
175 | case 0: p->code_rate_LP = FEC_1_2; break; | ||
176 | case 1: p->code_rate_LP = FEC_2_3; break; | ||
177 | case 2: p->code_rate_LP = FEC_3_4; break; | ||
178 | case 3: p->code_rate_LP = FEC_5_6; break; | ||
179 | case 4: p->code_rate_LP = FEC_7_8; break; | ||
180 | } | ||
181 | |||
182 | |||
183 | val = cx22702_readreg (state, 0x03); | ||
184 | switch( (val&0x0c)>>2 ) { | ||
185 | case 0: p->guard_interval = GUARD_INTERVAL_1_32; break; | ||
186 | case 1: p->guard_interval = GUARD_INTERVAL_1_16; break; | ||
187 | case 2: p->guard_interval = GUARD_INTERVAL_1_8; break; | ||
188 | case 3: p->guard_interval = GUARD_INTERVAL_1_4; break; | ||
189 | } | ||
190 | switch( val&0x03 ) { | ||
191 | case 0: p->transmission_mode = TRANSMISSION_MODE_2K; break; | ||
192 | case 1: p->transmission_mode = TRANSMISSION_MODE_8K; break; | ||
193 | } | ||
194 | |||
195 | return 0; | ||
196 | } | ||
197 | |||
198 | /* Talk to the demod, set the FEC, GUARD, QAM settings etc */ | ||
199 | static int cx22702_set_tps (struct dvb_frontend* fe, struct dvb_frontend_parameters *p) | ||
200 | { | ||
201 | u8 val; | ||
202 | struct cx22702_state* state = (struct cx22702_state*) fe->demodulator_priv; | ||
203 | |||
204 | /* set PLL */ | ||
205 | cx22702_writereg (state, 0x0D, cx22702_readreg(state,0x0D) &0xfe); | ||
206 | state->config->pll_set(fe, p); | ||
207 | cx22702_writereg (state, 0x0D, cx22702_readreg(state,0x0D) | 1); | ||
208 | |||
209 | /* set inversion */ | ||
210 | cx22702_set_inversion (state, p->inversion); | ||
211 | |||
212 | /* set bandwidth */ | ||
213 | switch(p->u.ofdm.bandwidth) { | ||
214 | case BANDWIDTH_6_MHZ: | ||
215 | cx22702_writereg(state, 0x0C, (cx22702_readreg(state, 0x0C) & 0xcf) | 0x20 ); | ||
216 | break; | ||
217 | case BANDWIDTH_7_MHZ: | ||
218 | cx22702_writereg(state, 0x0C, (cx22702_readreg(state, 0x0C) & 0xcf) | 0x10 ); | ||
219 | break; | ||
220 | case BANDWIDTH_8_MHZ: | ||
221 | cx22702_writereg(state, 0x0C, cx22702_readreg(state, 0x0C) &0xcf ); | ||
222 | break; | ||
223 | default: | ||
224 | dprintk ("%s: invalid bandwidth\n",__FUNCTION__); | ||
225 | return -EINVAL; | ||
226 | } | ||
227 | |||
228 | |||
229 | p->u.ofdm.code_rate_LP = FEC_AUTO; //temp hack as manual not working | ||
230 | |||
231 | /* use auto configuration? */ | ||
232 | if((p->u.ofdm.hierarchy_information==HIERARCHY_AUTO) || | ||
233 | (p->u.ofdm.constellation==QAM_AUTO) || | ||
234 | (p->u.ofdm.code_rate_HP==FEC_AUTO) || | ||
235 | (p->u.ofdm.code_rate_LP==FEC_AUTO) || | ||
236 | (p->u.ofdm.guard_interval==GUARD_INTERVAL_AUTO) || | ||
237 | (p->u.ofdm.transmission_mode==TRANSMISSION_MODE_AUTO) ) { | ||
238 | |||
239 | /* TPS Source - use hardware driven values */ | ||
240 | cx22702_writereg(state, 0x06, 0x10); | ||
241 | cx22702_writereg(state, 0x07, 0x9); | ||
242 | cx22702_writereg(state, 0x08, 0xC1); | ||
243 | cx22702_writereg(state, 0x0B, cx22702_readreg(state, 0x0B) & 0xfc ); | ||
244 | cx22702_writereg(state, 0x0C, (cx22702_readreg(state, 0x0C) & 0xBF) | 0x40 ); | ||
245 | cx22702_writereg(state, 0x00, 0x01); /* Begin aquisition */ | ||
246 | printk("%s: Autodetecting\n",__FUNCTION__); | ||
247 | return 0; | ||
248 | } | ||
249 | |||
250 | /* manually programmed values */ | ||
251 | val=0; | ||
252 | switch(p->u.ofdm.constellation) { | ||
253 | case QPSK: val = (val&0xe7); break; | ||
254 | case QAM_16: val = (val&0xe7)|0x08; break; | ||
255 | case QAM_64: val = (val&0xe7)|0x10; break; | ||
256 | default: | ||
257 | dprintk ("%s: invalid constellation\n",__FUNCTION__); | ||
258 | return -EINVAL; | ||
259 | } | ||
260 | switch(p->u.ofdm.hierarchy_information) { | ||
261 | case HIERARCHY_NONE: val = (val&0xf8); break; | ||
262 | case HIERARCHY_1: val = (val&0xf8)|1; break; | ||
263 | case HIERARCHY_2: val = (val&0xf8)|2; break; | ||
264 | case HIERARCHY_4: val = (val&0xf8)|3; break; | ||
265 | default: | ||
266 | dprintk ("%s: invalid hierarchy\n",__FUNCTION__); | ||
267 | return -EINVAL; | ||
268 | } | ||
269 | cx22702_writereg (state, 0x06, val); | ||
270 | |||
271 | val=0; | ||
272 | switch(p->u.ofdm.code_rate_HP) { | ||
273 | case FEC_NONE: | ||
274 | case FEC_1_2: val = (val&0xc7); break; | ||
275 | case FEC_2_3: val = (val&0xc7)|0x08; break; | ||
276 | case FEC_3_4: val = (val&0xc7)|0x10; break; | ||
277 | case FEC_5_6: val = (val&0xc7)|0x18; break; | ||
278 | case FEC_7_8: val = (val&0xc7)|0x20; break; | ||
279 | default: | ||
280 | dprintk ("%s: invalid code_rate_HP\n",__FUNCTION__); | ||
281 | return -EINVAL; | ||
282 | } | ||
283 | switch(p->u.ofdm.code_rate_LP) { | ||
284 | case FEC_NONE: | ||
285 | case FEC_1_2: val = (val&0xf8); break; | ||
286 | case FEC_2_3: val = (val&0xf8)|1; break; | ||
287 | case FEC_3_4: val = (val&0xf8)|2; break; | ||
288 | case FEC_5_6: val = (val&0xf8)|3; break; | ||
289 | case FEC_7_8: val = (val&0xf8)|4; break; | ||
290 | default: | ||
291 | dprintk ("%s: invalid code_rate_LP\n",__FUNCTION__); | ||
292 | return -EINVAL; | ||
293 | } | ||
294 | cx22702_writereg (state, 0x07, val); | ||
295 | |||
296 | val=0; | ||
297 | switch(p->u.ofdm.guard_interval) { | ||
298 | case GUARD_INTERVAL_1_32: val = (val&0xf3); break; | ||
299 | case GUARD_INTERVAL_1_16: val = (val&0xf3)|0x04; break; | ||
300 | case GUARD_INTERVAL_1_8: val = (val&0xf3)|0x08; break; | ||
301 | case GUARD_INTERVAL_1_4: val = (val&0xf3)|0x0c; break; | ||
302 | default: | ||
303 | dprintk ("%s: invalid guard_interval\n",__FUNCTION__); | ||
304 | return -EINVAL; | ||
305 | } | ||
306 | switch(p->u.ofdm.transmission_mode) { | ||
307 | case TRANSMISSION_MODE_2K: val = (val&0xfc); break; | ||
308 | case TRANSMISSION_MODE_8K: val = (val&0xfc)|1; break; | ||
309 | default: | ||
310 | dprintk ("%s: invalid transmission_mode\n",__FUNCTION__); | ||
311 | return -EINVAL; | ||
312 | } | ||
313 | cx22702_writereg(state, 0x08, val); | ||
314 | cx22702_writereg(state, 0x0B, (cx22702_readreg(state, 0x0B) & 0xfc) | 0x02 ); | ||
315 | cx22702_writereg(state, 0x0C, (cx22702_readreg(state, 0x0C) & 0xBF) | 0x40 ); | ||
316 | |||
317 | /* Begin channel aquisition */ | ||
318 | cx22702_writereg(state, 0x00, 0x01); | ||
319 | |||
320 | return 0; | ||
321 | } | ||
322 | |||
323 | /* Reset the demod hardware and reset all of the configuration registers | ||
324 | to a default state. */ | ||
325 | static int cx22702_init (struct dvb_frontend* fe) | ||
326 | { | ||
327 | int i; | ||
328 | struct cx22702_state* state = (struct cx22702_state*) fe->demodulator_priv; | ||
329 | |||
330 | cx22702_writereg (state, 0x00, 0x02); | ||
331 | |||
332 | msleep(10); | ||
333 | |||
334 | for (i=0; i<sizeof(init_tab); i+=2) | ||
335 | cx22702_writereg (state, init_tab[i], init_tab[i+1]); | ||
336 | |||
337 | |||
338 | /* init PLL */ | ||
339 | if (state->config->pll_init) { | ||
340 | cx22702_writereg (state, 0x0D, cx22702_readreg(state,0x0D) &0xfe); | ||
341 | state->config->pll_init(fe); | ||
342 | cx22702_writereg (state, 0x0D, cx22702_readreg(state,0x0D) | 1); | ||
343 | } | ||
344 | |||
345 | return 0; | ||
346 | } | ||
347 | |||
348 | static int cx22702_read_status(struct dvb_frontend* fe, fe_status_t* status) | ||
349 | { | ||
350 | struct cx22702_state* state = (struct cx22702_state*) fe->demodulator_priv; | ||
351 | u8 reg0A; | ||
352 | u8 reg23; | ||
353 | |||
354 | *status = 0; | ||
355 | |||
356 | reg0A = cx22702_readreg (state, 0x0A); | ||
357 | reg23 = cx22702_readreg (state, 0x23); | ||
358 | |||
359 | dprintk ("%s: status demod=0x%02x agc=0x%02x\n" | ||
360 | ,__FUNCTION__,reg0A,reg23); | ||
361 | |||
362 | if(reg0A & 0x10) { | ||
363 | *status |= FE_HAS_LOCK; | ||
364 | *status |= FE_HAS_VITERBI; | ||
365 | *status |= FE_HAS_SYNC; | ||
366 | } | ||
367 | |||
368 | if(reg0A & 0x20) | ||
369 | *status |= FE_HAS_CARRIER; | ||
370 | |||
371 | if(reg23 < 0xf0) | ||
372 | *status |= FE_HAS_SIGNAL; | ||
373 | |||
374 | return 0; | ||
375 | } | ||
376 | |||
377 | static int cx22702_read_ber(struct dvb_frontend* fe, u32* ber) | ||
378 | { | ||
379 | struct cx22702_state* state = (struct cx22702_state*) fe->demodulator_priv; | ||
380 | |||
381 | if(cx22702_readreg (state, 0xE4) & 0x02) { | ||
382 | /* Realtime statistics */ | ||
383 | *ber = (cx22702_readreg (state, 0xDE) & 0x7F) << 7 | ||
384 | | (cx22702_readreg (state, 0xDF)&0x7F); | ||
385 | } else { | ||
386 | /* Averagtine statistics */ | ||
387 | *ber = (cx22702_readreg (state, 0xDE) & 0x7F) << 7 | ||
388 | | cx22702_readreg (state, 0xDF); | ||
389 | } | ||
390 | |||
391 | return 0; | ||
392 | } | ||
393 | |||
394 | static int cx22702_read_signal_strength(struct dvb_frontend* fe, u16* signal_strength) | ||
395 | { | ||
396 | struct cx22702_state* state = (struct cx22702_state*) fe->demodulator_priv; | ||
397 | |||
398 | *signal_strength = cx22702_readreg (state, 0x23); | ||
399 | |||
400 | return 0; | ||
401 | } | ||
402 | |||
403 | static int cx22702_read_snr(struct dvb_frontend* fe, u16* snr) | ||
404 | { | ||
405 | struct cx22702_state* state = (struct cx22702_state*) fe->demodulator_priv; | ||
406 | |||
407 | u16 rs_ber=0; | ||
408 | if(cx22702_readreg (state, 0xE4) & 0x02) { | ||
409 | /* Realtime statistics */ | ||
410 | rs_ber = (cx22702_readreg (state, 0xDE) & 0x7F) << 7 | ||
411 | | (cx22702_readreg (state, 0xDF)& 0x7F); | ||
412 | } else { | ||
413 | /* Averagine statistics */ | ||
414 | rs_ber = (cx22702_readreg (state, 0xDE) & 0x7F) << 8 | ||
415 | | cx22702_readreg (state, 0xDF); | ||
416 | } | ||
417 | *snr = ~rs_ber; | ||
418 | |||
419 | return 0; | ||
420 | } | ||
421 | |||
422 | static int cx22702_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks) | ||
423 | { | ||
424 | struct cx22702_state* state = (struct cx22702_state*) fe->demodulator_priv; | ||
425 | |||
426 | u8 _ucblocks; | ||
427 | |||
428 | /* RS Uncorrectable Packet Count then reset */ | ||
429 | _ucblocks = cx22702_readreg (state, 0xE3); | ||
430 | if (state->prevUCBlocks < _ucblocks) *ucblocks = (_ucblocks - state->prevUCBlocks); | ||
431 | else *ucblocks = state->prevUCBlocks - _ucblocks; | ||
432 | state->prevUCBlocks = _ucblocks; | ||
433 | |||
434 | return 0; | ||
435 | } | ||
436 | |||
437 | static int cx22702_get_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p) | ||
438 | { | ||
439 | struct cx22702_state* state = (struct cx22702_state*) fe->demodulator_priv; | ||
440 | |||
441 | u8 reg0C = cx22702_readreg (state, 0x0C); | ||
442 | |||
443 | p->inversion = reg0C & 0x1 ? INVERSION_ON : INVERSION_OFF; | ||
444 | return cx22702_get_tps (state, &p->u.ofdm); | ||
445 | } | ||
446 | |||
447 | static void cx22702_release(struct dvb_frontend* fe) | ||
448 | { | ||
449 | struct cx22702_state* state = (struct cx22702_state*) fe->demodulator_priv; | ||
450 | kfree(state); | ||
451 | } | ||
452 | |||
453 | static struct dvb_frontend_ops cx22702_ops; | ||
454 | |||
455 | struct dvb_frontend* cx22702_attach(const struct cx22702_config* config, | ||
456 | struct i2c_adapter* i2c) | ||
457 | { | ||
458 | struct cx22702_state* state = NULL; | ||
459 | |||
460 | /* allocate memory for the internal state */ | ||
461 | state = (struct cx22702_state*) kmalloc(sizeof(struct cx22702_state), GFP_KERNEL); | ||
462 | if (state == NULL) goto error; | ||
463 | |||
464 | /* setup the state */ | ||
465 | state->config = config; | ||
466 | state->i2c = i2c; | ||
467 | memcpy(&state->ops, &cx22702_ops, sizeof(struct dvb_frontend_ops)); | ||
468 | state->prevUCBlocks = 0; | ||
469 | |||
470 | /* check if the demod is there */ | ||
471 | if (cx22702_readreg(state, 0x1f) != 0x3) goto error; | ||
472 | |||
473 | /* create dvb_frontend */ | ||
474 | state->frontend.ops = &state->ops; | ||
475 | state->frontend.demodulator_priv = state; | ||
476 | return &state->frontend; | ||
477 | |||
478 | error: | ||
479 | kfree(state); | ||
480 | return NULL; | ||
481 | } | ||
482 | |||
483 | static struct dvb_frontend_ops cx22702_ops = { | ||
484 | |||
485 | .info = { | ||
486 | .name = "Conexant CX22702 DVB-T", | ||
487 | .type = FE_OFDM, | ||
488 | .frequency_min = 177000000, | ||
489 | .frequency_max = 858000000, | ||
490 | .frequency_stepsize = 166666, | ||
491 | .caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | | ||
492 | FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO | | ||
493 | FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO | | ||
494 | FE_CAN_HIERARCHY_AUTO | FE_CAN_GUARD_INTERVAL_AUTO | | ||
495 | FE_CAN_TRANSMISSION_MODE_AUTO | FE_CAN_RECOVER | ||
496 | }, | ||
497 | |||
498 | .release = cx22702_release, | ||
499 | |||
500 | .init = cx22702_init, | ||
501 | |||
502 | .set_frontend = cx22702_set_tps, | ||
503 | .get_frontend = cx22702_get_frontend, | ||
504 | |||
505 | .read_status = cx22702_read_status, | ||
506 | .read_ber = cx22702_read_ber, | ||
507 | .read_signal_strength = cx22702_read_signal_strength, | ||
508 | .read_snr = cx22702_read_snr, | ||
509 | .read_ucblocks = cx22702_read_ucblocks, | ||
510 | }; | ||
511 | |||
512 | module_param(debug, int, 0644); | ||
513 | MODULE_PARM_DESC(debug, "Enable verbose debug messages"); | ||
514 | |||
515 | MODULE_DESCRIPTION("Conexant CX22702 DVB-T Demodulator driver"); | ||
516 | MODULE_AUTHOR("Steven Toth"); | ||
517 | MODULE_LICENSE("GPL"); | ||
518 | |||
519 | EXPORT_SYMBOL(cx22702_attach); | ||
diff --git a/drivers/media/dvb/frontends/cx22702.h b/drivers/media/dvb/frontends/cx22702.h new file mode 100644 index 000000000000..6e34f997aba2 --- /dev/null +++ b/drivers/media/dvb/frontends/cx22702.h | |||
@@ -0,0 +1,46 @@ | |||
1 | /* | ||
2 | Conexant 22702 DVB OFDM demodulator driver | ||
3 | |||
4 | based on: | ||
5 | Alps TDMB7 DVB OFDM demodulator driver | ||
6 | |||
7 | Copyright (C) 2001-2002 Convergence Integrated Media GmbH | ||
8 | Holger Waechtler <holger@convergence.de> | ||
9 | |||
10 | Copyright (C) 2004 Steven Toth <steve@toth.demon.co.uk> | ||
11 | |||
12 | This program is free software; you can redistribute it and/or modify | ||
13 | it under the terms of the GNU General Public License as published by | ||
14 | the Free Software Foundation; either version 2 of the License, or | ||
15 | (at your option) any later version. | ||
16 | |||
17 | This program is distributed in the hope that it will be useful, | ||
18 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
19 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
20 | GNU General Public License for more details. | ||
21 | |||
22 | You should have received a copy of the GNU General Public License | ||
23 | along with this program; if not, write to the Free Software | ||
24 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
25 | |||
26 | */ | ||
27 | |||
28 | #ifndef CX22702_H | ||
29 | #define CX22702_H | ||
30 | |||
31 | #include <linux/dvb/frontend.h> | ||
32 | |||
33 | struct cx22702_config | ||
34 | { | ||
35 | /* the demodulator's i2c address */ | ||
36 | u8 demod_address; | ||
37 | |||
38 | /* PLL maintenance */ | ||
39 | int (*pll_init)(struct dvb_frontend* fe); | ||
40 | int (*pll_set)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params); | ||
41 | }; | ||
42 | |||
43 | extern struct dvb_frontend* cx22702_attach(const struct cx22702_config* config, | ||
44 | struct i2c_adapter* i2c); | ||
45 | |||
46 | #endif // CX22702_H | ||
diff --git a/drivers/media/dvb/frontends/cx24110.c b/drivers/media/dvb/frontends/cx24110.c new file mode 100644 index 000000000000..ae16112a0653 --- /dev/null +++ b/drivers/media/dvb/frontends/cx24110.c | |||
@@ -0,0 +1,657 @@ | |||
1 | /* | ||
2 | cx24110 - Single Chip Satellite Channel Receiver driver module | ||
3 | |||
4 | Copyright (C) 2002 Peter Hettkamp <peter.hettkamp@t-online.de> based on | ||
5 | work | ||
6 | Copyright (C) 1999 Convergence Integrated Media GmbH <ralph@convergence.de> | ||
7 | |||
8 | This program is free software; you can redistribute it and/or modify | ||
9 | it under the terms of the GNU General Public License as published by | ||
10 | the Free Software Foundation; either version 2 of the License, or | ||
11 | (at your option) any later version. | ||
12 | |||
13 | This program is distributed in the hope that it will be useful, | ||
14 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
16 | |||
17 | GNU General Public License for more details. | ||
18 | |||
19 | You should have received a copy of the GNU General Public License | ||
20 | along with this program; if not, write to the Free Software | ||
21 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
22 | |||
23 | */ | ||
24 | |||
25 | #include <linux/slab.h> | ||
26 | #include <linux/kernel.h> | ||
27 | #include <linux/module.h> | ||
28 | #include <linux/moduleparam.h> | ||
29 | #include <linux/init.h> | ||
30 | |||
31 | #include "dvb_frontend.h" | ||
32 | #include "cx24110.h" | ||
33 | |||
34 | |||
35 | struct cx24110_state { | ||
36 | |||
37 | struct i2c_adapter* i2c; | ||
38 | |||
39 | struct dvb_frontend_ops ops; | ||
40 | |||
41 | const struct cx24110_config* config; | ||
42 | |||
43 | struct dvb_frontend frontend; | ||
44 | |||
45 | u32 lastber; | ||
46 | u32 lastbler; | ||
47 | u32 lastesn0; | ||
48 | }; | ||
49 | |||
50 | static int debug; | ||
51 | #define dprintk(args...) \ | ||
52 | do { \ | ||
53 | if (debug) printk(KERN_DEBUG "cx24110: " args); \ | ||
54 | } while (0) | ||
55 | |||
56 | static struct {u8 reg; u8 data;} cx24110_regdata[]= | ||
57 | /* Comments beginning with @ denote this value should | ||
58 | be the default */ | ||
59 | {{0x09,0x01}, /* SoftResetAll */ | ||
60 | {0x09,0x00}, /* release reset */ | ||
61 | {0x01,0xe8}, /* MSB of code rate 27.5MS/s */ | ||
62 | {0x02,0x17}, /* middle byte " */ | ||
63 | {0x03,0x29}, /* LSB " */ | ||
64 | {0x05,0x03}, /* @ DVB mode, standard code rate 3/4 */ | ||
65 | {0x06,0xa5}, /* @ PLL 60MHz */ | ||
66 | {0x07,0x01}, /* @ Fclk, i.e. sampling clock, 60MHz */ | ||
67 | {0x0a,0x00}, /* @ partial chip disables, do not set */ | ||
68 | {0x0b,0x01}, /* set output clock in gapped mode, start signal low | ||
69 | active for first byte */ | ||
70 | {0x0c,0x11}, /* no parity bytes, large hold time, serial data out */ | ||
71 | {0x0d,0x6f}, /* @ RS Sync/Unsync thresholds */ | ||
72 | {0x10,0x40}, /* chip doc is misleading here: write bit 6 as 1 | ||
73 | to avoid starting the BER counter. Reset the | ||
74 | CRC test bit. Finite counting selected */ | ||
75 | {0x15,0xff}, /* @ size of the limited time window for RS BER | ||
76 | estimation. It is <value>*256 RS blocks, this | ||
77 | gives approx. 2.6 sec at 27.5MS/s, rate 3/4 */ | ||
78 | {0x16,0x00}, /* @ enable all RS output ports */ | ||
79 | {0x17,0x04}, /* @ time window allowed for the RS to sync */ | ||
80 | {0x18,0xae}, /* @ allow all standard DVB code rates to be scanned | ||
81 | for automatically */ | ||
82 | /* leave the current code rate and normalization | ||
83 | registers as they are after reset... */ | ||
84 | {0x21,0x10}, /* @ during AutoAcq, search each viterbi setting | ||
85 | only once */ | ||
86 | {0x23,0x18}, /* @ size of the limited time window for Viterbi BER | ||
87 | estimation. It is <value>*65536 channel bits, i.e. | ||
88 | approx. 38ms at 27.5MS/s, rate 3/4 */ | ||
89 | {0x24,0x24}, /* do not trigger Viterbi CRC test. Finite count window */ | ||
90 | /* leave front-end AGC parameters at default values */ | ||
91 | /* leave decimation AGC parameters at default values */ | ||
92 | {0x35,0x40}, /* disable all interrupts. They are not connected anyway */ | ||
93 | {0x36,0xff}, /* clear all interrupt pending flags */ | ||
94 | {0x37,0x00}, /* @ fully enable AutoAcqq state machine */ | ||
95 | {0x38,0x07}, /* @ enable fade recovery, but not autostart AutoAcq */ | ||
96 | /* leave the equalizer parameters on their default values */ | ||
97 | /* leave the final AGC parameters on their default values */ | ||
98 | {0x41,0x00}, /* @ MSB of front-end derotator frequency */ | ||
99 | {0x42,0x00}, /* @ middle bytes " */ | ||
100 | {0x43,0x00}, /* @ LSB " */ | ||
101 | /* leave the carrier tracking loop parameters on default */ | ||
102 | /* leave the bit timing loop parameters at gefault */ | ||
103 | {0x56,0x4d}, /* set the filtune voltage to 2.7V, as recommended by */ | ||
104 | /* the cx24108 data sheet for symbol rates above 15MS/s */ | ||
105 | {0x57,0x00}, /* @ Filter sigma delta enabled, positive */ | ||
106 | {0x61,0x95}, /* GPIO pins 1-4 have special function */ | ||
107 | {0x62,0x05}, /* GPIO pin 5 has special function, pin 6 is GPIO */ | ||
108 | {0x63,0x00}, /* All GPIO pins use CMOS output characteristics */ | ||
109 | {0x64,0x20}, /* GPIO 6 is input, all others are outputs */ | ||
110 | {0x6d,0x30}, /* tuner auto mode clock freq 62kHz */ | ||
111 | {0x70,0x15}, /* use auto mode, tuner word is 21 bits long */ | ||
112 | {0x73,0x00}, /* @ disable several demod bypasses */ | ||
113 | {0x74,0x00}, /* @ " */ | ||
114 | {0x75,0x00} /* @ " */ | ||
115 | /* the remaining registers are for SEC */ | ||
116 | }; | ||
117 | |||
118 | |||
119 | static int cx24110_writereg (struct cx24110_state* state, int reg, int data) | ||
120 | { | ||
121 | u8 buf [] = { reg, data }; | ||
122 | struct i2c_msg msg = { .addr = state->config->demod_address, .flags = 0, .buf = buf, .len = 2 }; | ||
123 | int err; | ||
124 | |||
125 | if ((err = i2c_transfer(state->i2c, &msg, 1)) != 1) { | ||
126 | dprintk ("%s: writereg error (err == %i, reg == 0x%02x," | ||
127 | " data == 0x%02x)\n", __FUNCTION__, err, reg, data); | ||
128 | return -EREMOTEIO; | ||
129 | } | ||
130 | |||
131 | return 0; | ||
132 | } | ||
133 | |||
134 | static int cx24110_readreg (struct cx24110_state* state, u8 reg) | ||
135 | { | ||
136 | int ret; | ||
137 | u8 b0 [] = { reg }; | ||
138 | u8 b1 [] = { 0 }; | ||
139 | struct i2c_msg msg [] = { { .addr = state->config->demod_address, .flags = 0, .buf = b0, .len = 1 }, | ||
140 | { .addr = state->config->demod_address, .flags = I2C_M_RD, .buf = b1, .len = 1 } }; | ||
141 | |||
142 | ret = i2c_transfer(state->i2c, msg, 2); | ||
143 | |||
144 | if (ret != 2) return ret; | ||
145 | |||
146 | return b1[0]; | ||
147 | } | ||
148 | |||
149 | static int cx24110_set_inversion (struct cx24110_state* state, fe_spectral_inversion_t inversion) | ||
150 | { | ||
151 | /* fixme (low): error handling */ | ||
152 | |||
153 | switch (inversion) { | ||
154 | case INVERSION_OFF: | ||
155 | cx24110_writereg(state,0x37,cx24110_readreg(state,0x37)|0x1); | ||
156 | /* AcqSpectrInvDis on. No idea why someone should want this */ | ||
157 | cx24110_writereg(state,0x5,cx24110_readreg(state,0x5)&0xf7); | ||
158 | /* Initial value 0 at start of acq */ | ||
159 | cx24110_writereg(state,0x22,cx24110_readreg(state,0x22)&0xef); | ||
160 | /* current value 0 */ | ||
161 | /* The cx24110 manual tells us this reg is read-only. | ||
162 | But what the heck... set it ayways */ | ||
163 | break; | ||
164 | case INVERSION_ON: | ||
165 | cx24110_writereg(state,0x37,cx24110_readreg(state,0x37)|0x1); | ||
166 | /* AcqSpectrInvDis on. No idea why someone should want this */ | ||
167 | cx24110_writereg(state,0x5,cx24110_readreg(state,0x5)|0x08); | ||
168 | /* Initial value 1 at start of acq */ | ||
169 | cx24110_writereg(state,0x22,cx24110_readreg(state,0x22)|0x10); | ||
170 | /* current value 1 */ | ||
171 | break; | ||
172 | case INVERSION_AUTO: | ||
173 | cx24110_writereg(state,0x37,cx24110_readreg(state,0x37)&0xfe); | ||
174 | /* AcqSpectrInvDis off. Leave initial & current states as is */ | ||
175 | break; | ||
176 | default: | ||
177 | return -EINVAL; | ||
178 | } | ||
179 | |||
180 | return 0; | ||
181 | } | ||
182 | |||
183 | static int cx24110_set_fec (struct cx24110_state* state, fe_code_rate_t fec) | ||
184 | { | ||
185 | /* fixme (low): error handling */ | ||
186 | |||
187 | static const int rate[]={-1,1,2,3,5,7,-1}; | ||
188 | static const int g1[]={-1,0x01,0x02,0x05,0x15,0x45,-1}; | ||
189 | static const int g2[]={-1,0x01,0x03,0x06,0x1a,0x7a,-1}; | ||
190 | |||
191 | /* Well, the AutoAcq engine of the cx24106 and 24110 automatically | ||
192 | searches all enabled viterbi rates, and can handle non-standard | ||
193 | rates as well. */ | ||
194 | |||
195 | if (fec>FEC_AUTO) | ||
196 | fec=FEC_AUTO; | ||
197 | |||
198 | if (fec==FEC_AUTO) { /* (re-)establish AutoAcq behaviour */ | ||
199 | cx24110_writereg(state,0x37,cx24110_readreg(state,0x37)&0xdf); | ||
200 | /* clear AcqVitDis bit */ | ||
201 | cx24110_writereg(state,0x18,0xae); | ||
202 | /* allow all DVB standard code rates */ | ||
203 | cx24110_writereg(state,0x05,(cx24110_readreg(state,0x05)&0xf0)|0x3); | ||
204 | /* set nominal Viterbi rate 3/4 */ | ||
205 | cx24110_writereg(state,0x22,(cx24110_readreg(state,0x22)&0xf0)|0x3); | ||
206 | /* set current Viterbi rate 3/4 */ | ||
207 | cx24110_writereg(state,0x1a,0x05); cx24110_writereg(state,0x1b,0x06); | ||
208 | /* set the puncture registers for code rate 3/4 */ | ||
209 | return 0; | ||
210 | } else { | ||
211 | cx24110_writereg(state,0x37,cx24110_readreg(state,0x37)|0x20); | ||
212 | /* set AcqVitDis bit */ | ||
213 | if(rate[fec]>0) { | ||
214 | cx24110_writereg(state,0x05,(cx24110_readreg(state,0x05)&0xf0)|rate[fec]); | ||
215 | /* set nominal Viterbi rate */ | ||
216 | cx24110_writereg(state,0x22,(cx24110_readreg(state,0x22)&0xf0)|rate[fec]); | ||
217 | /* set current Viterbi rate */ | ||
218 | cx24110_writereg(state,0x1a,g1[fec]); | ||
219 | cx24110_writereg(state,0x1b,g2[fec]); | ||
220 | /* not sure if this is the right way: I always used AutoAcq mode */ | ||
221 | } else | ||
222 | return -EOPNOTSUPP; | ||
223 | /* fixme (low): which is the correct return code? */ | ||
224 | }; | ||
225 | return 0; | ||
226 | } | ||
227 | |||
228 | static fe_code_rate_t cx24110_get_fec (struct cx24110_state* state) | ||
229 | { | ||
230 | int i; | ||
231 | |||
232 | i=cx24110_readreg(state,0x22)&0x0f; | ||
233 | if(!(i&0x08)) { | ||
234 | return FEC_1_2 + i - 1; | ||
235 | } else { | ||
236 | /* fixme (low): a special code rate has been selected. In theory, we need to | ||
237 | return a denominator value, a numerator value, and a pair of puncture | ||
238 | maps to correctly describe this mode. But this should never happen in | ||
239 | practice, because it cannot be set by cx24110_get_fec. */ | ||
240 | return FEC_NONE; | ||
241 | } | ||
242 | } | ||
243 | |||
244 | static int cx24110_set_symbolrate (struct cx24110_state* state, u32 srate) | ||
245 | { | ||
246 | /* fixme (low): add error handling */ | ||
247 | u32 ratio; | ||
248 | u32 tmp, fclk, BDRI; | ||
249 | |||
250 | static const u32 bands[]={5000000UL,15000000UL,90999000UL/2}; | ||
251 | int i; | ||
252 | |||
253 | dprintk("cx24110 debug: entering %s(%d)\n",__FUNCTION__,srate); | ||
254 | if (srate>90999000UL/2) | ||
255 | srate=90999000UL/2; | ||
256 | if (srate<500000) | ||
257 | srate=500000; | ||
258 | |||
259 | for(i=0;(i<sizeof(bands)/sizeof(bands[0]))&&(srate>bands[i]);i++) | ||
260 | ; | ||
261 | /* first, check which sample rate is appropriate: 45, 60 80 or 90 MHz, | ||
262 | and set the PLL accordingly (R07[1:0] Fclk, R06[7:4] PLLmult, | ||
263 | R06[3:0] PLLphaseDetGain */ | ||
264 | tmp=cx24110_readreg(state,0x07)&0xfc; | ||
265 | if(srate<90999000UL/4) { /* sample rate 45MHz*/ | ||
266 | cx24110_writereg(state,0x07,tmp); | ||
267 | cx24110_writereg(state,0x06,0x78); | ||
268 | fclk=90999000UL/2; | ||
269 | } else if(srate<60666000UL/2) { /* sample rate 60MHz */ | ||
270 | cx24110_writereg(state,0x07,tmp|0x1); | ||
271 | cx24110_writereg(state,0x06,0xa5); | ||
272 | fclk=60666000UL; | ||
273 | } else if(srate<80888000UL/2) { /* sample rate 80MHz */ | ||
274 | cx24110_writereg(state,0x07,tmp|0x2); | ||
275 | cx24110_writereg(state,0x06,0x87); | ||
276 | fclk=80888000UL; | ||
277 | } else { /* sample rate 90MHz */ | ||
278 | cx24110_writereg(state,0x07,tmp|0x3); | ||
279 | cx24110_writereg(state,0x06,0x78); | ||
280 | fclk=90999000UL; | ||
281 | }; | ||
282 | dprintk("cx24110 debug: fclk %d Hz\n",fclk); | ||
283 | /* we need to divide two integers with approx. 27 bits in 32 bit | ||
284 | arithmetic giving a 25 bit result */ | ||
285 | /* the maximum dividend is 90999000/2, 0x02b6446c, this number is | ||
286 | also the most complex divisor. Hence, the dividend has, | ||
287 | assuming 32bit unsigned arithmetic, 6 clear bits on top, the | ||
288 | divisor 2 unused bits at the bottom. Also, the quotient is | ||
289 | always less than 1/2. Borrowed from VES1893.c, of course */ | ||
290 | |||
291 | tmp=srate<<6; | ||
292 | BDRI=fclk>>2; | ||
293 | ratio=(tmp/BDRI); | ||
294 | |||
295 | tmp=(tmp%BDRI)<<8; | ||
296 | ratio=(ratio<<8)+(tmp/BDRI); | ||
297 | |||
298 | tmp=(tmp%BDRI)<<8; | ||
299 | ratio=(ratio<<8)+(tmp/BDRI); | ||
300 | |||
301 | tmp=(tmp%BDRI)<<1; | ||
302 | ratio=(ratio<<1)+(tmp/BDRI); | ||
303 | |||
304 | dprintk("srate= %d (range %d, up to %d)\n", srate,i,bands[i]); | ||
305 | dprintk("fclk = %d\n", fclk); | ||
306 | dprintk("ratio= %08x\n", ratio); | ||
307 | |||
308 | cx24110_writereg(state, 0x1, (ratio>>16)&0xff); | ||
309 | cx24110_writereg(state, 0x2, (ratio>>8)&0xff); | ||
310 | cx24110_writereg(state, 0x3, (ratio)&0xff); | ||
311 | |||
312 | return 0; | ||
313 | |||
314 | } | ||
315 | |||
316 | int cx24110_pll_write (struct dvb_frontend* fe, u32 data) | ||
317 | { | ||
318 | struct cx24110_state *state = (struct cx24110_state*) fe->demodulator_priv; | ||
319 | |||
320 | /* tuner data is 21 bits long, must be left-aligned in data */ | ||
321 | /* tuner cx24108 is written through a dedicated 3wire interface on the demod chip */ | ||
322 | /* FIXME (low): add error handling, avoid infinite loops if HW fails... */ | ||
323 | |||
324 | dprintk("cx24110 debug: cx24108_write(%8.8x)\n",data); | ||
325 | |||
326 | cx24110_writereg(state,0x6d,0x30); /* auto mode at 62kHz */ | ||
327 | cx24110_writereg(state,0x70,0x15); /* auto mode 21 bits */ | ||
328 | |||
329 | /* if the auto tuner writer is still busy, clear it out */ | ||
330 | while (cx24110_readreg(state,0x6d)&0x80) | ||
331 | cx24110_writereg(state,0x72,0); | ||
332 | |||
333 | /* write the topmost 8 bits */ | ||
334 | cx24110_writereg(state,0x72,(data>>24)&0xff); | ||
335 | |||
336 | /* wait for the send to be completed */ | ||
337 | while ((cx24110_readreg(state,0x6d)&0xc0)==0x80) | ||
338 | ; | ||
339 | |||
340 | /* send another 8 bytes */ | ||
341 | cx24110_writereg(state,0x72,(data>>16)&0xff); | ||
342 | while ((cx24110_readreg(state,0x6d)&0xc0)==0x80) | ||
343 | ; | ||
344 | |||
345 | /* and the topmost 5 bits of this byte */ | ||
346 | cx24110_writereg(state,0x72,(data>>8)&0xff); | ||
347 | while ((cx24110_readreg(state,0x6d)&0xc0)==0x80) | ||
348 | ; | ||
349 | |||
350 | /* now strobe the enable line once */ | ||
351 | cx24110_writereg(state,0x6d,0x32); | ||
352 | cx24110_writereg(state,0x6d,0x30); | ||
353 | |||
354 | return 0; | ||
355 | } | ||
356 | |||
357 | static int cx24110_initfe(struct dvb_frontend* fe) | ||
358 | { | ||
359 | struct cx24110_state *state = (struct cx24110_state*) fe->demodulator_priv; | ||
360 | /* fixme (low): error handling */ | ||
361 | int i; | ||
362 | |||
363 | dprintk("%s: init chip\n", __FUNCTION__); | ||
364 | |||
365 | for(i=0;i<sizeof(cx24110_regdata)/sizeof(cx24110_regdata[0]);i++) { | ||
366 | cx24110_writereg(state, cx24110_regdata[i].reg, cx24110_regdata[i].data); | ||
367 | }; | ||
368 | |||
369 | if (state->config->pll_init) state->config->pll_init(fe); | ||
370 | |||
371 | return 0; | ||
372 | } | ||
373 | |||
374 | static int cx24110_set_voltage (struct dvb_frontend* fe, fe_sec_voltage_t voltage) | ||
375 | { | ||
376 | struct cx24110_state *state = (struct cx24110_state*) fe->demodulator_priv; | ||
377 | |||
378 | switch (voltage) { | ||
379 | case SEC_VOLTAGE_13: | ||
380 | return cx24110_writereg(state,0x76,(cx24110_readreg(state,0x76)&0x3b)|0xc0); | ||
381 | case SEC_VOLTAGE_18: | ||
382 | return cx24110_writereg(state,0x76,(cx24110_readreg(state,0x76)&0x3b)|0x40); | ||
383 | default: | ||
384 | return -EINVAL; | ||
385 | }; | ||
386 | } | ||
387 | |||
388 | static int cx24110_diseqc_send_burst(struct dvb_frontend* fe, | ||
389 | fe_sec_mini_cmd_t burst) | ||
390 | { | ||
391 | int rv, bit, i; | ||
392 | struct cx24110_state *state = fe->demodulator_priv; | ||
393 | |||
394 | if (burst == SEC_MINI_A) | ||
395 | bit = 0x00; | ||
396 | else if (burst == SEC_MINI_B) | ||
397 | bit = 0x08; | ||
398 | else | ||
399 | return -EINVAL; | ||
400 | |||
401 | rv = cx24110_readreg(state, 0x77); | ||
402 | cx24110_writereg(state, 0x77, rv|0x04); | ||
403 | |||
404 | rv = cx24110_readreg(state, 0x76); | ||
405 | cx24110_writereg(state, 0x76, ((rv & 0x90) | 0x40 | bit)); | ||
406 | for (i = 500; i-- > 0 && !(cx24110_readreg(state,0x76)&0x40) ; ) | ||
407 | ; /* wait for LNB ready */ | ||
408 | |||
409 | return 0; | ||
410 | } | ||
411 | |||
412 | static int cx24110_send_diseqc_msg(struct dvb_frontend* fe, | ||
413 | struct dvb_diseqc_master_cmd *cmd) | ||
414 | { | ||
415 | int i, rv; | ||
416 | struct cx24110_state *state = (struct cx24110_state*) fe->demodulator_priv; | ||
417 | |||
418 | for (i = 0; i < cmd->msg_len; i++) | ||
419 | cx24110_writereg(state, 0x79 + i, cmd->msg[i]); | ||
420 | |||
421 | rv = cx24110_readreg(state, 0x77); | ||
422 | cx24110_writereg(state, 0x77, rv|0x04); | ||
423 | |||
424 | rv = cx24110_readreg(state, 0x76); | ||
425 | |||
426 | cx24110_writereg(state, 0x76, ((rv & 0x90) | 0x40) | ((cmd->msg_len-3) & 3)); | ||
427 | for (i=500; i-- > 0 && !(cx24110_readreg(state,0x76)&0x40);) | ||
428 | ; /* wait for LNB ready */ | ||
429 | |||
430 | return 0; | ||
431 | } | ||
432 | |||
433 | static int cx24110_read_status(struct dvb_frontend* fe, fe_status_t* status) | ||
434 | { | ||
435 | struct cx24110_state *state = (struct cx24110_state*) fe->demodulator_priv; | ||
436 | |||
437 | int sync = cx24110_readreg (state, 0x55); | ||
438 | |||
439 | *status = 0; | ||
440 | |||
441 | if (sync & 0x10) | ||
442 | *status |= FE_HAS_SIGNAL; | ||
443 | |||
444 | if (sync & 0x08) | ||
445 | *status |= FE_HAS_CARRIER; | ||
446 | |||
447 | sync = cx24110_readreg (state, 0x08); | ||
448 | |||
449 | if (sync & 0x40) | ||
450 | *status |= FE_HAS_VITERBI; | ||
451 | |||
452 | if (sync & 0x20) | ||
453 | *status |= FE_HAS_SYNC; | ||
454 | |||
455 | if ((sync & 0x60) == 0x60) | ||
456 | *status |= FE_HAS_LOCK; | ||
457 | |||
458 | return 0; | ||
459 | } | ||
460 | |||
461 | static int cx24110_read_ber(struct dvb_frontend* fe, u32* ber) | ||
462 | { | ||
463 | struct cx24110_state *state = (struct cx24110_state*) fe->demodulator_priv; | ||
464 | |||
465 | /* fixme (maybe): value range is 16 bit. Scale? */ | ||
466 | if(cx24110_readreg(state,0x24)&0x10) { | ||
467 | /* the Viterbi error counter has finished one counting window */ | ||
468 | cx24110_writereg(state,0x24,0x04); /* select the ber reg */ | ||
469 | state->lastber=cx24110_readreg(state,0x25)| | ||
470 | (cx24110_readreg(state,0x26)<<8); | ||
471 | cx24110_writereg(state,0x24,0x04); /* start new count window */ | ||
472 | cx24110_writereg(state,0x24,0x14); | ||
473 | } | ||
474 | *ber = state->lastber; | ||
475 | |||
476 | return 0; | ||
477 | } | ||
478 | |||
479 | static int cx24110_read_signal_strength(struct dvb_frontend* fe, u16* signal_strength) | ||
480 | { | ||
481 | struct cx24110_state *state = (struct cx24110_state*) fe->demodulator_priv; | ||
482 | |||
483 | /* no provision in hardware. Read the frontend AGC accumulator. No idea how to scale this, but I know it is 2s complement */ | ||
484 | u8 signal = cx24110_readreg (state, 0x27)+128; | ||
485 | *signal_strength = (signal << 8) | signal; | ||
486 | |||
487 | return 0; | ||
488 | } | ||
489 | |||
490 | static int cx24110_read_snr(struct dvb_frontend* fe, u16* snr) | ||
491 | { | ||
492 | struct cx24110_state *state = (struct cx24110_state*) fe->demodulator_priv; | ||
493 | |||
494 | /* no provision in hardware. Can be computed from the Es/N0 estimator, but I don't know how. */ | ||
495 | if(cx24110_readreg(state,0x6a)&0x80) { | ||
496 | /* the Es/N0 error counter has finished one counting window */ | ||
497 | state->lastesn0=cx24110_readreg(state,0x69)| | ||
498 | (cx24110_readreg(state,0x68)<<8); | ||
499 | cx24110_writereg(state,0x6a,0x84); /* start new count window */ | ||
500 | } | ||
501 | *snr = state->lastesn0; | ||
502 | |||
503 | return 0; | ||
504 | } | ||
505 | |||
506 | static int cx24110_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks) | ||
507 | { | ||
508 | struct cx24110_state *state = (struct cx24110_state*) fe->demodulator_priv; | ||
509 | u32 lastbyer; | ||
510 | |||
511 | if(cx24110_readreg(state,0x10)&0x40) { | ||
512 | /* the RS error counter has finished one counting window */ | ||
513 | cx24110_writereg(state,0x10,0x60); /* select the byer reg */ | ||
514 | lastbyer=cx24110_readreg(state,0x12)| | ||
515 | (cx24110_readreg(state,0x13)<<8)| | ||
516 | (cx24110_readreg(state,0x14)<<16); | ||
517 | cx24110_writereg(state,0x10,0x70); /* select the bler reg */ | ||
518 | state->lastbler=cx24110_readreg(state,0x12)| | ||
519 | (cx24110_readreg(state,0x13)<<8)| | ||
520 | (cx24110_readreg(state,0x14)<<16); | ||
521 | cx24110_writereg(state,0x10,0x20); /* start new count window */ | ||
522 | } | ||
523 | *ucblocks = state->lastbler; | ||
524 | |||
525 | return 0; | ||
526 | } | ||
527 | |||
528 | static int cx24110_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p) | ||
529 | { | ||
530 | struct cx24110_state *state = (struct cx24110_state*) fe->demodulator_priv; | ||
531 | |||
532 | state->config->pll_set(fe, p); | ||
533 | cx24110_set_inversion (state, p->inversion); | ||
534 | cx24110_set_fec (state, p->u.qpsk.fec_inner); | ||
535 | cx24110_set_symbolrate (state, p->u.qpsk.symbol_rate); | ||
536 | cx24110_writereg(state,0x04,0x05); /* start aquisition */ | ||
537 | |||
538 | return 0; | ||
539 | } | ||
540 | |||
541 | static int cx24110_get_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p) | ||
542 | { | ||
543 | struct cx24110_state *state = (struct cx24110_state*) fe->demodulator_priv; | ||
544 | s32 afc; unsigned sclk; | ||
545 | |||
546 | /* cannot read back tuner settings (freq). Need to have some private storage */ | ||
547 | |||
548 | sclk = cx24110_readreg (state, 0x07) & 0x03; | ||
549 | /* ok, real AFC (FEDR) freq. is afc/2^24*fsamp, fsamp=45/60/80/90MHz. | ||
550 | * Need 64 bit arithmetic. Is thiss possible in the kernel? */ | ||
551 | if (sclk==0) sclk=90999000L/2L; | ||
552 | else if (sclk==1) sclk=60666000L; | ||
553 | else if (sclk==2) sclk=80888000L; | ||
554 | else sclk=90999000L; | ||
555 | sclk>>=8; | ||
556 | afc = sclk*(cx24110_readreg (state, 0x44)&0x1f)+ | ||
557 | ((sclk*cx24110_readreg (state, 0x45))>>8)+ | ||
558 | ((sclk*cx24110_readreg (state, 0x46))>>16); | ||
559 | |||
560 | p->frequency += afc; | ||
561 | p->inversion = (cx24110_readreg (state, 0x22) & 0x10) ? | ||
562 | INVERSION_ON : INVERSION_OFF; | ||
563 | p->u.qpsk.fec_inner = cx24110_get_fec (state); | ||
564 | |||
565 | return 0; | ||
566 | } | ||
567 | |||
568 | static int cx24110_set_tone(struct dvb_frontend* fe, fe_sec_tone_mode_t tone) | ||
569 | { | ||
570 | struct cx24110_state *state = (struct cx24110_state*) fe->demodulator_priv; | ||
571 | |||
572 | return cx24110_writereg(state,0x76,(cx24110_readreg(state,0x76)&~0x10)|(((tone==SEC_TONE_ON))?0x10:0)); | ||
573 | } | ||
574 | |||
575 | static void cx24110_release(struct dvb_frontend* fe) | ||
576 | { | ||
577 | struct cx24110_state* state = (struct cx24110_state*) fe->demodulator_priv; | ||
578 | kfree(state); | ||
579 | } | ||
580 | |||
581 | static struct dvb_frontend_ops cx24110_ops; | ||
582 | |||
583 | struct dvb_frontend* cx24110_attach(const struct cx24110_config* config, | ||
584 | struct i2c_adapter* i2c) | ||
585 | { | ||
586 | struct cx24110_state* state = NULL; | ||
587 | int ret; | ||
588 | |||
589 | /* allocate memory for the internal state */ | ||
590 | state = (struct cx24110_state*) kmalloc(sizeof(struct cx24110_state), GFP_KERNEL); | ||
591 | if (state == NULL) goto error; | ||
592 | |||
593 | /* setup the state */ | ||
594 | state->config = config; | ||
595 | state->i2c = i2c; | ||
596 | memcpy(&state->ops, &cx24110_ops, sizeof(struct dvb_frontend_ops)); | ||
597 | state->lastber = 0; | ||
598 | state->lastbler = 0; | ||
599 | state->lastesn0 = 0; | ||
600 | |||
601 | /* check if the demod is there */ | ||
602 | ret = cx24110_readreg(state, 0x00); | ||
603 | if ((ret != 0x5a) && (ret != 0x69)) goto error; | ||
604 | |||
605 | /* create dvb_frontend */ | ||
606 | state->frontend.ops = &state->ops; | ||
607 | state->frontend.demodulator_priv = state; | ||
608 | return &state->frontend; | ||
609 | |||
610 | error: | ||
611 | kfree(state); | ||
612 | return NULL; | ||
613 | } | ||
614 | |||
615 | static struct dvb_frontend_ops cx24110_ops = { | ||
616 | |||
617 | .info = { | ||
618 | .name = "Conexant CX24110 DVB-S", | ||
619 | .type = FE_QPSK, | ||
620 | .frequency_min = 950000, | ||
621 | .frequency_max = 2150000, | ||
622 | .frequency_stepsize = 1011, /* kHz for QPSK frontends */ | ||
623 | .frequency_tolerance = 29500, | ||
624 | .symbol_rate_min = 1000000, | ||
625 | .symbol_rate_max = 45000000, | ||
626 | .caps = FE_CAN_INVERSION_AUTO | | ||
627 | FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | | ||
628 | FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO | | ||
629 | FE_CAN_QPSK | FE_CAN_RECOVER | ||
630 | }, | ||
631 | |||
632 | .release = cx24110_release, | ||
633 | |||
634 | .init = cx24110_initfe, | ||
635 | .set_frontend = cx24110_set_frontend, | ||
636 | .get_frontend = cx24110_get_frontend, | ||
637 | .read_status = cx24110_read_status, | ||
638 | .read_ber = cx24110_read_ber, | ||
639 | .read_signal_strength = cx24110_read_signal_strength, | ||
640 | .read_snr = cx24110_read_snr, | ||
641 | .read_ucblocks = cx24110_read_ucblocks, | ||
642 | |||
643 | .diseqc_send_master_cmd = cx24110_send_diseqc_msg, | ||
644 | .set_tone = cx24110_set_tone, | ||
645 | .set_voltage = cx24110_set_voltage, | ||
646 | .diseqc_send_burst = cx24110_diseqc_send_burst, | ||
647 | }; | ||
648 | |||
649 | module_param(debug, int, 0644); | ||
650 | MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off)."); | ||
651 | |||
652 | MODULE_DESCRIPTION("Conexant CX24110 DVB-S Demodulator driver"); | ||
653 | MODULE_AUTHOR("Peter Hettkamp"); | ||
654 | MODULE_LICENSE("GPL"); | ||
655 | |||
656 | EXPORT_SYMBOL(cx24110_attach); | ||
657 | EXPORT_SYMBOL(cx24110_pll_write); | ||
diff --git a/drivers/media/dvb/frontends/cx24110.h b/drivers/media/dvb/frontends/cx24110.h new file mode 100644 index 000000000000..6b663f4744e0 --- /dev/null +++ b/drivers/media/dvb/frontends/cx24110.h | |||
@@ -0,0 +1,45 @@ | |||
1 | /* | ||
2 | cx24110 - Single Chip Satellite Channel Receiver driver module | ||
3 | |||
4 | Copyright (C) 2002 Peter Hettkamp <peter.hettkamp@t-online.de> based on | ||
5 | work | ||
6 | Copyright (C) 1999 Convergence Integrated Media GmbH <ralph@convergence.de> | ||
7 | |||
8 | This program is free software; you can redistribute it and/or modify | ||
9 | it under the terms of the GNU General Public License as published by | ||
10 | the Free Software Foundation; either version 2 of the License, or | ||
11 | (at your option) any later version. | ||
12 | |||
13 | This program is distributed in the hope that it will be useful, | ||
14 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
16 | |||
17 | GNU General Public License for more details. | ||
18 | |||
19 | You should have received a copy of the GNU General Public License | ||
20 | along with this program; if not, write to the Free Software | ||
21 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
22 | |||
23 | */ | ||
24 | |||
25 | #ifndef CX24110_H | ||
26 | #define CX24110_H | ||
27 | |||
28 | #include <linux/dvb/frontend.h> | ||
29 | |||
30 | struct cx24110_config | ||
31 | { | ||
32 | /* the demodulator's i2c address */ | ||
33 | u8 demod_address; | ||
34 | |||
35 | /* PLL maintenance */ | ||
36 | int (*pll_init)(struct dvb_frontend* fe); | ||
37 | int (*pll_set)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params); | ||
38 | }; | ||
39 | |||
40 | extern struct dvb_frontend* cx24110_attach(const struct cx24110_config* config, | ||
41 | struct i2c_adapter* i2c); | ||
42 | |||
43 | extern int cx24110_pll_write(struct dvb_frontend* fe, u32 data); | ||
44 | |||
45 | #endif // CX24110_H | ||
diff --git a/drivers/media/dvb/frontends/dib3000-common.c b/drivers/media/dvb/frontends/dib3000-common.c new file mode 100644 index 000000000000..47ab02e133d1 --- /dev/null +++ b/drivers/media/dvb/frontends/dib3000-common.c | |||
@@ -0,0 +1,83 @@ | |||
1 | #include "dib3000-common.h" | ||
2 | |||
3 | #ifdef CONFIG_DVB_DIBCOM_DEBUG | ||
4 | static int debug; | ||
5 | module_param(debug, int, 0644); | ||
6 | MODULE_PARM_DESC(debug, "set debugging level (1=info,2=i2c,4=srch (|-able))."); | ||
7 | #endif | ||
8 | #define deb_info(args...) dprintk(0x01,args) | ||
9 | #define deb_i2c(args...) dprintk(0x02,args) | ||
10 | #define deb_srch(args...) dprintk(0x04,args) | ||
11 | |||
12 | |||
13 | int dib3000_read_reg(struct dib3000_state *state, u16 reg) | ||
14 | { | ||
15 | u8 wb[] = { ((reg >> 8) | 0x80) & 0xff, reg & 0xff }; | ||
16 | u8 rb[2]; | ||
17 | struct i2c_msg msg[] = { | ||
18 | { .addr = state->config.demod_address, .flags = 0, .buf = wb, .len = 2 }, | ||
19 | { .addr = state->config.demod_address, .flags = I2C_M_RD, .buf = rb, .len = 2 }, | ||
20 | }; | ||
21 | |||
22 | if (i2c_transfer(state->i2c, msg, 2) != 2) | ||
23 | deb_i2c("i2c read error\n"); | ||
24 | |||
25 | deb_i2c("reading i2c bus (reg: %5d 0x%04x, val: %5d 0x%04x)\n",reg,reg, | ||
26 | (rb[0] << 8) | rb[1],(rb[0] << 8) | rb[1]); | ||
27 | |||
28 | return (rb[0] << 8) | rb[1]; | ||
29 | } | ||
30 | |||
31 | int dib3000_write_reg(struct dib3000_state *state, u16 reg, u16 val) | ||
32 | { | ||
33 | u8 b[] = { | ||
34 | (reg >> 8) & 0xff, reg & 0xff, | ||
35 | (val >> 8) & 0xff, val & 0xff, | ||
36 | }; | ||
37 | struct i2c_msg msg[] = { | ||
38 | { .addr = state->config.demod_address, .flags = 0, .buf = b, .len = 4 } | ||
39 | }; | ||
40 | deb_i2c("writing i2c bus (reg: %5d 0x%04x, val: %5d 0x%04x)\n",reg,reg,val,val); | ||
41 | |||
42 | return i2c_transfer(state->i2c,msg, 1) != 1 ? -EREMOTEIO : 0; | ||
43 | } | ||
44 | |||
45 | int dib3000_search_status(u16 irq,u16 lock) | ||
46 | { | ||
47 | if (irq & 0x02) { | ||
48 | if (lock & 0x01) { | ||
49 | deb_srch("auto search succeeded\n"); | ||
50 | return 1; // auto search succeeded | ||
51 | } else { | ||
52 | deb_srch("auto search not successful\n"); | ||
53 | return 0; // auto search failed | ||
54 | } | ||
55 | } else if (irq & 0x01) { | ||
56 | deb_srch("auto search failed\n"); | ||
57 | return 0; // auto search failed | ||
58 | } | ||
59 | return -1; // try again | ||
60 | } | ||
61 | |||
62 | /* for auto search */ | ||
63 | u16 dib3000_seq[2][2][2] = /* fft,gua, inv */ | ||
64 | { /* fft */ | ||
65 | { /* gua */ | ||
66 | { 0, 1 }, /* 0 0 { 0,1 } */ | ||
67 | { 3, 9 }, /* 0 1 { 0,1 } */ | ||
68 | }, | ||
69 | { | ||
70 | { 2, 5 }, /* 1 0 { 0,1 } */ | ||
71 | { 6, 11 }, /* 1 1 { 0,1 } */ | ||
72 | } | ||
73 | }; | ||
74 | |||
75 | MODULE_AUTHOR("Patrick Boettcher <patrick.boettcher@desy.de"); | ||
76 | MODULE_DESCRIPTION("Common functions for the dib3000mb/dib3000mc dvb-frontend drivers"); | ||
77 | MODULE_LICENSE("GPL"); | ||
78 | |||
79 | EXPORT_SYMBOL(dib3000_seq); | ||
80 | |||
81 | EXPORT_SYMBOL(dib3000_read_reg); | ||
82 | EXPORT_SYMBOL(dib3000_write_reg); | ||
83 | EXPORT_SYMBOL(dib3000_search_status); | ||
diff --git a/drivers/media/dvb/frontends/dib3000-common.h b/drivers/media/dvb/frontends/dib3000-common.h new file mode 100644 index 000000000000..c31d6df15472 --- /dev/null +++ b/drivers/media/dvb/frontends/dib3000-common.h | |||
@@ -0,0 +1,137 @@ | |||
1 | /* | ||
2 | * .h-files for the common use of the frontend drivers made by DiBcom | ||
3 | * DiBcom 3000M-B/C, 3000P | ||
4 | * | ||
5 | * DiBcom (http://www.dibcom.fr/) | ||
6 | * | ||
7 | * Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de) | ||
8 | * | ||
9 | * based on GPL code from DibCom, which has | ||
10 | * | ||
11 | * Copyright (C) 2004 Amaury Demol for DiBcom (ademol@dibcom.fr) | ||
12 | * | ||
13 | * This program is free software; you can redistribute it and/or | ||
14 | * modify it under the terms of the GNU General Public License as | ||
15 | * published by the Free Software Foundation, version 2. | ||
16 | * | ||
17 | * Acknowledgements | ||
18 | * | ||
19 | * Amaury Demol (ademol@dibcom.fr) from DiBcom for providing specs and driver | ||
20 | * sources, on which this driver (and the dvb-dibusb) are based. | ||
21 | * | ||
22 | * see Documentation/dvb/README.dibusb for more information | ||
23 | * | ||
24 | */ | ||
25 | |||
26 | #ifndef DIB3000_COMMON_H | ||
27 | #define DIB3000_COMMON_H | ||
28 | |||
29 | #include "dvb_frontend.h" | ||
30 | #include "dib3000.h" | ||
31 | |||
32 | /* info and err, taken from usb.h, if there is anything available like by default. */ | ||
33 | #define err(format, arg...) printk(KERN_ERR "dib3000: " format "\n" , ## arg) | ||
34 | #define info(format, arg...) printk(KERN_INFO "dib3000: " format "\n" , ## arg) | ||
35 | #define warn(format, arg...) printk(KERN_WARNING "dib3000: " format "\n" , ## arg) | ||
36 | |||
37 | /* frontend state */ | ||
38 | struct dib3000_state { | ||
39 | struct i2c_adapter* i2c; | ||
40 | |||
41 | struct dvb_frontend_ops ops; | ||
42 | |||
43 | /* configuration settings */ | ||
44 | struct dib3000_config config; | ||
45 | |||
46 | struct dvb_frontend frontend; | ||
47 | int timing_offset; | ||
48 | int timing_offset_comp_done; | ||
49 | |||
50 | fe_bandwidth_t last_tuned_bw; | ||
51 | u32 last_tuned_freq; | ||
52 | }; | ||
53 | |||
54 | /* commonly used methods by the dib3000mb/mc/p frontend */ | ||
55 | extern int dib3000_read_reg(struct dib3000_state *state, u16 reg); | ||
56 | extern int dib3000_write_reg(struct dib3000_state *state, u16 reg, u16 val); | ||
57 | |||
58 | extern int dib3000_search_status(u16 irq,u16 lock); | ||
59 | |||
60 | /* handy shortcuts */ | ||
61 | #define rd(reg) dib3000_read_reg(state,reg) | ||
62 | |||
63 | #define wr(reg,val) if (dib3000_write_reg(state,reg,val)) \ | ||
64 | { err("while sending 0x%04x to 0x%04x.",val,reg); return -EREMOTEIO; } | ||
65 | |||
66 | #define wr_foreach(a,v) { int i; \ | ||
67 | if (sizeof(a) != sizeof(v)) \ | ||
68 | err("sizeof: %zu %zu is different",sizeof(a),sizeof(v));\ | ||
69 | for (i=0; i < sizeof(a)/sizeof(u16); i++) \ | ||
70 | wr(a[i],v[i]); \ | ||
71 | } | ||
72 | |||
73 | #define set_or(reg,val) wr(reg,rd(reg) | val) | ||
74 | |||
75 | #define set_and(reg,val) wr(reg,rd(reg) & val) | ||
76 | |||
77 | |||
78 | /* debug */ | ||
79 | |||
80 | #ifdef CONFIG_DVB_DIBCOM_DEBUG | ||
81 | #define dprintk(level,args...) \ | ||
82 | do { if ((debug & level)) { printk(args); } } while (0) | ||
83 | #else | ||
84 | #define dprintk(args...) do { } while (0) | ||
85 | #endif | ||
86 | |||
87 | /* mask for enabling a specific pid for the pid_filter */ | ||
88 | #define DIB3000_ACTIVATE_PID_FILTERING (0x2000) | ||
89 | |||
90 | /* common values for tuning */ | ||
91 | #define DIB3000_ALPHA_0 ( 0) | ||
92 | #define DIB3000_ALPHA_1 ( 1) | ||
93 | #define DIB3000_ALPHA_2 ( 2) | ||
94 | #define DIB3000_ALPHA_4 ( 4) | ||
95 | |||
96 | #define DIB3000_CONSTELLATION_QPSK ( 0) | ||
97 | #define DIB3000_CONSTELLATION_16QAM ( 1) | ||
98 | #define DIB3000_CONSTELLATION_64QAM ( 2) | ||
99 | |||
100 | #define DIB3000_GUARD_TIME_1_32 ( 0) | ||
101 | #define DIB3000_GUARD_TIME_1_16 ( 1) | ||
102 | #define DIB3000_GUARD_TIME_1_8 ( 2) | ||
103 | #define DIB3000_GUARD_TIME_1_4 ( 3) | ||
104 | |||
105 | #define DIB3000_TRANSMISSION_MODE_2K ( 0) | ||
106 | #define DIB3000_TRANSMISSION_MODE_8K ( 1) | ||
107 | |||
108 | #define DIB3000_SELECT_LP ( 0) | ||
109 | #define DIB3000_SELECT_HP ( 1) | ||
110 | |||
111 | #define DIB3000_FEC_1_2 ( 1) | ||
112 | #define DIB3000_FEC_2_3 ( 2) | ||
113 | #define DIB3000_FEC_3_4 ( 3) | ||
114 | #define DIB3000_FEC_5_6 ( 5) | ||
115 | #define DIB3000_FEC_7_8 ( 7) | ||
116 | |||
117 | #define DIB3000_HRCH_OFF ( 0) | ||
118 | #define DIB3000_HRCH_ON ( 1) | ||
119 | |||
120 | #define DIB3000_DDS_INVERSION_OFF ( 0) | ||
121 | #define DIB3000_DDS_INVERSION_ON ( 1) | ||
122 | |||
123 | #define DIB3000_TUNER_WRITE_ENABLE(a) (0xffff & (a << 8)) | ||
124 | #define DIB3000_TUNER_WRITE_DISABLE(a) (0xffff & ((a << 8) | (1 << 7))) | ||
125 | |||
126 | /* for auto search */ | ||
127 | extern u16 dib3000_seq[2][2][2]; | ||
128 | |||
129 | #define DIB3000_REG_MANUFACTOR_ID ( 1025) | ||
130 | #define DIB3000_I2C_ID_DIBCOM (0x01b3) | ||
131 | |||
132 | #define DIB3000_REG_DEVICE_ID ( 1026) | ||
133 | #define DIB3000MB_DEVICE_ID (0x3000) | ||
134 | #define DIB3000MC_DEVICE_ID (0x3001) | ||
135 | #define DIB3000P_DEVICE_ID (0x3002) | ||
136 | |||
137 | #endif // DIB3000_COMMON_H | ||
diff --git a/drivers/media/dvb/frontends/dib3000.h b/drivers/media/dvb/frontends/dib3000.h new file mode 100644 index 000000000000..80687c130836 --- /dev/null +++ b/drivers/media/dvb/frontends/dib3000.h | |||
@@ -0,0 +1,54 @@ | |||
1 | /* | ||
2 | * public header file of the frontend drivers for mobile DVB-T demodulators | ||
3 | * DiBcom 3000M-B and DiBcom 3000P/M-C (http://www.dibcom.fr/) | ||
4 | * | ||
5 | * Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de) | ||
6 | * | ||
7 | * based on GPL code from DibCom, which has | ||
8 | * | ||
9 | * Copyright (C) 2004 Amaury Demol for DiBcom (ademol@dibcom.fr) | ||
10 | * | ||
11 | * This program is free software; you can redistribute it and/or | ||
12 | * modify it under the terms of the GNU General Public License as | ||
13 | * published by the Free Software Foundation, version 2. | ||
14 | * | ||
15 | * Acknowledgements | ||
16 | * | ||
17 | * Amaury Demol (ademol@dibcom.fr) from DiBcom for providing specs and driver | ||
18 | * sources, on which this driver (and the dvb-dibusb) are based. | ||
19 | * | ||
20 | * see Documentation/dvb/README.dibusb for more information | ||
21 | * | ||
22 | */ | ||
23 | |||
24 | #ifndef DIB3000_H | ||
25 | #define DIB3000_H | ||
26 | |||
27 | #include <linux/dvb/frontend.h> | ||
28 | |||
29 | struct dib3000_config | ||
30 | { | ||
31 | /* the demodulator's i2c address */ | ||
32 | u8 demod_address; | ||
33 | |||
34 | /* PLL maintenance and the i2c address of the PLL */ | ||
35 | u8 (*pll_addr)(struct dvb_frontend *fe); | ||
36 | int (*pll_init)(struct dvb_frontend *fe, u8 pll_buf[5]); | ||
37 | int (*pll_set)(struct dvb_frontend *fe, struct dvb_frontend_parameters* params, u8 pll_buf[5]); | ||
38 | }; | ||
39 | |||
40 | struct dib_fe_xfer_ops | ||
41 | { | ||
42 | /* pid and transfer handling is done in the demodulator */ | ||
43 | int (*pid_parse)(struct dvb_frontend *fe, int onoff); | ||
44 | int (*fifo_ctrl)(struct dvb_frontend *fe, int onoff); | ||
45 | int (*pid_ctrl)(struct dvb_frontend *fe, int index, int pid, int onoff); | ||
46 | int (*tuner_pass_ctrl)(struct dvb_frontend *fe, int onoff, u8 pll_ctrl); | ||
47 | }; | ||
48 | |||
49 | extern struct dvb_frontend* dib3000mb_attach(const struct dib3000_config* config, | ||
50 | struct i2c_adapter* i2c, struct dib_fe_xfer_ops *xfer_ops); | ||
51 | |||
52 | extern struct dvb_frontend* dib3000mc_attach(const struct dib3000_config* config, | ||
53 | struct i2c_adapter* i2c, struct dib_fe_xfer_ops *xfer_ops); | ||
54 | #endif // DIB3000_H | ||
diff --git a/drivers/media/dvb/frontends/dib3000mb.c b/drivers/media/dvb/frontends/dib3000mb.c new file mode 100644 index 000000000000..a853d12a26f1 --- /dev/null +++ b/drivers/media/dvb/frontends/dib3000mb.c | |||
@@ -0,0 +1,784 @@ | |||
1 | /* | ||
2 | * Frontend driver for mobile DVB-T demodulator DiBcom 3000M-B | ||
3 | * DiBcom (http://www.dibcom.fr/) | ||
4 | * | ||
5 | * Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de) | ||
6 | * | ||
7 | * based on GPL code from DibCom, which has | ||
8 | * | ||
9 | * Copyright (C) 2004 Amaury Demol for DiBcom (ademol@dibcom.fr) | ||
10 | * | ||
11 | * This program is free software; you can redistribute it and/or | ||
12 | * modify it under the terms of the GNU General Public License as | ||
13 | * published by the Free Software Foundation, version 2. | ||
14 | * | ||
15 | * Acknowledgements | ||
16 | * | ||
17 | * Amaury Demol (ademol@dibcom.fr) from DiBcom for providing specs and driver | ||
18 | * sources, on which this driver (and the dvb-dibusb) are based. | ||
19 | * | ||
20 | * see Documentation/dvb/README.dibusb for more information | ||
21 | * | ||
22 | */ | ||
23 | |||
24 | #include <linux/config.h> | ||
25 | #include <linux/kernel.h> | ||
26 | #include <linux/version.h> | ||
27 | #include <linux/module.h> | ||
28 | #include <linux/moduleparam.h> | ||
29 | #include <linux/init.h> | ||
30 | #include <linux/delay.h> | ||
31 | |||
32 | #include "dib3000-common.h" | ||
33 | #include "dib3000mb_priv.h" | ||
34 | #include "dib3000.h" | ||
35 | |||
36 | /* Version information */ | ||
37 | #define DRIVER_VERSION "0.1" | ||
38 | #define DRIVER_DESC "DiBcom 3000M-B DVB-T demodulator" | ||
39 | #define DRIVER_AUTHOR "Patrick Boettcher, patrick.boettcher@desy.de" | ||
40 | |||
41 | #ifdef CONFIG_DVB_DIBCOM_DEBUG | ||
42 | static int debug; | ||
43 | module_param(debug, int, 0644); | ||
44 | MODULE_PARM_DESC(debug, "set debugging level (1=info,2=xfer,4=setfe,8=getfe (|-able))."); | ||
45 | #endif | ||
46 | #define deb_info(args...) dprintk(0x01,args) | ||
47 | #define deb_xfer(args...) dprintk(0x02,args) | ||
48 | #define deb_setf(args...) dprintk(0x04,args) | ||
49 | #define deb_getf(args...) dprintk(0x08,args) | ||
50 | |||
51 | static int dib3000mb_tuner_pass_ctrl(struct dvb_frontend *fe, int onoff, u8 pll_addr); | ||
52 | |||
53 | static int dib3000mb_get_frontend(struct dvb_frontend* fe, | ||
54 | struct dvb_frontend_parameters *fep); | ||
55 | |||
56 | static int dib3000mb_set_frontend(struct dvb_frontend* fe, | ||
57 | struct dvb_frontend_parameters *fep, int tuner) | ||
58 | { | ||
59 | struct dib3000_state* state = (struct dib3000_state*) fe->demodulator_priv; | ||
60 | struct dvb_ofdm_parameters *ofdm = &fep->u.ofdm; | ||
61 | fe_code_rate_t fe_cr = FEC_NONE; | ||
62 | int search_state, seq; | ||
63 | |||
64 | if (tuner) { | ||
65 | dib3000mb_tuner_pass_ctrl(fe,1,state->config.pll_addr(fe)); | ||
66 | state->config.pll_set(fe, fep, NULL); | ||
67 | dib3000mb_tuner_pass_ctrl(fe,0,state->config.pll_addr(fe)); | ||
68 | |||
69 | deb_setf("bandwidth: "); | ||
70 | switch (ofdm->bandwidth) { | ||
71 | case BANDWIDTH_8_MHZ: | ||
72 | deb_setf("8 MHz\n"); | ||
73 | wr_foreach(dib3000mb_reg_timing_freq, dib3000mb_timing_freq[2]); | ||
74 | wr_foreach(dib3000mb_reg_bandwidth, dib3000mb_bandwidth_8mhz); | ||
75 | break; | ||
76 | case BANDWIDTH_7_MHZ: | ||
77 | deb_setf("7 MHz\n"); | ||
78 | wr_foreach(dib3000mb_reg_timing_freq, dib3000mb_timing_freq[1]); | ||
79 | wr_foreach(dib3000mb_reg_bandwidth, dib3000mb_bandwidth_7mhz); | ||
80 | break; | ||
81 | case BANDWIDTH_6_MHZ: | ||
82 | deb_setf("6 MHz\n"); | ||
83 | wr_foreach(dib3000mb_reg_timing_freq, dib3000mb_timing_freq[0]); | ||
84 | wr_foreach(dib3000mb_reg_bandwidth, dib3000mb_bandwidth_6mhz); | ||
85 | break; | ||
86 | case BANDWIDTH_AUTO: | ||
87 | return -EOPNOTSUPP; | ||
88 | default: | ||
89 | err("unkown bandwidth value."); | ||
90 | return -EINVAL; | ||
91 | } | ||
92 | } | ||
93 | wr(DIB3000MB_REG_LOCK1_MASK, DIB3000MB_LOCK1_SEARCH_4); | ||
94 | |||
95 | deb_setf("transmission mode: "); | ||
96 | switch (ofdm->transmission_mode) { | ||
97 | case TRANSMISSION_MODE_2K: | ||
98 | deb_setf("2k\n"); | ||
99 | wr(DIB3000MB_REG_FFT, DIB3000_TRANSMISSION_MODE_2K); | ||
100 | break; | ||
101 | case TRANSMISSION_MODE_8K: | ||
102 | deb_setf("8k\n"); | ||
103 | wr(DIB3000MB_REG_FFT, DIB3000_TRANSMISSION_MODE_8K); | ||
104 | break; | ||
105 | case TRANSMISSION_MODE_AUTO: | ||
106 | deb_setf("auto\n"); | ||
107 | break; | ||
108 | default: | ||
109 | return -EINVAL; | ||
110 | } | ||
111 | |||
112 | deb_setf("guard: "); | ||
113 | switch (ofdm->guard_interval) { | ||
114 | case GUARD_INTERVAL_1_32: | ||
115 | deb_setf("1_32\n"); | ||
116 | wr(DIB3000MB_REG_GUARD_TIME, DIB3000_GUARD_TIME_1_32); | ||
117 | break; | ||
118 | case GUARD_INTERVAL_1_16: | ||
119 | deb_setf("1_16\n"); | ||
120 | wr(DIB3000MB_REG_GUARD_TIME, DIB3000_GUARD_TIME_1_16); | ||
121 | break; | ||
122 | case GUARD_INTERVAL_1_8: | ||
123 | deb_setf("1_8\n"); | ||
124 | wr(DIB3000MB_REG_GUARD_TIME, DIB3000_GUARD_TIME_1_8); | ||
125 | break; | ||
126 | case GUARD_INTERVAL_1_4: | ||
127 | deb_setf("1_4\n"); | ||
128 | wr(DIB3000MB_REG_GUARD_TIME, DIB3000_GUARD_TIME_1_4); | ||
129 | break; | ||
130 | case GUARD_INTERVAL_AUTO: | ||
131 | deb_setf("auto\n"); | ||
132 | break; | ||
133 | default: | ||
134 | return -EINVAL; | ||
135 | } | ||
136 | |||
137 | deb_setf("inversion: "); | ||
138 | switch (fep->inversion) { | ||
139 | case INVERSION_OFF: | ||
140 | deb_setf("off\n"); | ||
141 | wr(DIB3000MB_REG_DDS_INV, DIB3000_DDS_INVERSION_OFF); | ||
142 | break; | ||
143 | case INVERSION_AUTO: | ||
144 | deb_setf("auto "); | ||
145 | break; | ||
146 | case INVERSION_ON: | ||
147 | deb_setf("on\n"); | ||
148 | wr(DIB3000MB_REG_DDS_INV, DIB3000_DDS_INVERSION_ON); | ||
149 | break; | ||
150 | default: | ||
151 | return -EINVAL; | ||
152 | } | ||
153 | |||
154 | deb_setf("constellation: "); | ||
155 | switch (ofdm->constellation) { | ||
156 | case QPSK: | ||
157 | deb_setf("qpsk\n"); | ||
158 | wr(DIB3000MB_REG_QAM, DIB3000_CONSTELLATION_QPSK); | ||
159 | break; | ||
160 | case QAM_16: | ||
161 | deb_setf("qam16\n"); | ||
162 | wr(DIB3000MB_REG_QAM, DIB3000_CONSTELLATION_16QAM); | ||
163 | break; | ||
164 | case QAM_64: | ||
165 | deb_setf("qam64\n"); | ||
166 | wr(DIB3000MB_REG_QAM, DIB3000_CONSTELLATION_64QAM); | ||
167 | break; | ||
168 | case QAM_AUTO: | ||
169 | break; | ||
170 | default: | ||
171 | return -EINVAL; | ||
172 | } | ||
173 | deb_setf("hierachy: "); | ||
174 | switch (ofdm->hierarchy_information) { | ||
175 | case HIERARCHY_NONE: | ||
176 | deb_setf("none "); | ||
177 | /* fall through */ | ||
178 | case HIERARCHY_1: | ||
179 | deb_setf("alpha=1\n"); | ||
180 | wr(DIB3000MB_REG_VIT_ALPHA, DIB3000_ALPHA_1); | ||
181 | break; | ||
182 | case HIERARCHY_2: | ||
183 | deb_setf("alpha=2\n"); | ||
184 | wr(DIB3000MB_REG_VIT_ALPHA, DIB3000_ALPHA_2); | ||
185 | break; | ||
186 | case HIERARCHY_4: | ||
187 | deb_setf("alpha=4\n"); | ||
188 | wr(DIB3000MB_REG_VIT_ALPHA, DIB3000_ALPHA_4); | ||
189 | break; | ||
190 | case HIERARCHY_AUTO: | ||
191 | deb_setf("alpha=auto\n"); | ||
192 | break; | ||
193 | default: | ||
194 | return -EINVAL; | ||
195 | } | ||
196 | |||
197 | deb_setf("hierarchy: "); | ||
198 | if (ofdm->hierarchy_information == HIERARCHY_NONE) { | ||
199 | deb_setf("none\n"); | ||
200 | wr(DIB3000MB_REG_VIT_HRCH, DIB3000_HRCH_OFF); | ||
201 | wr(DIB3000MB_REG_VIT_HP, DIB3000_SELECT_HP); | ||
202 | fe_cr = ofdm->code_rate_HP; | ||
203 | } else if (ofdm->hierarchy_information != HIERARCHY_AUTO) { | ||
204 | deb_setf("on\n"); | ||
205 | wr(DIB3000MB_REG_VIT_HRCH, DIB3000_HRCH_ON); | ||
206 | wr(DIB3000MB_REG_VIT_HP, DIB3000_SELECT_LP); | ||
207 | fe_cr = ofdm->code_rate_LP; | ||
208 | } | ||
209 | deb_setf("fec: "); | ||
210 | switch (fe_cr) { | ||
211 | case FEC_1_2: | ||
212 | deb_setf("1_2\n"); | ||
213 | wr(DIB3000MB_REG_VIT_CODE_RATE, DIB3000_FEC_1_2); | ||
214 | break; | ||
215 | case FEC_2_3: | ||
216 | deb_setf("2_3\n"); | ||
217 | wr(DIB3000MB_REG_VIT_CODE_RATE, DIB3000_FEC_2_3); | ||
218 | break; | ||
219 | case FEC_3_4: | ||
220 | deb_setf("3_4\n"); | ||
221 | wr(DIB3000MB_REG_VIT_CODE_RATE, DIB3000_FEC_3_4); | ||
222 | break; | ||
223 | case FEC_5_6: | ||
224 | deb_setf("5_6\n"); | ||
225 | wr(DIB3000MB_REG_VIT_CODE_RATE, DIB3000_FEC_5_6); | ||
226 | break; | ||
227 | case FEC_7_8: | ||
228 | deb_setf("7_8\n"); | ||
229 | wr(DIB3000MB_REG_VIT_CODE_RATE, DIB3000_FEC_7_8); | ||
230 | break; | ||
231 | case FEC_NONE: | ||
232 | deb_setf("none "); | ||
233 | break; | ||
234 | case FEC_AUTO: | ||
235 | deb_setf("auto\n"); | ||
236 | break; | ||
237 | default: | ||
238 | return -EINVAL; | ||
239 | } | ||
240 | |||
241 | seq = dib3000_seq | ||
242 | [ofdm->transmission_mode == TRANSMISSION_MODE_AUTO] | ||
243 | [ofdm->guard_interval == GUARD_INTERVAL_AUTO] | ||
244 | [fep->inversion == INVERSION_AUTO]; | ||
245 | |||
246 | deb_setf("seq? %d\n", seq); | ||
247 | |||
248 | wr(DIB3000MB_REG_SEQ, seq); | ||
249 | |||
250 | wr(DIB3000MB_REG_ISI, seq ? DIB3000MB_ISI_INHIBIT : DIB3000MB_ISI_ACTIVATE); | ||
251 | |||
252 | if (ofdm->transmission_mode == TRANSMISSION_MODE_2K) { | ||
253 | if (ofdm->guard_interval == GUARD_INTERVAL_1_8) { | ||
254 | wr(DIB3000MB_REG_SYNC_IMPROVEMENT, DIB3000MB_SYNC_IMPROVE_2K_1_8); | ||
255 | } else { | ||
256 | wr(DIB3000MB_REG_SYNC_IMPROVEMENT, DIB3000MB_SYNC_IMPROVE_DEFAULT); | ||
257 | } | ||
258 | |||
259 | wr(DIB3000MB_REG_UNK_121, DIB3000MB_UNK_121_2K); | ||
260 | } else { | ||
261 | wr(DIB3000MB_REG_UNK_121, DIB3000MB_UNK_121_DEFAULT); | ||
262 | } | ||
263 | |||
264 | wr(DIB3000MB_REG_MOBILE_ALGO, DIB3000MB_MOBILE_ALGO_OFF); | ||
265 | wr(DIB3000MB_REG_MOBILE_MODE_QAM, DIB3000MB_MOBILE_MODE_QAM_OFF); | ||
266 | wr(DIB3000MB_REG_MOBILE_MODE, DIB3000MB_MOBILE_MODE_OFF); | ||
267 | |||
268 | wr_foreach(dib3000mb_reg_agc_bandwidth, dib3000mb_agc_bandwidth_high); | ||
269 | |||
270 | wr(DIB3000MB_REG_ISI, DIB3000MB_ISI_ACTIVATE); | ||
271 | |||
272 | wr(DIB3000MB_REG_RESTART, DIB3000MB_RESTART_AGC + DIB3000MB_RESTART_CTRL); | ||
273 | wr(DIB3000MB_REG_RESTART, DIB3000MB_RESTART_OFF); | ||
274 | |||
275 | /* wait for AGC lock */ | ||
276 | msleep(70); | ||
277 | |||
278 | wr_foreach(dib3000mb_reg_agc_bandwidth, dib3000mb_agc_bandwidth_low); | ||
279 | |||
280 | /* something has to be auto searched */ | ||
281 | if (ofdm->constellation == QAM_AUTO || | ||
282 | ofdm->hierarchy_information == HIERARCHY_AUTO || | ||
283 | fe_cr == FEC_AUTO || | ||
284 | fep->inversion == INVERSION_AUTO) { | ||
285 | int as_count=0; | ||
286 | |||
287 | deb_setf("autosearch enabled.\n"); | ||
288 | |||
289 | wr(DIB3000MB_REG_ISI, DIB3000MB_ISI_INHIBIT); | ||
290 | |||
291 | wr(DIB3000MB_REG_RESTART, DIB3000MB_RESTART_AUTO_SEARCH); | ||
292 | wr(DIB3000MB_REG_RESTART, DIB3000MB_RESTART_OFF); | ||
293 | |||
294 | while ((search_state = | ||
295 | dib3000_search_status( | ||
296 | rd(DIB3000MB_REG_AS_IRQ_PENDING), | ||
297 | rd(DIB3000MB_REG_LOCK2_VALUE))) < 0 && as_count++ < 100) | ||
298 | msleep(1); | ||
299 | |||
300 | deb_setf("search_state after autosearch %d after %d checks\n",search_state,as_count); | ||
301 | |||
302 | if (search_state == 1) { | ||
303 | struct dvb_frontend_parameters feps; | ||
304 | if (dib3000mb_get_frontend(fe, &feps) == 0) { | ||
305 | deb_setf("reading tuning data from frontend succeeded.\n"); | ||
306 | return dib3000mb_set_frontend(fe, &feps, 0); | ||
307 | } | ||
308 | } | ||
309 | |||
310 | } else { | ||
311 | wr(DIB3000MB_REG_RESTART, DIB3000MB_RESTART_CTRL); | ||
312 | wr(DIB3000MB_REG_RESTART, DIB3000MB_RESTART_OFF); | ||
313 | } | ||
314 | |||
315 | return 0; | ||
316 | } | ||
317 | |||
318 | static int dib3000mb_fe_init(struct dvb_frontend* fe, int mobile_mode) | ||
319 | { | ||
320 | struct dib3000_state* state = (struct dib3000_state*) fe->demodulator_priv; | ||
321 | |||
322 | deb_info("dib3000mb is getting up.\n"); | ||
323 | wr(DIB3000MB_REG_POWER_CONTROL, DIB3000MB_POWER_UP); | ||
324 | |||
325 | wr(DIB3000MB_REG_RESTART, DIB3000MB_RESTART_AGC); | ||
326 | |||
327 | wr(DIB3000MB_REG_RESET_DEVICE, DIB3000MB_RESET_DEVICE); | ||
328 | wr(DIB3000MB_REG_RESET_DEVICE, DIB3000MB_RESET_DEVICE_RST); | ||
329 | |||
330 | wr(DIB3000MB_REG_CLOCK, DIB3000MB_CLOCK_DEFAULT); | ||
331 | |||
332 | wr(DIB3000MB_REG_ELECT_OUT_MODE, DIB3000MB_ELECT_OUT_MODE_ON); | ||
333 | |||
334 | wr(DIB3000MB_REG_DDS_FREQ_MSB, DIB3000MB_DDS_FREQ_MSB); | ||
335 | wr(DIB3000MB_REG_DDS_FREQ_LSB, DIB3000MB_DDS_FREQ_LSB); | ||
336 | |||
337 | wr_foreach(dib3000mb_reg_timing_freq, dib3000mb_timing_freq[2]); | ||
338 | |||
339 | wr_foreach(dib3000mb_reg_impulse_noise, | ||
340 | dib3000mb_impulse_noise_values[DIB3000MB_IMPNOISE_OFF]); | ||
341 | |||
342 | wr_foreach(dib3000mb_reg_agc_gain, dib3000mb_default_agc_gain); | ||
343 | |||
344 | wr(DIB3000MB_REG_PHASE_NOISE, DIB3000MB_PHASE_NOISE_DEFAULT); | ||
345 | |||
346 | wr_foreach(dib3000mb_reg_phase_noise, dib3000mb_default_noise_phase); | ||
347 | |||
348 | wr_foreach(dib3000mb_reg_lock_duration, dib3000mb_default_lock_duration); | ||
349 | |||
350 | wr_foreach(dib3000mb_reg_agc_bandwidth, dib3000mb_agc_bandwidth_low); | ||
351 | |||
352 | wr(DIB3000MB_REG_LOCK0_MASK, DIB3000MB_LOCK0_DEFAULT); | ||
353 | wr(DIB3000MB_REG_LOCK1_MASK, DIB3000MB_LOCK1_SEARCH_4); | ||
354 | wr(DIB3000MB_REG_LOCK2_MASK, DIB3000MB_LOCK2_DEFAULT); | ||
355 | wr(DIB3000MB_REG_SEQ, dib3000_seq[1][1][1]); | ||
356 | |||
357 | wr_foreach(dib3000mb_reg_bandwidth, dib3000mb_bandwidth_8mhz); | ||
358 | |||
359 | wr(DIB3000MB_REG_UNK_68, DIB3000MB_UNK_68); | ||
360 | wr(DIB3000MB_REG_UNK_69, DIB3000MB_UNK_69); | ||
361 | wr(DIB3000MB_REG_UNK_71, DIB3000MB_UNK_71); | ||
362 | wr(DIB3000MB_REG_UNK_77, DIB3000MB_UNK_77); | ||
363 | wr(DIB3000MB_REG_UNK_78, DIB3000MB_UNK_78); | ||
364 | wr(DIB3000MB_REG_ISI, DIB3000MB_ISI_INHIBIT); | ||
365 | wr(DIB3000MB_REG_UNK_92, DIB3000MB_UNK_92); | ||
366 | wr(DIB3000MB_REG_UNK_96, DIB3000MB_UNK_96); | ||
367 | wr(DIB3000MB_REG_UNK_97, DIB3000MB_UNK_97); | ||
368 | wr(DIB3000MB_REG_UNK_106, DIB3000MB_UNK_106); | ||
369 | wr(DIB3000MB_REG_UNK_107, DIB3000MB_UNK_107); | ||
370 | wr(DIB3000MB_REG_UNK_108, DIB3000MB_UNK_108); | ||
371 | wr(DIB3000MB_REG_UNK_122, DIB3000MB_UNK_122); | ||
372 | wr(DIB3000MB_REG_MOBILE_MODE_QAM, DIB3000MB_MOBILE_MODE_QAM_OFF); | ||
373 | wr(DIB3000MB_REG_BERLEN, DIB3000MB_BERLEN_DEFAULT); | ||
374 | |||
375 | wr_foreach(dib3000mb_reg_filter_coeffs, dib3000mb_filter_coeffs); | ||
376 | |||
377 | wr(DIB3000MB_REG_MOBILE_ALGO, DIB3000MB_MOBILE_ALGO_ON); | ||
378 | wr(DIB3000MB_REG_MULTI_DEMOD_MSB, DIB3000MB_MULTI_DEMOD_MSB); | ||
379 | wr(DIB3000MB_REG_MULTI_DEMOD_LSB, DIB3000MB_MULTI_DEMOD_LSB); | ||
380 | |||
381 | wr(DIB3000MB_REG_OUTPUT_MODE, DIB3000MB_OUTPUT_MODE_SLAVE); | ||
382 | |||
383 | wr(DIB3000MB_REG_FIFO_142, DIB3000MB_FIFO_142); | ||
384 | wr(DIB3000MB_REG_MPEG2_OUT_MODE, DIB3000MB_MPEG2_OUT_MODE_188); | ||
385 | wr(DIB3000MB_REG_PID_PARSE, DIB3000MB_PID_PARSE_ACTIVATE); | ||
386 | wr(DIB3000MB_REG_FIFO, DIB3000MB_FIFO_INHIBIT); | ||
387 | wr(DIB3000MB_REG_FIFO_146, DIB3000MB_FIFO_146); | ||
388 | wr(DIB3000MB_REG_FIFO_147, DIB3000MB_FIFO_147); | ||
389 | |||
390 | wr(DIB3000MB_REG_DATA_IN_DIVERSITY, DIB3000MB_DATA_DIVERSITY_IN_OFF); | ||
391 | |||
392 | if (state->config.pll_init) { | ||
393 | dib3000mb_tuner_pass_ctrl(fe,1,state->config.pll_addr(fe)); | ||
394 | state->config.pll_init(fe,NULL); | ||
395 | dib3000mb_tuner_pass_ctrl(fe,0,state->config.pll_addr(fe)); | ||
396 | } | ||
397 | |||
398 | return 0; | ||
399 | } | ||
400 | |||
401 | static int dib3000mb_get_frontend(struct dvb_frontend* fe, | ||
402 | struct dvb_frontend_parameters *fep) | ||
403 | { | ||
404 | struct dib3000_state* state = (struct dib3000_state*) fe->demodulator_priv; | ||
405 | struct dvb_ofdm_parameters *ofdm = &fep->u.ofdm; | ||
406 | fe_code_rate_t *cr; | ||
407 | u16 tps_val; | ||
408 | int inv_test1,inv_test2; | ||
409 | u32 dds_val, threshold = 0x800000; | ||
410 | |||
411 | if (!rd(DIB3000MB_REG_TPS_LOCK)) | ||
412 | return 0; | ||
413 | |||
414 | dds_val = ((rd(DIB3000MB_REG_DDS_VALUE_MSB) & 0xff) << 16) + rd(DIB3000MB_REG_DDS_VALUE_LSB); | ||
415 | deb_getf("DDS_VAL: %x %x %x",dds_val, rd(DIB3000MB_REG_DDS_VALUE_MSB), rd(DIB3000MB_REG_DDS_VALUE_LSB)); | ||
416 | if (dds_val < threshold) | ||
417 | inv_test1 = 0; | ||
418 | else if (dds_val == threshold) | ||
419 | inv_test1 = 1; | ||
420 | else | ||
421 | inv_test1 = 2; | ||
422 | |||
423 | dds_val = ((rd(DIB3000MB_REG_DDS_FREQ_MSB) & 0xff) << 16) + rd(DIB3000MB_REG_DDS_FREQ_LSB); | ||
424 | deb_getf("DDS_FREQ: %x %x %x",dds_val, rd(DIB3000MB_REG_DDS_FREQ_MSB), rd(DIB3000MB_REG_DDS_FREQ_LSB)); | ||
425 | if (dds_val < threshold) | ||
426 | inv_test2 = 0; | ||
427 | else if (dds_val == threshold) | ||
428 | inv_test2 = 1; | ||
429 | else | ||
430 | inv_test2 = 2; | ||
431 | |||
432 | fep->inversion = | ||
433 | ((inv_test2 == 2) && (inv_test1==1 || inv_test1==0)) || | ||
434 | ((inv_test2 == 0) && (inv_test1==1 || inv_test1==2)) ? | ||
435 | INVERSION_ON : INVERSION_OFF; | ||
436 | |||
437 | deb_getf("inversion %d %d, %d\n", inv_test2, inv_test1, fep->inversion); | ||
438 | |||
439 | switch ((tps_val = rd(DIB3000MB_REG_TPS_QAM))) { | ||
440 | case DIB3000_CONSTELLATION_QPSK: | ||
441 | deb_getf("QPSK "); | ||
442 | ofdm->constellation = QPSK; | ||
443 | break; | ||
444 | case DIB3000_CONSTELLATION_16QAM: | ||
445 | deb_getf("QAM16 "); | ||
446 | ofdm->constellation = QAM_16; | ||
447 | break; | ||
448 | case DIB3000_CONSTELLATION_64QAM: | ||
449 | deb_getf("QAM64 "); | ||
450 | ofdm->constellation = QAM_64; | ||
451 | break; | ||
452 | default: | ||
453 | err("Unexpected constellation returned by TPS (%d)", tps_val); | ||
454 | break; | ||
455 | } | ||
456 | deb_getf("TPS: %d\n", tps_val); | ||
457 | |||
458 | if (rd(DIB3000MB_REG_TPS_HRCH)) { | ||
459 | deb_getf("HRCH ON\n"); | ||
460 | cr = &ofdm->code_rate_LP; | ||
461 | ofdm->code_rate_HP = FEC_NONE; | ||
462 | switch ((tps_val = rd(DIB3000MB_REG_TPS_VIT_ALPHA))) { | ||
463 | case DIB3000_ALPHA_0: | ||
464 | deb_getf("HIERARCHY_NONE "); | ||
465 | ofdm->hierarchy_information = HIERARCHY_NONE; | ||
466 | break; | ||
467 | case DIB3000_ALPHA_1: | ||
468 | deb_getf("HIERARCHY_1 "); | ||
469 | ofdm->hierarchy_information = HIERARCHY_1; | ||
470 | break; | ||
471 | case DIB3000_ALPHA_2: | ||
472 | deb_getf("HIERARCHY_2 "); | ||
473 | ofdm->hierarchy_information = HIERARCHY_2; | ||
474 | break; | ||
475 | case DIB3000_ALPHA_4: | ||
476 | deb_getf("HIERARCHY_4 "); | ||
477 | ofdm->hierarchy_information = HIERARCHY_4; | ||
478 | break; | ||
479 | default: | ||
480 | err("Unexpected ALPHA value returned by TPS (%d)", tps_val); | ||
481 | break; | ||
482 | } | ||
483 | deb_getf("TPS: %d\n", tps_val); | ||
484 | |||
485 | tps_val = rd(DIB3000MB_REG_TPS_CODE_RATE_LP); | ||
486 | } else { | ||
487 | deb_getf("HRCH OFF\n"); | ||
488 | cr = &ofdm->code_rate_HP; | ||
489 | ofdm->code_rate_LP = FEC_NONE; | ||
490 | ofdm->hierarchy_information = HIERARCHY_NONE; | ||
491 | |||
492 | tps_val = rd(DIB3000MB_REG_TPS_CODE_RATE_HP); | ||
493 | } | ||
494 | |||
495 | switch (tps_val) { | ||
496 | case DIB3000_FEC_1_2: | ||
497 | deb_getf("FEC_1_2 "); | ||
498 | *cr = FEC_1_2; | ||
499 | break; | ||
500 | case DIB3000_FEC_2_3: | ||
501 | deb_getf("FEC_2_3 "); | ||
502 | *cr = FEC_2_3; | ||
503 | break; | ||
504 | case DIB3000_FEC_3_4: | ||
505 | deb_getf("FEC_3_4 "); | ||
506 | *cr = FEC_3_4; | ||
507 | break; | ||
508 | case DIB3000_FEC_5_6: | ||
509 | deb_getf("FEC_5_6 "); | ||
510 | *cr = FEC_4_5; | ||
511 | break; | ||
512 | case DIB3000_FEC_7_8: | ||
513 | deb_getf("FEC_7_8 "); | ||
514 | *cr = FEC_7_8; | ||
515 | break; | ||
516 | default: | ||
517 | err("Unexpected FEC returned by TPS (%d)", tps_val); | ||
518 | break; | ||
519 | } | ||
520 | deb_getf("TPS: %d\n",tps_val); | ||
521 | |||
522 | switch ((tps_val = rd(DIB3000MB_REG_TPS_GUARD_TIME))) { | ||
523 | case DIB3000_GUARD_TIME_1_32: | ||
524 | deb_getf("GUARD_INTERVAL_1_32 "); | ||
525 | ofdm->guard_interval = GUARD_INTERVAL_1_32; | ||
526 | break; | ||
527 | case DIB3000_GUARD_TIME_1_16: | ||
528 | deb_getf("GUARD_INTERVAL_1_16 "); | ||
529 | ofdm->guard_interval = GUARD_INTERVAL_1_16; | ||
530 | break; | ||
531 | case DIB3000_GUARD_TIME_1_8: | ||
532 | deb_getf("GUARD_INTERVAL_1_8 "); | ||
533 | ofdm->guard_interval = GUARD_INTERVAL_1_8; | ||
534 | break; | ||
535 | case DIB3000_GUARD_TIME_1_4: | ||
536 | deb_getf("GUARD_INTERVAL_1_4 "); | ||
537 | ofdm->guard_interval = GUARD_INTERVAL_1_4; | ||
538 | break; | ||
539 | default: | ||
540 | err("Unexpected Guard Time returned by TPS (%d)", tps_val); | ||
541 | break; | ||
542 | } | ||
543 | deb_getf("TPS: %d\n", tps_val); | ||
544 | |||
545 | switch ((tps_val = rd(DIB3000MB_REG_TPS_FFT))) { | ||
546 | case DIB3000_TRANSMISSION_MODE_2K: | ||
547 | deb_getf("TRANSMISSION_MODE_2K "); | ||
548 | ofdm->transmission_mode = TRANSMISSION_MODE_2K; | ||
549 | break; | ||
550 | case DIB3000_TRANSMISSION_MODE_8K: | ||
551 | deb_getf("TRANSMISSION_MODE_8K "); | ||
552 | ofdm->transmission_mode = TRANSMISSION_MODE_8K; | ||
553 | break; | ||
554 | default: | ||
555 | err("unexpected transmission mode return by TPS (%d)", tps_val); | ||
556 | break; | ||
557 | } | ||
558 | deb_getf("TPS: %d\n", tps_val); | ||
559 | |||
560 | return 0; | ||
561 | } | ||
562 | |||
563 | static int dib3000mb_read_status(struct dvb_frontend* fe, fe_status_t *stat) | ||
564 | { | ||
565 | struct dib3000_state* state = (struct dib3000_state*) fe->demodulator_priv; | ||
566 | |||
567 | *stat = 0; | ||
568 | |||
569 | if (rd(DIB3000MB_REG_AGC_LOCK)) | ||
570 | *stat |= FE_HAS_SIGNAL; | ||
571 | if (rd(DIB3000MB_REG_CARRIER_LOCK)) | ||
572 | *stat |= FE_HAS_CARRIER; | ||
573 | if (rd(DIB3000MB_REG_VIT_LCK)) | ||
574 | *stat |= FE_HAS_VITERBI; | ||
575 | if (rd(DIB3000MB_REG_TS_SYNC_LOCK)) | ||
576 | *stat |= (FE_HAS_SYNC | FE_HAS_LOCK); | ||
577 | |||
578 | deb_getf("actual status is %2x\n",*stat); | ||
579 | |||
580 | deb_getf("autoval: tps: %d, qam: %d, hrch: %d, alpha: %d, hp: %d, lp: %d, guard: %d, fft: %d cell: %d\n", | ||
581 | rd(DIB3000MB_REG_TPS_LOCK), | ||
582 | rd(DIB3000MB_REG_TPS_QAM), | ||
583 | rd(DIB3000MB_REG_TPS_HRCH), | ||
584 | rd(DIB3000MB_REG_TPS_VIT_ALPHA), | ||
585 | rd(DIB3000MB_REG_TPS_CODE_RATE_HP), | ||
586 | rd(DIB3000MB_REG_TPS_CODE_RATE_LP), | ||
587 | rd(DIB3000MB_REG_TPS_GUARD_TIME), | ||
588 | rd(DIB3000MB_REG_TPS_FFT), | ||
589 | rd(DIB3000MB_REG_TPS_CELL_ID)); | ||
590 | |||
591 | //*stat = FE_HAS_SIGNAL | FE_HAS_CARRIER | FE_HAS_VITERBI | FE_HAS_SYNC | FE_HAS_LOCK; | ||
592 | return 0; | ||
593 | } | ||
594 | |||
595 | static int dib3000mb_read_ber(struct dvb_frontend* fe, u32 *ber) | ||
596 | { | ||
597 | struct dib3000_state* state = (struct dib3000_state*) fe->demodulator_priv; | ||
598 | |||
599 | *ber = ((rd(DIB3000MB_REG_BER_MSB) << 16) | rd(DIB3000MB_REG_BER_LSB)); | ||
600 | return 0; | ||
601 | } | ||
602 | |||
603 | /* see dib3000-watch dvb-apps for exact calcuations of signal_strength and snr */ | ||
604 | static int dib3000mb_read_signal_strength(struct dvb_frontend* fe, u16 *strength) | ||
605 | { | ||
606 | struct dib3000_state* state = (struct dib3000_state*) fe->demodulator_priv; | ||
607 | |||
608 | *strength = rd(DIB3000MB_REG_SIGNAL_POWER) * 0xffff / 0x170; | ||
609 | return 0; | ||
610 | } | ||
611 | |||
612 | static int dib3000mb_read_snr(struct dvb_frontend* fe, u16 *snr) | ||
613 | { | ||
614 | struct dib3000_state* state = (struct dib3000_state*) fe->demodulator_priv; | ||
615 | short sigpow = rd(DIB3000MB_REG_SIGNAL_POWER); | ||
616 | int icipow = ((rd(DIB3000MB_REG_NOISE_POWER_MSB) & 0xff) << 16) | | ||
617 | rd(DIB3000MB_REG_NOISE_POWER_LSB); | ||
618 | *snr = (sigpow << 8) / ((icipow > 0) ? icipow : 1); | ||
619 | return 0; | ||
620 | } | ||
621 | |||
622 | static int dib3000mb_read_unc_blocks(struct dvb_frontend* fe, u32 *unc) | ||
623 | { | ||
624 | struct dib3000_state* state = (struct dib3000_state*) fe->demodulator_priv; | ||
625 | |||
626 | *unc = rd(DIB3000MB_REG_UNC); | ||
627 | return 0; | ||
628 | } | ||
629 | |||
630 | static int dib3000mb_sleep(struct dvb_frontend* fe) | ||
631 | { | ||
632 | struct dib3000_state* state = (struct dib3000_state*) fe->demodulator_priv; | ||
633 | deb_info("dib3000mb is going to bed.\n"); | ||
634 | wr(DIB3000MB_REG_POWER_CONTROL, DIB3000MB_POWER_DOWN); | ||
635 | return 0; | ||
636 | } | ||
637 | |||
638 | static int dib3000mb_fe_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings *tune) | ||
639 | { | ||
640 | tune->min_delay_ms = 800; | ||
641 | tune->step_size = 166667; | ||
642 | tune->max_drift = 166667 * 2; | ||
643 | |||
644 | return 0; | ||
645 | } | ||
646 | |||
647 | static int dib3000mb_fe_init_nonmobile(struct dvb_frontend* fe) | ||
648 | { | ||
649 | return dib3000mb_fe_init(fe, 0); | ||
650 | } | ||
651 | |||
652 | static int dib3000mb_set_frontend_and_tuner(struct dvb_frontend* fe, struct dvb_frontend_parameters *fep) | ||
653 | { | ||
654 | return dib3000mb_set_frontend(fe, fep, 1); | ||
655 | } | ||
656 | |||
657 | static void dib3000mb_release(struct dvb_frontend* fe) | ||
658 | { | ||
659 | struct dib3000_state *state = (struct dib3000_state*) fe->demodulator_priv; | ||
660 | kfree(state); | ||
661 | } | ||
662 | |||
663 | /* pid filter and transfer stuff */ | ||
664 | static int dib3000mb_pid_control(struct dvb_frontend *fe,int index, int pid,int onoff) | ||
665 | { | ||
666 | struct dib3000_state *state = fe->demodulator_priv; | ||
667 | pid = (onoff ? pid | DIB3000_ACTIVATE_PID_FILTERING : 0); | ||
668 | wr(index+DIB3000MB_REG_FIRST_PID,pid); | ||
669 | return 0; | ||
670 | } | ||
671 | |||
672 | static int dib3000mb_fifo_control(struct dvb_frontend *fe, int onoff) | ||
673 | { | ||
674 | struct dib3000_state *state = (struct dib3000_state*) fe->demodulator_priv; | ||
675 | |||
676 | deb_xfer("%s fifo\n",onoff ? "enabling" : "disabling"); | ||
677 | if (onoff) { | ||
678 | wr(DIB3000MB_REG_FIFO, DIB3000MB_FIFO_ACTIVATE); | ||
679 | } else { | ||
680 | wr(DIB3000MB_REG_FIFO, DIB3000MB_FIFO_INHIBIT); | ||
681 | } | ||
682 | return 0; | ||
683 | } | ||
684 | |||
685 | static int dib3000mb_pid_parse(struct dvb_frontend *fe, int onoff) | ||
686 | { | ||
687 | struct dib3000_state *state = fe->demodulator_priv; | ||
688 | deb_xfer("%s pid parsing\n",onoff ? "enabling" : "disabling"); | ||
689 | wr(DIB3000MB_REG_PID_PARSE,onoff); | ||
690 | return 0; | ||
691 | } | ||
692 | |||
693 | static int dib3000mb_tuner_pass_ctrl(struct dvb_frontend *fe, int onoff, u8 pll_addr) | ||
694 | { | ||
695 | struct dib3000_state *state = (struct dib3000_state*) fe->demodulator_priv; | ||
696 | if (onoff) { | ||
697 | wr(DIB3000MB_REG_TUNER, DIB3000_TUNER_WRITE_ENABLE(pll_addr)); | ||
698 | } else { | ||
699 | wr(DIB3000MB_REG_TUNER, DIB3000_TUNER_WRITE_DISABLE(pll_addr)); | ||
700 | } | ||
701 | return 0; | ||
702 | } | ||
703 | |||
704 | static struct dvb_frontend_ops dib3000mb_ops; | ||
705 | |||
706 | struct dvb_frontend* dib3000mb_attach(const struct dib3000_config* config, | ||
707 | struct i2c_adapter* i2c, struct dib_fe_xfer_ops *xfer_ops) | ||
708 | { | ||
709 | struct dib3000_state* state = NULL; | ||
710 | |||
711 | /* allocate memory for the internal state */ | ||
712 | state = (struct dib3000_state*) kmalloc(sizeof(struct dib3000_state), GFP_KERNEL); | ||
713 | if (state == NULL) | ||
714 | goto error; | ||
715 | memset(state,0,sizeof(struct dib3000_state)); | ||
716 | |||
717 | /* setup the state */ | ||
718 | state->i2c = i2c; | ||
719 | memcpy(&state->config,config,sizeof(struct dib3000_config)); | ||
720 | memcpy(&state->ops, &dib3000mb_ops, sizeof(struct dvb_frontend_ops)); | ||
721 | |||
722 | /* check for the correct demod */ | ||
723 | if (rd(DIB3000_REG_MANUFACTOR_ID) != DIB3000_I2C_ID_DIBCOM) | ||
724 | goto error; | ||
725 | |||
726 | if (rd(DIB3000_REG_DEVICE_ID) != DIB3000MB_DEVICE_ID) | ||
727 | goto error; | ||
728 | |||
729 | /* create dvb_frontend */ | ||
730 | state->frontend.ops = &state->ops; | ||
731 | state->frontend.demodulator_priv = state; | ||
732 | |||
733 | /* set the xfer operations */ | ||
734 | xfer_ops->pid_parse = dib3000mb_pid_parse; | ||
735 | xfer_ops->fifo_ctrl = dib3000mb_fifo_control; | ||
736 | xfer_ops->pid_ctrl = dib3000mb_pid_control; | ||
737 | xfer_ops->tuner_pass_ctrl = dib3000mb_tuner_pass_ctrl; | ||
738 | |||
739 | return &state->frontend; | ||
740 | |||
741 | error: | ||
742 | kfree(state); | ||
743 | return NULL; | ||
744 | } | ||
745 | |||
746 | static struct dvb_frontend_ops dib3000mb_ops = { | ||
747 | |||
748 | .info = { | ||
749 | .name = "DiBcom 3000M-B DVB-T", | ||
750 | .type = FE_OFDM, | ||
751 | .frequency_min = 44250000, | ||
752 | .frequency_max = 867250000, | ||
753 | .frequency_stepsize = 62500, | ||
754 | .caps = FE_CAN_INVERSION_AUTO | | ||
755 | FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | | ||
756 | FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO | | ||
757 | FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO | | ||
758 | FE_CAN_TRANSMISSION_MODE_AUTO | | ||
759 | FE_CAN_GUARD_INTERVAL_AUTO | | ||
760 | FE_CAN_RECOVER | | ||
761 | FE_CAN_HIERARCHY_AUTO, | ||
762 | }, | ||
763 | |||
764 | .release = dib3000mb_release, | ||
765 | |||
766 | .init = dib3000mb_fe_init_nonmobile, | ||
767 | .sleep = dib3000mb_sleep, | ||
768 | |||
769 | .set_frontend = dib3000mb_set_frontend_and_tuner, | ||
770 | .get_frontend = dib3000mb_get_frontend, | ||
771 | .get_tune_settings = dib3000mb_fe_get_tune_settings, | ||
772 | |||
773 | .read_status = dib3000mb_read_status, | ||
774 | .read_ber = dib3000mb_read_ber, | ||
775 | .read_signal_strength = dib3000mb_read_signal_strength, | ||
776 | .read_snr = dib3000mb_read_snr, | ||
777 | .read_ucblocks = dib3000mb_read_unc_blocks, | ||
778 | }; | ||
779 | |||
780 | MODULE_AUTHOR(DRIVER_AUTHOR); | ||
781 | MODULE_DESCRIPTION(DRIVER_DESC); | ||
782 | MODULE_LICENSE("GPL"); | ||
783 | |||
784 | EXPORT_SYMBOL(dib3000mb_attach); | ||
diff --git a/drivers/media/dvb/frontends/dib3000mb_priv.h b/drivers/media/dvb/frontends/dib3000mb_priv.h new file mode 100644 index 000000000000..57e61aa5b07b --- /dev/null +++ b/drivers/media/dvb/frontends/dib3000mb_priv.h | |||
@@ -0,0 +1,467 @@ | |||
1 | /* | ||
2 | * dib3000mb_priv.h | ||
3 | * | ||
4 | * Copyright (C) 2004 Patrick Boettcher (patrick.boettcher@desy.de) | ||
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 | * for more information see dib3000mb.c . | ||
11 | */ | ||
12 | |||
13 | #ifndef __DIB3000MB_PRIV_H_INCLUDED__ | ||
14 | #define __DIB3000MB_PRIV_H_INCLUDED__ | ||
15 | |||
16 | /* register addresses and some of their default values */ | ||
17 | |||
18 | /* restart subsystems */ | ||
19 | #define DIB3000MB_REG_RESTART ( 0) | ||
20 | |||
21 | #define DIB3000MB_RESTART_OFF ( 0) | ||
22 | #define DIB3000MB_RESTART_AUTO_SEARCH (1 << 1) | ||
23 | #define DIB3000MB_RESTART_CTRL (1 << 2) | ||
24 | #define DIB3000MB_RESTART_AGC (1 << 3) | ||
25 | |||
26 | /* FFT size */ | ||
27 | #define DIB3000MB_REG_FFT ( 1) | ||
28 | |||
29 | /* Guard time */ | ||
30 | #define DIB3000MB_REG_GUARD_TIME ( 2) | ||
31 | |||
32 | /* QAM */ | ||
33 | #define DIB3000MB_REG_QAM ( 3) | ||
34 | |||
35 | /* Alpha coefficient high priority Viterbi algorithm */ | ||
36 | #define DIB3000MB_REG_VIT_ALPHA ( 4) | ||
37 | |||
38 | /* spectrum inversion */ | ||
39 | #define DIB3000MB_REG_DDS_INV ( 5) | ||
40 | |||
41 | /* DDS frequency value (IF position) ad ? values don't match reg_3000mb.txt */ | ||
42 | #define DIB3000MB_REG_DDS_FREQ_MSB ( 6) | ||
43 | #define DIB3000MB_REG_DDS_FREQ_LSB ( 7) | ||
44 | #define DIB3000MB_DDS_FREQ_MSB ( 178) | ||
45 | #define DIB3000MB_DDS_FREQ_LSB ( 8990) | ||
46 | |||
47 | /* timing frequency (carrier spacing) */ | ||
48 | static u16 dib3000mb_reg_timing_freq[] = { 8,9 }; | ||
49 | static u16 dib3000mb_timing_freq[][2] = { | ||
50 | { 126 , 48873 }, /* 6 MHz */ | ||
51 | { 147 , 57019 }, /* 7 MHz */ | ||
52 | { 168 , 65164 }, /* 8 MHz */ | ||
53 | }; | ||
54 | |||
55 | /* impulse noise parameter */ | ||
56 | /* 36 ??? */ | ||
57 | |||
58 | static u16 dib3000mb_reg_impulse_noise[] = { 10,11,12,15,36 }; | ||
59 | |||
60 | enum dib3000mb_impulse_noise_type { | ||
61 | DIB3000MB_IMPNOISE_OFF, | ||
62 | DIB3000MB_IMPNOISE_MOBILE, | ||
63 | DIB3000MB_IMPNOISE_FIXED, | ||
64 | DIB3000MB_IMPNOISE_DEFAULT | ||
65 | }; | ||
66 | |||
67 | static u16 dib3000mb_impulse_noise_values[][5] = { | ||
68 | { 0x0000, 0x0004, 0x0014, 0x01ff, 0x0399 }, /* off */ | ||
69 | { 0x0001, 0x0004, 0x0014, 0x01ff, 0x037b }, /* mobile */ | ||
70 | { 0x0001, 0x0004, 0x0020, 0x01bd, 0x0399 }, /* fixed */ | ||
71 | { 0x0000, 0x0002, 0x000a, 0x01ff, 0x0399 }, /* default */ | ||
72 | }; | ||
73 | |||
74 | /* | ||
75 | * Dual Automatic-Gain-Control | ||
76 | * - gains RF in tuner (AGC1) | ||
77 | * - gains IF after filtering (AGC2) | ||
78 | */ | ||
79 | |||
80 | /* also from 16 to 18 */ | ||
81 | static u16 dib3000mb_reg_agc_gain[] = { | ||
82 | 19,20,21,22,23,24,25,26,27,28,29,30,31,32 | ||
83 | }; | ||
84 | |||
85 | static u16 dib3000mb_default_agc_gain[] = | ||
86 | { 0x0001, 52429, 623, 128, 166, 195, 61, /* RF ??? */ | ||
87 | 0x0001, 53766, 38011, 0, 90, 33, 23 }; /* IF ??? */ | ||
88 | |||
89 | /* phase noise */ | ||
90 | /* 36 is set when setting the impulse noise */ | ||
91 | static u16 dib3000mb_reg_phase_noise[] = { 33,34,35,37,38 }; | ||
92 | |||
93 | static u16 dib3000mb_default_noise_phase[] = { 2, 544, 0, 5, 4 }; | ||
94 | |||
95 | /* lock duration */ | ||
96 | static u16 dib3000mb_reg_lock_duration[] = { 39,40 }; | ||
97 | static u16 dib3000mb_default_lock_duration[] = { 135, 135 }; | ||
98 | |||
99 | /* AGC loop bandwidth */ | ||
100 | static u16 dib3000mb_reg_agc_bandwidth[] = { 43,44,45,46,47,48,49,50 }; | ||
101 | |||
102 | static u16 dib3000mb_agc_bandwidth_low[] = | ||
103 | { 2088, 10, 2088, 10, 3448, 5, 3448, 5 }; | ||
104 | static u16 dib3000mb_agc_bandwidth_high[] = | ||
105 | { 2349, 5, 2349, 5, 2586, 2, 2586, 2 }; | ||
106 | |||
107 | /* | ||
108 | * lock0 definition (coff_lock) | ||
109 | */ | ||
110 | #define DIB3000MB_REG_LOCK0_MASK ( 51) | ||
111 | #define DIB3000MB_LOCK0_DEFAULT ( 4) | ||
112 | |||
113 | /* | ||
114 | * lock1 definition (cpil_lock) | ||
115 | * for auto search | ||
116 | * which values hide behind the lock masks | ||
117 | */ | ||
118 | #define DIB3000MB_REG_LOCK1_MASK ( 52) | ||
119 | #define DIB3000MB_LOCK1_SEARCH_4 (0x0004) | ||
120 | #define DIB3000MB_LOCK1_SEARCH_2048 (0x0800) | ||
121 | #define DIB3000MB_LOCK1_DEFAULT (0x0001) | ||
122 | |||
123 | /* | ||
124 | * lock2 definition (fec_lock) */ | ||
125 | #define DIB3000MB_REG_LOCK2_MASK ( 53) | ||
126 | #define DIB3000MB_LOCK2_DEFAULT (0x0080) | ||
127 | |||
128 | /* | ||
129 | * SEQ ? what was that again ... :) | ||
130 | * changes when, inversion, guard time and fft is | ||
131 | * either automatically detected or not | ||
132 | */ | ||
133 | #define DIB3000MB_REG_SEQ ( 54) | ||
134 | |||
135 | /* bandwidth */ | ||
136 | static u16 dib3000mb_reg_bandwidth[] = { 55,56,57,58,59,60,61,62,63,64,65,66,67 }; | ||
137 | static u16 dib3000mb_bandwidth_6mhz[] = | ||
138 | { 0, 33, 53312, 112, 46635, 563, 36565, 0, 1000, 0, 1010, 1, 45264 }; | ||
139 | |||
140 | static u16 dib3000mb_bandwidth_7mhz[] = | ||
141 | { 0, 28, 64421, 96, 39973, 483, 3255, 0, 1000, 0, 1010, 1, 45264 }; | ||
142 | |||
143 | static u16 dib3000mb_bandwidth_8mhz[] = | ||
144 | { 0, 25, 23600, 84, 34976, 422, 43808, 0, 1000, 0, 1010, 1, 45264 }; | ||
145 | |||
146 | #define DIB3000MB_REG_UNK_68 ( 68) | ||
147 | #define DIB3000MB_UNK_68 ( 0) | ||
148 | |||
149 | #define DIB3000MB_REG_UNK_69 ( 69) | ||
150 | #define DIB3000MB_UNK_69 ( 0) | ||
151 | |||
152 | #define DIB3000MB_REG_UNK_71 ( 71) | ||
153 | #define DIB3000MB_UNK_71 ( 0) | ||
154 | |||
155 | #define DIB3000MB_REG_UNK_77 ( 77) | ||
156 | #define DIB3000MB_UNK_77 ( 6) | ||
157 | |||
158 | #define DIB3000MB_REG_UNK_78 ( 78) | ||
159 | #define DIB3000MB_UNK_78 (0x0080) | ||
160 | |||
161 | /* isi */ | ||
162 | #define DIB3000MB_REG_ISI ( 79) | ||
163 | #define DIB3000MB_ISI_ACTIVATE ( 0) | ||
164 | #define DIB3000MB_ISI_INHIBIT ( 1) | ||
165 | |||
166 | /* sync impovement */ | ||
167 | #define DIB3000MB_REG_SYNC_IMPROVEMENT ( 84) | ||
168 | #define DIB3000MB_SYNC_IMPROVE_2K_1_8 ( 3) | ||
169 | #define DIB3000MB_SYNC_IMPROVE_DEFAULT ( 0) | ||
170 | |||
171 | /* phase noise compensation inhibition */ | ||
172 | #define DIB3000MB_REG_PHASE_NOISE ( 87) | ||
173 | #define DIB3000MB_PHASE_NOISE_DEFAULT ( 0) | ||
174 | |||
175 | #define DIB3000MB_REG_UNK_92 ( 92) | ||
176 | #define DIB3000MB_UNK_92 (0x0080) | ||
177 | |||
178 | #define DIB3000MB_REG_UNK_96 ( 96) | ||
179 | #define DIB3000MB_UNK_96 (0x0010) | ||
180 | |||
181 | #define DIB3000MB_REG_UNK_97 ( 97) | ||
182 | #define DIB3000MB_UNK_97 (0x0009) | ||
183 | |||
184 | /* mobile mode ??? */ | ||
185 | #define DIB3000MB_REG_MOBILE_MODE ( 101) | ||
186 | #define DIB3000MB_MOBILE_MODE_ON ( 1) | ||
187 | #define DIB3000MB_MOBILE_MODE_OFF ( 0) | ||
188 | |||
189 | #define DIB3000MB_REG_UNK_106 ( 106) | ||
190 | #define DIB3000MB_UNK_106 (0x0080) | ||
191 | |||
192 | #define DIB3000MB_REG_UNK_107 ( 107) | ||
193 | #define DIB3000MB_UNK_107 (0x0080) | ||
194 | |||
195 | #define DIB3000MB_REG_UNK_108 ( 108) | ||
196 | #define DIB3000MB_UNK_108 (0x0080) | ||
197 | |||
198 | /* fft */ | ||
199 | #define DIB3000MB_REG_UNK_121 ( 121) | ||
200 | #define DIB3000MB_UNK_121_2K ( 7) | ||
201 | #define DIB3000MB_UNK_121_DEFAULT ( 5) | ||
202 | |||
203 | #define DIB3000MB_REG_UNK_122 ( 122) | ||
204 | #define DIB3000MB_UNK_122 ( 2867) | ||
205 | |||
206 | /* QAM for mobile mode */ | ||
207 | #define DIB3000MB_REG_MOBILE_MODE_QAM ( 126) | ||
208 | #define DIB3000MB_MOBILE_MODE_QAM_64 ( 3) | ||
209 | #define DIB3000MB_MOBILE_MODE_QAM_QPSK_16 ( 1) | ||
210 | #define DIB3000MB_MOBILE_MODE_QAM_OFF ( 0) | ||
211 | |||
212 | /* | ||
213 | * data diversity when having more than one chip on-board | ||
214 | * see also DIB3000MB_OUTPUT_MODE_DATA_DIVERSITY | ||
215 | */ | ||
216 | #define DIB3000MB_REG_DATA_IN_DIVERSITY ( 127) | ||
217 | #define DIB3000MB_DATA_DIVERSITY_IN_OFF ( 0) | ||
218 | #define DIB3000MB_DATA_DIVERSITY_IN_ON ( 2) | ||
219 | |||
220 | /* vit hrch */ | ||
221 | #define DIB3000MB_REG_VIT_HRCH ( 128) | ||
222 | |||
223 | /* vit code rate */ | ||
224 | #define DIB3000MB_REG_VIT_CODE_RATE ( 129) | ||
225 | |||
226 | /* vit select hp */ | ||
227 | #define DIB3000MB_REG_VIT_HP ( 130) | ||
228 | |||
229 | /* time frame for Bit-Error-Rate calculation */ | ||
230 | #define DIB3000MB_REG_BERLEN ( 135) | ||
231 | #define DIB3000MB_BERLEN_LONG ( 0) | ||
232 | #define DIB3000MB_BERLEN_DEFAULT ( 1) | ||
233 | #define DIB3000MB_BERLEN_MEDIUM ( 2) | ||
234 | #define DIB3000MB_BERLEN_SHORT ( 3) | ||
235 | |||
236 | /* 142 - 152 FIFO parameters | ||
237 | * which is what ? | ||
238 | */ | ||
239 | |||
240 | #define DIB3000MB_REG_FIFO_142 ( 142) | ||
241 | #define DIB3000MB_FIFO_142 ( 0) | ||
242 | |||
243 | /* MPEG2 TS output mode */ | ||
244 | #define DIB3000MB_REG_MPEG2_OUT_MODE ( 143) | ||
245 | #define DIB3000MB_MPEG2_OUT_MODE_204 ( 0) | ||
246 | #define DIB3000MB_MPEG2_OUT_MODE_188 ( 1) | ||
247 | |||
248 | #define DIB3000MB_REG_PID_PARSE ( 144) | ||
249 | #define DIB3000MB_PID_PARSE_INHIBIT ( 0) | ||
250 | #define DIB3000MB_PID_PARSE_ACTIVATE ( 1) | ||
251 | |||
252 | #define DIB3000MB_REG_FIFO ( 145) | ||
253 | #define DIB3000MB_FIFO_INHIBIT ( 1) | ||
254 | #define DIB3000MB_FIFO_ACTIVATE ( 0) | ||
255 | |||
256 | #define DIB3000MB_REG_FIFO_146 ( 146) | ||
257 | #define DIB3000MB_FIFO_146 ( 3) | ||
258 | |||
259 | #define DIB3000MB_REG_FIFO_147 ( 147) | ||
260 | #define DIB3000MB_FIFO_147 (0x0100) | ||
261 | |||
262 | /* | ||
263 | * pidfilter | ||
264 | * it is not a hardware pidfilter but a filter which drops all pids | ||
265 | * except the ones set. Necessary because of the limited USB1.1 bandwidth. | ||
266 | * regs 153-168 | ||
267 | */ | ||
268 | |||
269 | #define DIB3000MB_REG_FIRST_PID ( 153) | ||
270 | #define DIB3000MB_NUM_PIDS ( 16) | ||
271 | |||
272 | /* | ||
273 | * output mode | ||
274 | * USB devices have to use 'slave'-mode | ||
275 | * see also DIB3000MB_REG_ELECT_OUT_MODE | ||
276 | */ | ||
277 | #define DIB3000MB_REG_OUTPUT_MODE ( 169) | ||
278 | #define DIB3000MB_OUTPUT_MODE_GATED_CLK ( 0) | ||
279 | #define DIB3000MB_OUTPUT_MODE_CONT_CLK ( 1) | ||
280 | #define DIB3000MB_OUTPUT_MODE_SERIAL ( 2) | ||
281 | #define DIB3000MB_OUTPUT_MODE_DATA_DIVERSITY ( 5) | ||
282 | #define DIB3000MB_OUTPUT_MODE_SLAVE ( 6) | ||
283 | |||
284 | /* irq event mask */ | ||
285 | #define DIB3000MB_REG_IRQ_EVENT_MASK ( 170) | ||
286 | #define DIB3000MB_IRQ_EVENT_MASK ( 0) | ||
287 | |||
288 | /* filter coefficients */ | ||
289 | static u16 dib3000mb_reg_filter_coeffs[] = { | ||
290 | 171, 172, 173, 174, 175, 176, 177, 178, | ||
291 | 179, 180, 181, 182, 183, 184, 185, 186, | ||
292 | 188, 189, 190, 191, 192, 194 | ||
293 | }; | ||
294 | |||
295 | static u16 dib3000mb_filter_coeffs[] = { | ||
296 | 226, 160, 29, | ||
297 | 979, 998, 19, | ||
298 | 22, 1019, 1006, | ||
299 | 1022, 12, 6, | ||
300 | 1017, 1017, 3, | ||
301 | 6, 1019, | ||
302 | 1021, 2, 3, | ||
303 | 1, 0, | ||
304 | }; | ||
305 | |||
306 | /* | ||
307 | * mobile algorithm (when you are moving with your device) | ||
308 | * but not faster than 90 km/h | ||
309 | */ | ||
310 | #define DIB3000MB_REG_MOBILE_ALGO ( 195) | ||
311 | #define DIB3000MB_MOBILE_ALGO_ON ( 0) | ||
312 | #define DIB3000MB_MOBILE_ALGO_OFF ( 1) | ||
313 | |||
314 | /* multiple demodulators algorithm */ | ||
315 | #define DIB3000MB_REG_MULTI_DEMOD_MSB ( 206) | ||
316 | #define DIB3000MB_REG_MULTI_DEMOD_LSB ( 207) | ||
317 | |||
318 | /* terminator, no more demods */ | ||
319 | #define DIB3000MB_MULTI_DEMOD_MSB ( 32767) | ||
320 | #define DIB3000MB_MULTI_DEMOD_LSB ( 4095) | ||
321 | |||
322 | /* bring the device into a known */ | ||
323 | #define DIB3000MB_REG_RESET_DEVICE ( 1024) | ||
324 | #define DIB3000MB_RESET_DEVICE (0x812c) | ||
325 | #define DIB3000MB_RESET_DEVICE_RST ( 0) | ||
326 | |||
327 | /* hardware clock configuration */ | ||
328 | #define DIB3000MB_REG_CLOCK ( 1027) | ||
329 | #define DIB3000MB_CLOCK_DEFAULT (0x9000) | ||
330 | #define DIB3000MB_CLOCK_DIVERSITY (0x92b0) | ||
331 | |||
332 | /* power down config */ | ||
333 | #define DIB3000MB_REG_POWER_CONTROL ( 1028) | ||
334 | #define DIB3000MB_POWER_DOWN ( 1) | ||
335 | #define DIB3000MB_POWER_UP ( 0) | ||
336 | |||
337 | /* electrical output mode */ | ||
338 | #define DIB3000MB_REG_ELECT_OUT_MODE ( 1029) | ||
339 | #define DIB3000MB_ELECT_OUT_MODE_OFF ( 0) | ||
340 | #define DIB3000MB_ELECT_OUT_MODE_ON ( 1) | ||
341 | |||
342 | /* set the tuner i2c address */ | ||
343 | #define DIB3000MB_REG_TUNER ( 1089) | ||
344 | |||
345 | /* monitoring registers (read only) */ | ||
346 | |||
347 | /* agc loop locked (size: 1) */ | ||
348 | #define DIB3000MB_REG_AGC_LOCK ( 324) | ||
349 | |||
350 | /* agc power (size: 16) */ | ||
351 | #define DIB3000MB_REG_AGC_POWER ( 325) | ||
352 | |||
353 | /* agc1 value (16) */ | ||
354 | #define DIB3000MB_REG_AGC1_VALUE ( 326) | ||
355 | |||
356 | /* agc2 value (16) */ | ||
357 | #define DIB3000MB_REG_AGC2_VALUE ( 327) | ||
358 | |||
359 | /* total RF power (16), can be used for signal strength */ | ||
360 | #define DIB3000MB_REG_RF_POWER ( 328) | ||
361 | |||
362 | /* dds_frequency with offset (24) */ | ||
363 | #define DIB3000MB_REG_DDS_VALUE_MSB ( 339) | ||
364 | #define DIB3000MB_REG_DDS_VALUE_LSB ( 340) | ||
365 | |||
366 | /* timing offset signed (24) */ | ||
367 | #define DIB3000MB_REG_TIMING_OFFSET_MSB ( 341) | ||
368 | #define DIB3000MB_REG_TIMING_OFFSET_LSB ( 342) | ||
369 | |||
370 | /* fft start position (13) */ | ||
371 | #define DIB3000MB_REG_FFT_WINDOW_POS ( 353) | ||
372 | |||
373 | /* carriers locked (1) */ | ||
374 | #define DIB3000MB_REG_CARRIER_LOCK ( 355) | ||
375 | |||
376 | /* noise power (24) */ | ||
377 | #define DIB3000MB_REG_NOISE_POWER_MSB ( 372) | ||
378 | #define DIB3000MB_REG_NOISE_POWER_LSB ( 373) | ||
379 | |||
380 | #define DIB3000MB_REG_MOBILE_NOISE_MSB ( 374) | ||
381 | #define DIB3000MB_REG_MOBILE_NOISE_LSB ( 375) | ||
382 | |||
383 | /* | ||
384 | * signal power (16), this and the above can be | ||
385 | * used to calculate the signal/noise - ratio | ||
386 | */ | ||
387 | #define DIB3000MB_REG_SIGNAL_POWER ( 380) | ||
388 | |||
389 | /* mer (24) */ | ||
390 | #define DIB3000MB_REG_MER_MSB ( 381) | ||
391 | #define DIB3000MB_REG_MER_LSB ( 382) | ||
392 | |||
393 | /* | ||
394 | * Transmission Parameter Signalling (TPS) | ||
395 | * the following registers can be used to get TPS-information. | ||
396 | * The values are according to the DVB-T standard. | ||
397 | */ | ||
398 | |||
399 | /* TPS locked (1) */ | ||
400 | #define DIB3000MB_REG_TPS_LOCK ( 394) | ||
401 | |||
402 | /* QAM from TPS (2) (values according to DIB3000MB_REG_QAM) */ | ||
403 | #define DIB3000MB_REG_TPS_QAM ( 398) | ||
404 | |||
405 | /* hierarchy from TPS (1) */ | ||
406 | #define DIB3000MB_REG_TPS_HRCH ( 399) | ||
407 | |||
408 | /* alpha from TPS (3) (values according to DIB3000MB_REG_VIT_ALPHA) */ | ||
409 | #define DIB3000MB_REG_TPS_VIT_ALPHA ( 400) | ||
410 | |||
411 | /* code rate high priority from TPS (3) (values according to DIB3000MB_FEC_*) */ | ||
412 | #define DIB3000MB_REG_TPS_CODE_RATE_HP ( 401) | ||
413 | |||
414 | /* code rate low priority from TPS (3) if DIB3000MB_REG_TPS_VIT_ALPHA */ | ||
415 | #define DIB3000MB_REG_TPS_CODE_RATE_LP ( 402) | ||
416 | |||
417 | /* guard time from TPS (2) (values according to DIB3000MB_REG_GUARD_TIME */ | ||
418 | #define DIB3000MB_REG_TPS_GUARD_TIME ( 403) | ||
419 | |||
420 | /* fft size from TPS (2) (values according to DIB3000MB_REG_FFT) */ | ||
421 | #define DIB3000MB_REG_TPS_FFT ( 404) | ||
422 | |||
423 | /* cell id from TPS (16) */ | ||
424 | #define DIB3000MB_REG_TPS_CELL_ID ( 406) | ||
425 | |||
426 | /* TPS (68) */ | ||
427 | #define DIB3000MB_REG_TPS_1 ( 408) | ||
428 | #define DIB3000MB_REG_TPS_2 ( 409) | ||
429 | #define DIB3000MB_REG_TPS_3 ( 410) | ||
430 | #define DIB3000MB_REG_TPS_4 ( 411) | ||
431 | #define DIB3000MB_REG_TPS_5 ( 412) | ||
432 | |||
433 | /* bit error rate (before RS correction) (21) */ | ||
434 | #define DIB3000MB_REG_BER_MSB ( 414) | ||
435 | #define DIB3000MB_REG_BER_LSB ( 415) | ||
436 | |||
437 | /* packet error rate (uncorrected TS packets) (16) */ | ||
438 | #define DIB3000MB_REG_PACKET_ERROR_RATE ( 417) | ||
439 | |||
440 | /* uncorrected packet count (16) */ | ||
441 | #define DIB3000MB_REG_UNC ( 420) | ||
442 | |||
443 | /* viterbi locked (1) */ | ||
444 | #define DIB3000MB_REG_VIT_LCK ( 421) | ||
445 | |||
446 | /* viterbi inidcator (16) */ | ||
447 | #define DIB3000MB_REG_VIT_INDICATOR ( 422) | ||
448 | |||
449 | /* transport stream sync lock (1) */ | ||
450 | #define DIB3000MB_REG_TS_SYNC_LOCK ( 423) | ||
451 | |||
452 | /* transport stream RS lock (1) */ | ||
453 | #define DIB3000MB_REG_TS_RS_LOCK ( 424) | ||
454 | |||
455 | /* lock mask 0 value (1) */ | ||
456 | #define DIB3000MB_REG_LOCK0_VALUE ( 425) | ||
457 | |||
458 | /* lock mask 1 value (1) */ | ||
459 | #define DIB3000MB_REG_LOCK1_VALUE ( 426) | ||
460 | |||
461 | /* lock mask 2 value (1) */ | ||
462 | #define DIB3000MB_REG_LOCK2_VALUE ( 427) | ||
463 | |||
464 | /* interrupt pending for auto search */ | ||
465 | #define DIB3000MB_REG_AS_IRQ_PENDING ( 434) | ||
466 | |||
467 | #endif | ||
diff --git a/drivers/media/dvb/frontends/dib3000mc.c b/drivers/media/dvb/frontends/dib3000mc.c new file mode 100644 index 000000000000..4a31c05eaecd --- /dev/null +++ b/drivers/media/dvb/frontends/dib3000mc.c | |||
@@ -0,0 +1,931 @@ | |||
1 | /* | ||
2 | * Frontend driver for mobile DVB-T demodulator DiBcom 3000P/M-C | ||
3 | * DiBcom (http://www.dibcom.fr/) | ||
4 | * | ||
5 | * Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de) | ||
6 | * | ||
7 | * based on GPL code from DiBCom, which has | ||
8 | * | ||
9 | * Copyright (C) 2004 Amaury Demol for DiBcom (ademol@dibcom.fr) | ||
10 | * | ||
11 | * This program is free software; you can redistribute it and/or | ||
12 | * modify it under the terms of the GNU General Public License as | ||
13 | * published by the Free Software Foundation, version 2. | ||
14 | * | ||
15 | * Acknowledgements | ||
16 | * | ||
17 | * Amaury Demol (ademol@dibcom.fr) from DiBcom for providing specs and driver | ||
18 | * sources, on which this driver (and the dvb-dibusb) are based. | ||
19 | * | ||
20 | * see Documentation/dvb/README.dibusb for more information | ||
21 | * | ||
22 | */ | ||
23 | #include <linux/config.h> | ||
24 | #include <linux/kernel.h> | ||
25 | #include <linux/version.h> | ||
26 | #include <linux/module.h> | ||
27 | #include <linux/moduleparam.h> | ||
28 | #include <linux/init.h> | ||
29 | #include <linux/delay.h> | ||
30 | |||
31 | #include "dib3000-common.h" | ||
32 | #include "dib3000mc_priv.h" | ||
33 | #include "dib3000.h" | ||
34 | |||
35 | /* Version information */ | ||
36 | #define DRIVER_VERSION "0.1" | ||
37 | #define DRIVER_DESC "DiBcom 3000M-C DVB-T demodulator" | ||
38 | #define DRIVER_AUTHOR "Patrick Boettcher, patrick.boettcher@desy.de" | ||
39 | |||
40 | #ifdef CONFIG_DVB_DIBCOM_DEBUG | ||
41 | static int debug; | ||
42 | module_param(debug, int, 0644); | ||
43 | MODULE_PARM_DESC(debug, "set debugging level (1=info,2=xfer,4=setfe,8=getfe,16=stat (|-able))."); | ||
44 | #endif | ||
45 | #define deb_info(args...) dprintk(0x01,args) | ||
46 | #define deb_xfer(args...) dprintk(0x02,args) | ||
47 | #define deb_setf(args...) dprintk(0x04,args) | ||
48 | #define deb_getf(args...) dprintk(0x08,args) | ||
49 | #define deb_stat(args...) dprintk(0x10,args) | ||
50 | |||
51 | static int dib3000mc_tuner_pass_ctrl(struct dvb_frontend *fe, int onoff, u8 pll_addr); | ||
52 | |||
53 | static int dib3000mc_set_impulse_noise(struct dib3000_state * state, int mode, | ||
54 | fe_transmit_mode_t transmission_mode, fe_bandwidth_t bandwidth) | ||
55 | { | ||
56 | switch (transmission_mode) { | ||
57 | case TRANSMISSION_MODE_2K: | ||
58 | wr_foreach(dib3000mc_reg_fft,dib3000mc_fft_modes[0]); | ||
59 | break; | ||
60 | case TRANSMISSION_MODE_8K: | ||
61 | wr_foreach(dib3000mc_reg_fft,dib3000mc_fft_modes[1]); | ||
62 | break; | ||
63 | default: | ||
64 | break; | ||
65 | } | ||
66 | |||
67 | switch (bandwidth) { | ||
68 | /* case BANDWIDTH_5_MHZ: | ||
69 | wr_foreach(dib3000mc_reg_impulse_noise,dib3000mc_impluse_noise[0]); | ||
70 | break; */ | ||
71 | case BANDWIDTH_6_MHZ: | ||
72 | wr_foreach(dib3000mc_reg_impulse_noise,dib3000mc_impluse_noise[1]); | ||
73 | break; | ||
74 | case BANDWIDTH_7_MHZ: | ||
75 | wr_foreach(dib3000mc_reg_impulse_noise,dib3000mc_impluse_noise[2]); | ||
76 | break; | ||
77 | case BANDWIDTH_8_MHZ: | ||
78 | wr_foreach(dib3000mc_reg_impulse_noise,dib3000mc_impluse_noise[3]); | ||
79 | break; | ||
80 | default: | ||
81 | break; | ||
82 | } | ||
83 | |||
84 | switch (mode) { | ||
85 | case 0: /* no impulse */ /* fall through */ | ||
86 | wr_foreach(dib3000mc_reg_imp_noise_ctl,dib3000mc_imp_noise_ctl[0]); | ||
87 | break; | ||
88 | case 1: /* new algo */ | ||
89 | wr_foreach(dib3000mc_reg_imp_noise_ctl,dib3000mc_imp_noise_ctl[1]); | ||
90 | set_or(DIB3000MC_REG_IMP_NOISE_55,DIB3000MC_IMP_NEW_ALGO(0)); /* gives 1<<10 */ | ||
91 | break; | ||
92 | default: /* old algo */ | ||
93 | wr_foreach(dib3000mc_reg_imp_noise_ctl,dib3000mc_imp_noise_ctl[3]); | ||
94 | break; | ||
95 | } | ||
96 | return 0; | ||
97 | } | ||
98 | |||
99 | static int dib3000mc_set_timing(struct dib3000_state *state, int upd_offset, | ||
100 | fe_transmit_mode_t fft, fe_bandwidth_t bw) | ||
101 | { | ||
102 | u16 timf_msb,timf_lsb; | ||
103 | s32 tim_offset,tim_sgn; | ||
104 | u64 comp1,comp2,comp=0; | ||
105 | |||
106 | switch (bw) { | ||
107 | case BANDWIDTH_8_MHZ: comp = DIB3000MC_CLOCK_REF*8; break; | ||
108 | case BANDWIDTH_7_MHZ: comp = DIB3000MC_CLOCK_REF*7; break; | ||
109 | case BANDWIDTH_6_MHZ: comp = DIB3000MC_CLOCK_REF*6; break; | ||
110 | default: err("unknown bandwidth (%d)",bw); break; | ||
111 | } | ||
112 | timf_msb = (comp >> 16) & 0xff; | ||
113 | timf_lsb = (comp & 0xffff); | ||
114 | |||
115 | // Update the timing offset ; | ||
116 | if (upd_offset > 0) { | ||
117 | if (!state->timing_offset_comp_done) { | ||
118 | msleep(200); | ||
119 | state->timing_offset_comp_done = 1; | ||
120 | } | ||
121 | tim_offset = rd(DIB3000MC_REG_TIMING_OFFS_MSB); | ||
122 | if ((tim_offset & 0x2000) == 0x2000) | ||
123 | tim_offset |= 0xC000; | ||
124 | if (fft == TRANSMISSION_MODE_2K) | ||
125 | tim_offset <<= 2; | ||
126 | state->timing_offset += tim_offset; | ||
127 | } | ||
128 | |||
129 | tim_offset = state->timing_offset; | ||
130 | if (tim_offset < 0) { | ||
131 | tim_sgn = 1; | ||
132 | tim_offset = -tim_offset; | ||
133 | } else | ||
134 | tim_sgn = 0; | ||
135 | |||
136 | comp1 = (u32)tim_offset * (u32)timf_lsb ; | ||
137 | comp2 = (u32)tim_offset * (u32)timf_msb ; | ||
138 | comp = ((comp1 >> 16) + comp2) >> 7; | ||
139 | |||
140 | if (tim_sgn == 0) | ||
141 | comp = (u32)(timf_msb << 16) + (u32) timf_lsb + comp; | ||
142 | else | ||
143 | comp = (u32)(timf_msb << 16) + (u32) timf_lsb - comp ; | ||
144 | |||
145 | timf_msb = (comp >> 16) & 0xff; | ||
146 | timf_lsb = comp & 0xffff; | ||
147 | |||
148 | wr(DIB3000MC_REG_TIMING_FREQ_MSB,timf_msb); | ||
149 | wr(DIB3000MC_REG_TIMING_FREQ_LSB,timf_lsb); | ||
150 | return 0; | ||
151 | } | ||
152 | |||
153 | static int dib3000mc_init_auto_scan(struct dib3000_state *state, fe_bandwidth_t bw, int boost) | ||
154 | { | ||
155 | if (boost) { | ||
156 | wr(DIB3000MC_REG_SCAN_BOOST,DIB3000MC_SCAN_BOOST_ON); | ||
157 | } else { | ||
158 | wr(DIB3000MC_REG_SCAN_BOOST,DIB3000MC_SCAN_BOOST_OFF); | ||
159 | } | ||
160 | switch (bw) { | ||
161 | case BANDWIDTH_8_MHZ: | ||
162 | wr_foreach(dib3000mc_reg_bandwidth,dib3000mc_bandwidth_8mhz); | ||
163 | break; | ||
164 | case BANDWIDTH_7_MHZ: | ||
165 | wr_foreach(dib3000mc_reg_bandwidth,dib3000mc_bandwidth_7mhz); | ||
166 | break; | ||
167 | case BANDWIDTH_6_MHZ: | ||
168 | wr_foreach(dib3000mc_reg_bandwidth,dib3000mc_bandwidth_6mhz); | ||
169 | break; | ||
170 | /* case BANDWIDTH_5_MHZ: | ||
171 | wr_foreach(dib3000mc_reg_bandwidth,dib3000mc_bandwidth_5mhz); | ||
172 | break;*/ | ||
173 | case BANDWIDTH_AUTO: | ||
174 | return -EOPNOTSUPP; | ||
175 | default: | ||
176 | err("unknown bandwidth value (%d).",bw); | ||
177 | return -EINVAL; | ||
178 | } | ||
179 | if (boost) { | ||
180 | u32 timeout = (rd(DIB3000MC_REG_BW_TIMOUT_MSB) << 16) + | ||
181 | rd(DIB3000MC_REG_BW_TIMOUT_LSB); | ||
182 | timeout *= 85; timeout >>= 7; | ||
183 | wr(DIB3000MC_REG_BW_TIMOUT_MSB,(timeout >> 16) & 0xffff); | ||
184 | wr(DIB3000MC_REG_BW_TIMOUT_LSB,timeout & 0xffff); | ||
185 | } | ||
186 | return 0; | ||
187 | } | ||
188 | |||
189 | static int dib3000mc_set_adp_cfg(struct dib3000_state *state, fe_modulation_t con) | ||
190 | { | ||
191 | switch (con) { | ||
192 | case QAM_64: | ||
193 | wr_foreach(dib3000mc_reg_adp_cfg,dib3000mc_adp_cfg[2]); | ||
194 | break; | ||
195 | case QAM_16: | ||
196 | wr_foreach(dib3000mc_reg_adp_cfg,dib3000mc_adp_cfg[1]); | ||
197 | break; | ||
198 | case QPSK: | ||
199 | wr_foreach(dib3000mc_reg_adp_cfg,dib3000mc_adp_cfg[0]); | ||
200 | break; | ||
201 | case QAM_AUTO: | ||
202 | break; | ||
203 | default: | ||
204 | warn("unkown constellation."); | ||
205 | break; | ||
206 | } | ||
207 | return 0; | ||
208 | } | ||
209 | |||
210 | static int dib3000mc_set_general_cfg(struct dib3000_state *state, struct dvb_frontend_parameters *fep, int *auto_val) | ||
211 | { | ||
212 | struct dvb_ofdm_parameters *ofdm = &fep->u.ofdm; | ||
213 | fe_code_rate_t fe_cr = FEC_NONE; | ||
214 | u8 fft=0, guard=0, qam=0, alpha=0, sel_hp=0, cr=0, hrch=0; | ||
215 | int seq; | ||
216 | |||
217 | switch (ofdm->transmission_mode) { | ||
218 | case TRANSMISSION_MODE_2K: fft = DIB3000_TRANSMISSION_MODE_2K; break; | ||
219 | case TRANSMISSION_MODE_8K: fft = DIB3000_TRANSMISSION_MODE_8K; break; | ||
220 | case TRANSMISSION_MODE_AUTO: break; | ||
221 | default: return -EINVAL; | ||
222 | } | ||
223 | switch (ofdm->guard_interval) { | ||
224 | case GUARD_INTERVAL_1_32: guard = DIB3000_GUARD_TIME_1_32; break; | ||
225 | case GUARD_INTERVAL_1_16: guard = DIB3000_GUARD_TIME_1_16; break; | ||
226 | case GUARD_INTERVAL_1_8: guard = DIB3000_GUARD_TIME_1_8; break; | ||
227 | case GUARD_INTERVAL_1_4: guard = DIB3000_GUARD_TIME_1_4; break; | ||
228 | case GUARD_INTERVAL_AUTO: break; | ||
229 | default: return -EINVAL; | ||
230 | } | ||
231 | switch (ofdm->constellation) { | ||
232 | case QPSK: qam = DIB3000_CONSTELLATION_QPSK; break; | ||
233 | case QAM_16: qam = DIB3000_CONSTELLATION_16QAM; break; | ||
234 | case QAM_64: qam = DIB3000_CONSTELLATION_64QAM; break; | ||
235 | case QAM_AUTO: break; | ||
236 | default: return -EINVAL; | ||
237 | } | ||
238 | switch (ofdm->hierarchy_information) { | ||
239 | case HIERARCHY_NONE: /* fall through */ | ||
240 | case HIERARCHY_1: alpha = DIB3000_ALPHA_1; break; | ||
241 | case HIERARCHY_2: alpha = DIB3000_ALPHA_2; break; | ||
242 | case HIERARCHY_4: alpha = DIB3000_ALPHA_4; break; | ||
243 | case HIERARCHY_AUTO: break; | ||
244 | default: return -EINVAL; | ||
245 | } | ||
246 | if (ofdm->hierarchy_information == HIERARCHY_NONE) { | ||
247 | hrch = DIB3000_HRCH_OFF; | ||
248 | sel_hp = DIB3000_SELECT_HP; | ||
249 | fe_cr = ofdm->code_rate_HP; | ||
250 | } else if (ofdm->hierarchy_information != HIERARCHY_AUTO) { | ||
251 | hrch = DIB3000_HRCH_ON; | ||
252 | sel_hp = DIB3000_SELECT_LP; | ||
253 | fe_cr = ofdm->code_rate_LP; | ||
254 | } | ||
255 | switch (fe_cr) { | ||
256 | case FEC_1_2: cr = DIB3000_FEC_1_2; break; | ||
257 | case FEC_2_3: cr = DIB3000_FEC_2_3; break; | ||
258 | case FEC_3_4: cr = DIB3000_FEC_3_4; break; | ||
259 | case FEC_5_6: cr = DIB3000_FEC_5_6; break; | ||
260 | case FEC_7_8: cr = DIB3000_FEC_7_8; break; | ||
261 | case FEC_NONE: break; | ||
262 | case FEC_AUTO: break; | ||
263 | default: return -EINVAL; | ||
264 | } | ||
265 | |||
266 | wr(DIB3000MC_REG_DEMOD_PARM,DIB3000MC_DEMOD_PARM(alpha,qam,guard,fft)); | ||
267 | wr(DIB3000MC_REG_HRCH_PARM,DIB3000MC_HRCH_PARM(sel_hp,cr,hrch)); | ||
268 | |||
269 | switch (fep->inversion) { | ||
270 | case INVERSION_OFF: | ||
271 | wr(DIB3000MC_REG_SET_DDS_FREQ_MSB,DIB3000MC_DDS_FREQ_MSB_INV_OFF); | ||
272 | break; | ||
273 | case INVERSION_AUTO: /* fall through */ | ||
274 | case INVERSION_ON: | ||
275 | wr(DIB3000MC_REG_SET_DDS_FREQ_MSB,DIB3000MC_DDS_FREQ_MSB_INV_ON); | ||
276 | break; | ||
277 | default: | ||
278 | return -EINVAL; | ||
279 | } | ||
280 | |||
281 | seq = dib3000_seq | ||
282 | [ofdm->transmission_mode == TRANSMISSION_MODE_AUTO] | ||
283 | [ofdm->guard_interval == GUARD_INTERVAL_AUTO] | ||
284 | [fep->inversion == INVERSION_AUTO]; | ||
285 | |||
286 | deb_setf("seq? %d\n", seq); | ||
287 | wr(DIB3000MC_REG_SEQ_TPS,DIB3000MC_SEQ_TPS(seq,1)); | ||
288 | *auto_val = ofdm->constellation == QAM_AUTO || | ||
289 | ofdm->hierarchy_information == HIERARCHY_AUTO || | ||
290 | ofdm->guard_interval == GUARD_INTERVAL_AUTO || | ||
291 | ofdm->transmission_mode == TRANSMISSION_MODE_AUTO || | ||
292 | fe_cr == FEC_AUTO || | ||
293 | fep->inversion == INVERSION_AUTO; | ||
294 | return 0; | ||
295 | } | ||
296 | |||
297 | static int dib3000mc_get_frontend(struct dvb_frontend* fe, | ||
298 | struct dvb_frontend_parameters *fep) | ||
299 | { | ||
300 | struct dib3000_state* state = (struct dib3000_state*) fe->demodulator_priv; | ||
301 | struct dvb_ofdm_parameters *ofdm = &fep->u.ofdm; | ||
302 | fe_code_rate_t *cr; | ||
303 | u16 tps_val,cr_val; | ||
304 | int inv_test1,inv_test2; | ||
305 | u32 dds_val, threshold = 0x1000000; | ||
306 | |||
307 | if (!(rd(DIB3000MC_REG_LOCK_507) & DIB3000MC_LOCK_507)) | ||
308 | return 0; | ||
309 | |||
310 | dds_val = (rd(DIB3000MC_REG_DDS_FREQ_MSB) << 16) + rd(DIB3000MC_REG_DDS_FREQ_LSB); | ||
311 | deb_getf("DDS_FREQ: %6x\n",dds_val); | ||
312 | if (dds_val < threshold) | ||
313 | inv_test1 = 0; | ||
314 | else if (dds_val == threshold) | ||
315 | inv_test1 = 1; | ||
316 | else | ||
317 | inv_test1 = 2; | ||
318 | |||
319 | dds_val = (rd(DIB3000MC_REG_SET_DDS_FREQ_MSB) << 16) + rd(DIB3000MC_REG_SET_DDS_FREQ_LSB); | ||
320 | deb_getf("DDS_SET_FREQ: %6x\n",dds_val); | ||
321 | if (dds_val < threshold) | ||
322 | inv_test2 = 0; | ||
323 | else if (dds_val == threshold) | ||
324 | inv_test2 = 1; | ||
325 | else | ||
326 | inv_test2 = 2; | ||
327 | |||
328 | fep->inversion = | ||
329 | ((inv_test2 == 2) && (inv_test1==1 || inv_test1==0)) || | ||
330 | ((inv_test2 == 0) && (inv_test1==1 || inv_test1==2)) ? | ||
331 | INVERSION_ON : INVERSION_OFF; | ||
332 | |||
333 | deb_getf("inversion %d %d, %d\n", inv_test2, inv_test1, fep->inversion); | ||
334 | |||
335 | fep->frequency = state->last_tuned_freq; | ||
336 | fep->u.ofdm.bandwidth= state->last_tuned_bw; | ||
337 | |||
338 | tps_val = rd(DIB3000MC_REG_TUNING_PARM); | ||
339 | |||
340 | switch (DIB3000MC_TP_QAM(tps_val)) { | ||
341 | case DIB3000_CONSTELLATION_QPSK: | ||
342 | deb_getf("QPSK "); | ||
343 | ofdm->constellation = QPSK; | ||
344 | break; | ||
345 | case DIB3000_CONSTELLATION_16QAM: | ||
346 | deb_getf("QAM16 "); | ||
347 | ofdm->constellation = QAM_16; | ||
348 | break; | ||
349 | case DIB3000_CONSTELLATION_64QAM: | ||
350 | deb_getf("QAM64 "); | ||
351 | ofdm->constellation = QAM_64; | ||
352 | break; | ||
353 | default: | ||
354 | err("Unexpected constellation returned by TPS (%d)", tps_val); | ||
355 | break; | ||
356 | } | ||
357 | |||
358 | if (DIB3000MC_TP_HRCH(tps_val)) { | ||
359 | deb_getf("HRCH ON "); | ||
360 | cr = &ofdm->code_rate_LP; | ||
361 | ofdm->code_rate_HP = FEC_NONE; | ||
362 | switch (DIB3000MC_TP_ALPHA(tps_val)) { | ||
363 | case DIB3000_ALPHA_0: | ||
364 | deb_getf("HIERARCHY_NONE "); | ||
365 | ofdm->hierarchy_information = HIERARCHY_NONE; | ||
366 | break; | ||
367 | case DIB3000_ALPHA_1: | ||
368 | deb_getf("HIERARCHY_1 "); | ||
369 | ofdm->hierarchy_information = HIERARCHY_1; | ||
370 | break; | ||
371 | case DIB3000_ALPHA_2: | ||
372 | deb_getf("HIERARCHY_2 "); | ||
373 | ofdm->hierarchy_information = HIERARCHY_2; | ||
374 | break; | ||
375 | case DIB3000_ALPHA_4: | ||
376 | deb_getf("HIERARCHY_4 "); | ||
377 | ofdm->hierarchy_information = HIERARCHY_4; | ||
378 | break; | ||
379 | default: | ||
380 | err("Unexpected ALPHA value returned by TPS (%d)", tps_val); | ||
381 | break; | ||
382 | } | ||
383 | cr_val = DIB3000MC_TP_FEC_CR_LP(tps_val); | ||
384 | } else { | ||
385 | deb_getf("HRCH OFF "); | ||
386 | cr = &ofdm->code_rate_HP; | ||
387 | ofdm->code_rate_LP = FEC_NONE; | ||
388 | ofdm->hierarchy_information = HIERARCHY_NONE; | ||
389 | cr_val = DIB3000MC_TP_FEC_CR_HP(tps_val); | ||
390 | } | ||
391 | |||
392 | switch (cr_val) { | ||
393 | case DIB3000_FEC_1_2: | ||
394 | deb_getf("FEC_1_2 "); | ||
395 | *cr = FEC_1_2; | ||
396 | break; | ||
397 | case DIB3000_FEC_2_3: | ||
398 | deb_getf("FEC_2_3 "); | ||
399 | *cr = FEC_2_3; | ||
400 | break; | ||
401 | case DIB3000_FEC_3_4: | ||
402 | deb_getf("FEC_3_4 "); | ||
403 | *cr = FEC_3_4; | ||
404 | break; | ||
405 | case DIB3000_FEC_5_6: | ||
406 | deb_getf("FEC_5_6 "); | ||
407 | *cr = FEC_4_5; | ||
408 | break; | ||
409 | case DIB3000_FEC_7_8: | ||
410 | deb_getf("FEC_7_8 "); | ||
411 | *cr = FEC_7_8; | ||
412 | break; | ||
413 | default: | ||
414 | err("Unexpected FEC returned by TPS (%d)", tps_val); | ||
415 | break; | ||
416 | } | ||
417 | |||
418 | switch (DIB3000MC_TP_GUARD(tps_val)) { | ||
419 | case DIB3000_GUARD_TIME_1_32: | ||
420 | deb_getf("GUARD_INTERVAL_1_32 "); | ||
421 | ofdm->guard_interval = GUARD_INTERVAL_1_32; | ||
422 | break; | ||
423 | case DIB3000_GUARD_TIME_1_16: | ||
424 | deb_getf("GUARD_INTERVAL_1_16 "); | ||
425 | ofdm->guard_interval = GUARD_INTERVAL_1_16; | ||
426 | break; | ||
427 | case DIB3000_GUARD_TIME_1_8: | ||
428 | deb_getf("GUARD_INTERVAL_1_8 "); | ||
429 | ofdm->guard_interval = GUARD_INTERVAL_1_8; | ||
430 | break; | ||
431 | case DIB3000_GUARD_TIME_1_4: | ||
432 | deb_getf("GUARD_INTERVAL_1_4 "); | ||
433 | ofdm->guard_interval = GUARD_INTERVAL_1_4; | ||
434 | break; | ||
435 | default: | ||
436 | err("Unexpected Guard Time returned by TPS (%d)", tps_val); | ||
437 | break; | ||
438 | } | ||
439 | |||
440 | switch (DIB3000MC_TP_FFT(tps_val)) { | ||
441 | case DIB3000_TRANSMISSION_MODE_2K: | ||
442 | deb_getf("TRANSMISSION_MODE_2K "); | ||
443 | ofdm->transmission_mode = TRANSMISSION_MODE_2K; | ||
444 | break; | ||
445 | case DIB3000_TRANSMISSION_MODE_8K: | ||
446 | deb_getf("TRANSMISSION_MODE_8K "); | ||
447 | ofdm->transmission_mode = TRANSMISSION_MODE_8K; | ||
448 | break; | ||
449 | default: | ||
450 | err("unexpected transmission mode return by TPS (%d)", tps_val); | ||
451 | break; | ||
452 | } | ||
453 | deb_getf("\n"); | ||
454 | |||
455 | return 0; | ||
456 | } | ||
457 | |||
458 | static int dib3000mc_set_frontend(struct dvb_frontend* fe, | ||
459 | struct dvb_frontend_parameters *fep, int tuner) | ||
460 | { | ||
461 | struct dib3000_state* state = (struct dib3000_state*) fe->demodulator_priv; | ||
462 | struct dvb_ofdm_parameters *ofdm = &fep->u.ofdm; | ||
463 | int search_state,auto_val; | ||
464 | u16 val; | ||
465 | |||
466 | if (tuner) { /* initial call from dvb */ | ||
467 | dib3000mc_tuner_pass_ctrl(fe,1,state->config.pll_addr(fe)); | ||
468 | state->config.pll_set(fe,fep,NULL); | ||
469 | dib3000mc_tuner_pass_ctrl(fe,0,state->config.pll_addr(fe)); | ||
470 | |||
471 | state->last_tuned_freq = fep->frequency; | ||
472 | // if (!scanboost) { | ||
473 | dib3000mc_set_timing(state,0,ofdm->transmission_mode,ofdm->bandwidth); | ||
474 | dib3000mc_init_auto_scan(state, ofdm->bandwidth, 0); | ||
475 | state->last_tuned_bw = ofdm->bandwidth; | ||
476 | |||
477 | wr_foreach(dib3000mc_reg_agc_bandwidth,dib3000mc_agc_bandwidth); | ||
478 | wr(DIB3000MC_REG_RESTART,DIB3000MC_RESTART_AGC); | ||
479 | wr(DIB3000MC_REG_RESTART,DIB3000MC_RESTART_OFF); | ||
480 | |||
481 | /* Default cfg isi offset adp */ | ||
482 | wr_foreach(dib3000mc_reg_offset,dib3000mc_offset[0]); | ||
483 | |||
484 | wr(DIB3000MC_REG_ISI,DIB3000MC_ISI_DEFAULT | DIB3000MC_ISI_INHIBIT); | ||
485 | dib3000mc_set_adp_cfg(state,ofdm->constellation); | ||
486 | wr(DIB3000MC_REG_UNK_133,DIB3000MC_UNK_133); | ||
487 | |||
488 | wr_foreach(dib3000mc_reg_bandwidth_general,dib3000mc_bandwidth_general); | ||
489 | /* power smoothing */ | ||
490 | if (ofdm->bandwidth != BANDWIDTH_8_MHZ) { | ||
491 | wr_foreach(dib3000mc_reg_bw,dib3000mc_bw[0]); | ||
492 | } else { | ||
493 | wr_foreach(dib3000mc_reg_bw,dib3000mc_bw[3]); | ||
494 | } | ||
495 | auto_val = 0; | ||
496 | dib3000mc_set_general_cfg(state,fep,&auto_val); | ||
497 | dib3000mc_set_impulse_noise(state,0,ofdm->constellation,ofdm->bandwidth); | ||
498 | |||
499 | val = rd(DIB3000MC_REG_DEMOD_PARM); | ||
500 | wr(DIB3000MC_REG_DEMOD_PARM,val|DIB3000MC_DEMOD_RST_DEMOD_ON); | ||
501 | wr(DIB3000MC_REG_DEMOD_PARM,val); | ||
502 | // } | ||
503 | msleep(70); | ||
504 | |||
505 | /* something has to be auto searched */ | ||
506 | if (auto_val) { | ||
507 | int as_count=0; | ||
508 | |||
509 | deb_setf("autosearch enabled.\n"); | ||
510 | |||
511 | val = rd(DIB3000MC_REG_DEMOD_PARM); | ||
512 | wr(DIB3000MC_REG_DEMOD_PARM,val | DIB3000MC_DEMOD_RST_AUTO_SRCH_ON); | ||
513 | wr(DIB3000MC_REG_DEMOD_PARM,val); | ||
514 | |||
515 | while ((search_state = dib3000_search_status( | ||
516 | rd(DIB3000MC_REG_AS_IRQ),1)) < 0 && as_count++ < 100) | ||
517 | msleep(10); | ||
518 | |||
519 | deb_info("search_state after autosearch %d after %d checks\n",search_state,as_count); | ||
520 | |||
521 | if (search_state == 1) { | ||
522 | struct dvb_frontend_parameters feps; | ||
523 | if (dib3000mc_get_frontend(fe, &feps) == 0) { | ||
524 | deb_setf("reading tuning data from frontend succeeded.\n"); | ||
525 | return dib3000mc_set_frontend(fe, &feps, 0); | ||
526 | } | ||
527 | } | ||
528 | } else { | ||
529 | dib3000mc_set_impulse_noise(state,0,ofdm->transmission_mode,ofdm->bandwidth); | ||
530 | wr(DIB3000MC_REG_ISI,DIB3000MC_ISI_DEFAULT|DIB3000MC_ISI_ACTIVATE); | ||
531 | dib3000mc_set_adp_cfg(state,ofdm->constellation); | ||
532 | |||
533 | /* set_offset_cfg */ | ||
534 | wr_foreach(dib3000mc_reg_offset, | ||
535 | dib3000mc_offset[(ofdm->transmission_mode == TRANSMISSION_MODE_8K)+1]); | ||
536 | } | ||
537 | } else { /* second call, after autosearch (fka: set_WithKnownParams) */ | ||
538 | // dib3000mc_set_timing(state,1,ofdm->transmission_mode,ofdm->bandwidth); | ||
539 | |||
540 | auto_val = 0; | ||
541 | dib3000mc_set_general_cfg(state,fep,&auto_val); | ||
542 | if (auto_val) | ||
543 | deb_info("auto_val is true, even though an auto search was already performed.\n"); | ||
544 | |||
545 | dib3000mc_set_impulse_noise(state,0,ofdm->constellation,ofdm->bandwidth); | ||
546 | |||
547 | val = rd(DIB3000MC_REG_DEMOD_PARM); | ||
548 | wr(DIB3000MC_REG_DEMOD_PARM,val | DIB3000MC_DEMOD_RST_AUTO_SRCH_ON); | ||
549 | wr(DIB3000MC_REG_DEMOD_PARM,val); | ||
550 | |||
551 | msleep(30); | ||
552 | |||
553 | wr(DIB3000MC_REG_ISI,DIB3000MC_ISI_DEFAULT|DIB3000MC_ISI_ACTIVATE); | ||
554 | dib3000mc_set_adp_cfg(state,ofdm->constellation); | ||
555 | wr_foreach(dib3000mc_reg_offset, | ||
556 | dib3000mc_offset[(ofdm->transmission_mode == TRANSMISSION_MODE_8K)+1]); | ||
557 | |||
558 | |||
559 | } | ||
560 | return 0; | ||
561 | } | ||
562 | |||
563 | static int dib3000mc_fe_init(struct dvb_frontend* fe, int mobile_mode) | ||
564 | { | ||
565 | struct dib3000_state *state; | ||
566 | |||
567 | deb_info("init start\n"); | ||
568 | |||
569 | state = fe->demodulator_priv; | ||
570 | state->timing_offset = 0; | ||
571 | state->timing_offset_comp_done = 0; | ||
572 | |||
573 | wr(DIB3000MC_REG_RESTART,DIB3000MC_RESTART_CONFIG); | ||
574 | wr(DIB3000MC_REG_RESTART,DIB3000MC_RESTART_OFF); | ||
575 | wr(DIB3000MC_REG_CLK_CFG_1,DIB3000MC_CLK_CFG_1_POWER_UP); | ||
576 | wr(DIB3000MC_REG_CLK_CFG_2,DIB3000MC_CLK_CFG_2_PUP_MOBILE); | ||
577 | wr(DIB3000MC_REG_CLK_CFG_3,DIB3000MC_CLK_CFG_3_POWER_UP); | ||
578 | wr(DIB3000MC_REG_CLK_CFG_7,DIB3000MC_CLK_CFG_7_INIT); | ||
579 | |||
580 | wr(DIB3000MC_REG_RST_UNC,DIB3000MC_RST_UNC_OFF); | ||
581 | wr(DIB3000MC_REG_UNK_19,DIB3000MC_UNK_19); | ||
582 | |||
583 | wr(33,5); | ||
584 | wr(36,81); | ||
585 | wr(DIB3000MC_REG_UNK_88,DIB3000MC_UNK_88); | ||
586 | |||
587 | wr(DIB3000MC_REG_UNK_99,DIB3000MC_UNK_99); | ||
588 | wr(DIB3000MC_REG_UNK_111,DIB3000MC_UNK_111_PH_N_MODE_0); /* phase noise algo off */ | ||
589 | |||
590 | /* mobile mode - portable reception */ | ||
591 | wr_foreach(dib3000mc_reg_mobile_mode,dib3000mc_mobile_mode[1]); | ||
592 | |||
593 | /* TUNER_PANASONIC_ENV57H12D5: */ | ||
594 | wr_foreach(dib3000mc_reg_agc_bandwidth,dib3000mc_agc_bandwidth); | ||
595 | wr_foreach(dib3000mc_reg_agc_bandwidth_general,dib3000mc_agc_bandwidth_general); | ||
596 | wr_foreach(dib3000mc_reg_agc,dib3000mc_agc_tuner[1]); | ||
597 | |||
598 | wr(DIB3000MC_REG_UNK_110,DIB3000MC_UNK_110); | ||
599 | wr(26,0x6680); | ||
600 | wr(DIB3000MC_REG_UNK_1,DIB3000MC_UNK_1); | ||
601 | wr(DIB3000MC_REG_UNK_2,DIB3000MC_UNK_2); | ||
602 | wr(DIB3000MC_REG_UNK_3,DIB3000MC_UNK_3); | ||
603 | wr(DIB3000MC_REG_SEQ_TPS,DIB3000MC_SEQ_TPS_DEFAULT); | ||
604 | |||
605 | wr_foreach(dib3000mc_reg_bandwidth,dib3000mc_bandwidth_8mhz); | ||
606 | wr_foreach(dib3000mc_reg_bandwidth_general,dib3000mc_bandwidth_general); | ||
607 | |||
608 | wr(DIB3000MC_REG_UNK_4,DIB3000MC_UNK_4); | ||
609 | |||
610 | wr(DIB3000MC_REG_SET_DDS_FREQ_MSB,DIB3000MC_DDS_FREQ_MSB_INV_OFF); | ||
611 | wr(DIB3000MC_REG_SET_DDS_FREQ_LSB,DIB3000MC_DDS_FREQ_LSB); | ||
612 | |||
613 | dib3000mc_set_timing(state,0,TRANSMISSION_MODE_8K,BANDWIDTH_8_MHZ); | ||
614 | // wr_foreach(dib3000mc_reg_timing_freq,dib3000mc_timing_freq[3]); | ||
615 | |||
616 | wr(DIB3000MC_REG_UNK_120,DIB3000MC_UNK_120); | ||
617 | wr(DIB3000MC_REG_UNK_134,DIB3000MC_UNK_134); | ||
618 | wr(DIB3000MC_REG_FEC_CFG,DIB3000MC_FEC_CFG); | ||
619 | |||
620 | wr(DIB3000MC_REG_DIVERSITY3,DIB3000MC_DIVERSITY3_IN_OFF); | ||
621 | |||
622 | dib3000mc_set_impulse_noise(state,0,TRANSMISSION_MODE_8K,BANDWIDTH_8_MHZ); | ||
623 | |||
624 | /* output mode control, just the MPEG2_SLAVE */ | ||
625 | // set_or(DIB3000MC_REG_OUTMODE,DIB3000MC_OM_SLAVE); | ||
626 | wr(DIB3000MC_REG_OUTMODE,DIB3000MC_OM_SLAVE); | ||
627 | wr(DIB3000MC_REG_SMO_MODE,DIB3000MC_SMO_MODE_SLAVE); | ||
628 | wr(DIB3000MC_REG_FIFO_THRESHOLD,DIB3000MC_FIFO_THRESHOLD_SLAVE); | ||
629 | wr(DIB3000MC_REG_ELEC_OUT,DIB3000MC_ELEC_OUT_SLAVE); | ||
630 | |||
631 | /* MPEG2_PARALLEL_CONTINUOUS_CLOCK | ||
632 | wr(DIB3000MC_REG_OUTMODE, | ||
633 | DIB3000MC_SET_OUTMODE(DIB3000MC_OM_PAR_CONT_CLK, | ||
634 | rd(DIB3000MC_REG_OUTMODE))); | ||
635 | |||
636 | wr(DIB3000MC_REG_SMO_MODE, | ||
637 | DIB3000MC_SMO_MODE_DEFAULT | | ||
638 | DIB3000MC_SMO_MODE_188); | ||
639 | |||
640 | wr(DIB3000MC_REG_FIFO_THRESHOLD,DIB3000MC_FIFO_THRESHOLD_DEFAULT); | ||
641 | wr(DIB3000MC_REG_ELEC_OUT,DIB3000MC_ELEC_OUT_DIV_OUT_ON); | ||
642 | */ | ||
643 | |||
644 | /* diversity */ | ||
645 | wr(DIB3000MC_REG_DIVERSITY1,DIB3000MC_DIVERSITY1_DEFAULT); | ||
646 | wr(DIB3000MC_REG_DIVERSITY2,DIB3000MC_DIVERSITY2_DEFAULT); | ||
647 | |||
648 | set_and(DIB3000MC_REG_DIVERSITY3,DIB3000MC_DIVERSITY3_IN_OFF); | ||
649 | |||
650 | set_or(DIB3000MC_REG_CLK_CFG_7,DIB3000MC_CLK_CFG_7_DIV_IN_OFF); | ||
651 | |||
652 | /* if (state->config->pll_init) { | ||
653 | dib3000mc_tuner_pass_ctrl(fe,1,state->config.pll_addr(fe)); | ||
654 | state->config->pll_init(fe,NULL); | ||
655 | dib3000mc_tuner_pass_ctrl(fe,0,state->config.pll_addr(fe)); | ||
656 | }*/ | ||
657 | deb_info("init end\n"); | ||
658 | return 0; | ||
659 | } | ||
660 | static int dib3000mc_read_status(struct dvb_frontend* fe, fe_status_t *stat) | ||
661 | { | ||
662 | struct dib3000_state* state = (struct dib3000_state*) fe->demodulator_priv; | ||
663 | u16 lock = rd(DIB3000MC_REG_LOCKING); | ||
664 | |||
665 | *stat = 0; | ||
666 | if (DIB3000MC_AGC_LOCK(lock)) | ||
667 | *stat |= FE_HAS_SIGNAL; | ||
668 | if (DIB3000MC_CARRIER_LOCK(lock)) | ||
669 | *stat |= FE_HAS_CARRIER; | ||
670 | if (DIB3000MC_TPS_LOCK(lock)) | ||
671 | *stat |= FE_HAS_VITERBI; | ||
672 | if (DIB3000MC_MPEG_SYNC_LOCK(lock)) | ||
673 | *stat |= (FE_HAS_SYNC | FE_HAS_LOCK); | ||
674 | |||
675 | deb_stat("actual status is %2x fifo_level: %x,244: %x, 206: %x, 207: %x, 1040: %x\n",*stat,rd(510),rd(244),rd(206),rd(207),rd(1040)); | ||
676 | |||
677 | return 0; | ||
678 | } | ||
679 | |||
680 | static int dib3000mc_read_ber(struct dvb_frontend* fe, u32 *ber) | ||
681 | { | ||
682 | struct dib3000_state* state = (struct dib3000_state*) fe->demodulator_priv; | ||
683 | *ber = ((rd(DIB3000MC_REG_BER_MSB) << 16) | rd(DIB3000MC_REG_BER_LSB)); | ||
684 | return 0; | ||
685 | } | ||
686 | |||
687 | static int dib3000mc_read_unc_blocks(struct dvb_frontend* fe, u32 *unc) | ||
688 | { | ||
689 | struct dib3000_state* state = (struct dib3000_state*) fe->demodulator_priv; | ||
690 | |||
691 | *unc = rd(DIB3000MC_REG_PACKET_ERROR_COUNT); | ||
692 | return 0; | ||
693 | } | ||
694 | |||
695 | /* see dib3000mb.c for calculation comments */ | ||
696 | static int dib3000mc_read_signal_strength(struct dvb_frontend* fe, u16 *strength) | ||
697 | { | ||
698 | struct dib3000_state* state = (struct dib3000_state*) fe->demodulator_priv; | ||
699 | u16 val = rd(DIB3000MC_REG_SIGNAL_NOISE_LSB); | ||
700 | *strength = (((val >> 6) & 0xff) << 8) + (val & 0x3f); | ||
701 | |||
702 | deb_stat("signal: mantisse = %d, exponent = %d\n",(*strength >> 8) & 0xff, *strength & 0xff); | ||
703 | return 0; | ||
704 | } | ||
705 | |||
706 | /* see dib3000mb.c for calculation comments */ | ||
707 | static int dib3000mc_read_snr(struct dvb_frontend* fe, u16 *snr) | ||
708 | { | ||
709 | struct dib3000_state* state = (struct dib3000_state*) fe->demodulator_priv; | ||
710 | u16 val = rd(DIB3000MC_REG_SIGNAL_NOISE_LSB), | ||
711 | val2 = rd(DIB3000MC_REG_SIGNAL_NOISE_MSB); | ||
712 | u16 sig,noise; | ||
713 | |||
714 | sig = (((val >> 6) & 0xff) << 8) + (val & 0x3f); | ||
715 | noise = (((val >> 4) & 0xff) << 8) + ((val & 0xf) << 2) + ((val2 >> 14) & 0x3); | ||
716 | if (noise == 0) | ||
717 | *snr = 0xffff; | ||
718 | else | ||
719 | *snr = (u16) sig/noise; | ||
720 | |||
721 | deb_stat("signal: mantisse = %d, exponent = %d\n",(sig >> 8) & 0xff, sig & 0xff); | ||
722 | deb_stat("noise: mantisse = %d, exponent = %d\n",(noise >> 8) & 0xff, noise & 0xff); | ||
723 | deb_stat("snr: %d\n",*snr); | ||
724 | return 0; | ||
725 | } | ||
726 | |||
727 | static int dib3000mc_sleep(struct dvb_frontend* fe) | ||
728 | { | ||
729 | struct dib3000_state* state = (struct dib3000_state*) fe->demodulator_priv; | ||
730 | |||
731 | set_or(DIB3000MC_REG_CLK_CFG_7,DIB3000MC_CLK_CFG_7_PWR_DOWN); | ||
732 | wr(DIB3000MC_REG_CLK_CFG_1,DIB3000MC_CLK_CFG_1_POWER_DOWN); | ||
733 | wr(DIB3000MC_REG_CLK_CFG_2,DIB3000MC_CLK_CFG_2_POWER_DOWN); | ||
734 | wr(DIB3000MC_REG_CLK_CFG_3,DIB3000MC_CLK_CFG_3_POWER_DOWN); | ||
735 | return 0; | ||
736 | } | ||
737 | |||
738 | static int dib3000mc_fe_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings *tune) | ||
739 | { | ||
740 | tune->min_delay_ms = 2000; | ||
741 | tune->step_size = 166667; | ||
742 | tune->max_drift = 166667 * 2; | ||
743 | |||
744 | return 0; | ||
745 | } | ||
746 | |||
747 | static int dib3000mc_fe_init_nonmobile(struct dvb_frontend* fe) | ||
748 | { | ||
749 | return dib3000mc_fe_init(fe, 0); | ||
750 | } | ||
751 | |||
752 | static int dib3000mc_set_frontend_and_tuner(struct dvb_frontend* fe, struct dvb_frontend_parameters *fep) | ||
753 | { | ||
754 | return dib3000mc_set_frontend(fe, fep, 1); | ||
755 | } | ||
756 | |||
757 | static void dib3000mc_release(struct dvb_frontend* fe) | ||
758 | { | ||
759 | struct dib3000_state *state = (struct dib3000_state *) fe->demodulator_priv; | ||
760 | kfree(state); | ||
761 | } | ||
762 | |||
763 | /* pid filter and transfer stuff */ | ||
764 | static int dib3000mc_pid_control(struct dvb_frontend *fe,int index, int pid,int onoff) | ||
765 | { | ||
766 | struct dib3000_state *state = fe->demodulator_priv; | ||
767 | pid = (onoff ? pid | DIB3000_ACTIVATE_PID_FILTERING : 0); | ||
768 | wr(index+DIB3000MC_REG_FIRST_PID,pid); | ||
769 | return 0; | ||
770 | } | ||
771 | |||
772 | static int dib3000mc_fifo_control(struct dvb_frontend *fe, int onoff) | ||
773 | { | ||
774 | struct dib3000_state *state = (struct dib3000_state*) fe->demodulator_priv; | ||
775 | u16 tmp = rd(DIB3000MC_REG_SMO_MODE); | ||
776 | |||
777 | deb_xfer("%s fifo\n",onoff ? "enabling" : "disabling"); | ||
778 | |||
779 | if (onoff) { | ||
780 | deb_xfer("%d %x\n",tmp & DIB3000MC_SMO_MODE_FIFO_UNFLUSH,tmp & DIB3000MC_SMO_MODE_FIFO_UNFLUSH); | ||
781 | wr(DIB3000MC_REG_SMO_MODE,tmp & DIB3000MC_SMO_MODE_FIFO_UNFLUSH); | ||
782 | } else { | ||
783 | deb_xfer("%d %x\n",tmp | DIB3000MC_SMO_MODE_FIFO_FLUSH,tmp | DIB3000MC_SMO_MODE_FIFO_FLUSH); | ||
784 | wr(DIB3000MC_REG_SMO_MODE,tmp | DIB3000MC_SMO_MODE_FIFO_FLUSH); | ||
785 | } | ||
786 | return 0; | ||
787 | } | ||
788 | |||
789 | static int dib3000mc_pid_parse(struct dvb_frontend *fe, int onoff) | ||
790 | { | ||
791 | struct dib3000_state *state = fe->demodulator_priv; | ||
792 | u16 tmp = rd(DIB3000MC_REG_SMO_MODE); | ||
793 | |||
794 | deb_xfer("%s pid parsing\n",onoff ? "enabling" : "disabling"); | ||
795 | |||
796 | if (onoff) { | ||
797 | wr(DIB3000MC_REG_SMO_MODE,tmp | DIB3000MC_SMO_MODE_PID_PARSE); | ||
798 | } else { | ||
799 | wr(DIB3000MC_REG_SMO_MODE,tmp & DIB3000MC_SMO_MODE_NO_PID_PARSE); | ||
800 | } | ||
801 | return 0; | ||
802 | } | ||
803 | |||
804 | static int dib3000mc_tuner_pass_ctrl(struct dvb_frontend *fe, int onoff, u8 pll_addr) | ||
805 | { | ||
806 | struct dib3000_state *state = (struct dib3000_state*) fe->demodulator_priv; | ||
807 | if (onoff) { | ||
808 | wr(DIB3000MC_REG_TUNER, DIB3000_TUNER_WRITE_ENABLE(pll_addr)); | ||
809 | } else { | ||
810 | wr(DIB3000MC_REG_TUNER, DIB3000_TUNER_WRITE_DISABLE(pll_addr)); | ||
811 | } | ||
812 | return 0; | ||
813 | } | ||
814 | |||
815 | static int dib3000mc_demod_init(struct dib3000_state *state) | ||
816 | { | ||
817 | u16 default_addr = 0x0a; | ||
818 | /* first init */ | ||
819 | if (state->config.demod_address != default_addr) { | ||
820 | deb_info("initializing the demod the first time. Setting demod addr to 0x%x\n",default_addr); | ||
821 | wr(DIB3000MC_REG_ELEC_OUT,DIB3000MC_ELEC_OUT_DIV_OUT_ON); | ||
822 | wr(DIB3000MC_REG_OUTMODE,DIB3000MC_OM_PAR_CONT_CLK); | ||
823 | |||
824 | wr(DIB3000MC_REG_RST_I2C_ADDR, | ||
825 | DIB3000MC_DEMOD_ADDR(default_addr) | | ||
826 | DIB3000MC_DEMOD_ADDR_ON); | ||
827 | |||
828 | state->config.demod_address = default_addr; | ||
829 | |||
830 | wr(DIB3000MC_REG_RST_I2C_ADDR, | ||
831 | DIB3000MC_DEMOD_ADDR(default_addr)); | ||
832 | } else | ||
833 | deb_info("demod is already initialized. Demod addr: 0x%x\n",state->config.demod_address); | ||
834 | return 0; | ||
835 | } | ||
836 | |||
837 | |||
838 | static struct dvb_frontend_ops dib3000mc_ops; | ||
839 | |||
840 | struct dvb_frontend* dib3000mc_attach(const struct dib3000_config* config, | ||
841 | struct i2c_adapter* i2c, struct dib_fe_xfer_ops *xfer_ops) | ||
842 | { | ||
843 | struct dib3000_state* state = NULL; | ||
844 | u16 devid; | ||
845 | |||
846 | /* allocate memory for the internal state */ | ||
847 | state = (struct dib3000_state*) kmalloc(sizeof(struct dib3000_state), GFP_KERNEL); | ||
848 | if (state == NULL) | ||
849 | goto error; | ||
850 | memset(state,0,sizeof(struct dib3000_state)); | ||
851 | |||
852 | /* setup the state */ | ||
853 | state->i2c = i2c; | ||
854 | memcpy(&state->config,config,sizeof(struct dib3000_config)); | ||
855 | memcpy(&state->ops, &dib3000mc_ops, sizeof(struct dvb_frontend_ops)); | ||
856 | |||
857 | /* check for the correct demod */ | ||
858 | if (rd(DIB3000_REG_MANUFACTOR_ID) != DIB3000_I2C_ID_DIBCOM) | ||
859 | goto error; | ||
860 | |||
861 | devid = rd(DIB3000_REG_DEVICE_ID); | ||
862 | if (devid != DIB3000MC_DEVICE_ID && devid != DIB3000P_DEVICE_ID) | ||
863 | goto error; | ||
864 | |||
865 | switch (devid) { | ||
866 | case DIB3000MC_DEVICE_ID: | ||
867 | info("Found a DiBcom 3000M-C, interesting..."); | ||
868 | break; | ||
869 | case DIB3000P_DEVICE_ID: | ||
870 | info("Found a DiBcom 3000P."); | ||
871 | break; | ||
872 | } | ||
873 | |||
874 | /* create dvb_frontend */ | ||
875 | state->frontend.ops = &state->ops; | ||
876 | state->frontend.demodulator_priv = state; | ||
877 | |||
878 | /* set the xfer operations */ | ||
879 | xfer_ops->pid_parse = dib3000mc_pid_parse; | ||
880 | xfer_ops->fifo_ctrl = dib3000mc_fifo_control; | ||
881 | xfer_ops->pid_ctrl = dib3000mc_pid_control; | ||
882 | xfer_ops->tuner_pass_ctrl = dib3000mc_tuner_pass_ctrl; | ||
883 | |||
884 | dib3000mc_demod_init(state); | ||
885 | |||
886 | return &state->frontend; | ||
887 | |||
888 | error: | ||
889 | kfree(state); | ||
890 | return NULL; | ||
891 | } | ||
892 | |||
893 | static struct dvb_frontend_ops dib3000mc_ops = { | ||
894 | |||
895 | .info = { | ||
896 | .name = "DiBcom 3000P/M-C DVB-T", | ||
897 | .type = FE_OFDM, | ||
898 | .frequency_min = 44250000, | ||
899 | .frequency_max = 867250000, | ||
900 | .frequency_stepsize = 62500, | ||
901 | .caps = FE_CAN_INVERSION_AUTO | | ||
902 | FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | | ||
903 | FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO | | ||
904 | FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO | | ||
905 | FE_CAN_TRANSMISSION_MODE_AUTO | | ||
906 | FE_CAN_GUARD_INTERVAL_AUTO | | ||
907 | FE_CAN_RECOVER | | ||
908 | FE_CAN_HIERARCHY_AUTO, | ||
909 | }, | ||
910 | |||
911 | .release = dib3000mc_release, | ||
912 | |||
913 | .init = dib3000mc_fe_init_nonmobile, | ||
914 | .sleep = dib3000mc_sleep, | ||
915 | |||
916 | .set_frontend = dib3000mc_set_frontend_and_tuner, | ||
917 | .get_frontend = dib3000mc_get_frontend, | ||
918 | .get_tune_settings = dib3000mc_fe_get_tune_settings, | ||
919 | |||
920 | .read_status = dib3000mc_read_status, | ||
921 | .read_ber = dib3000mc_read_ber, | ||
922 | .read_signal_strength = dib3000mc_read_signal_strength, | ||
923 | .read_snr = dib3000mc_read_snr, | ||
924 | .read_ucblocks = dib3000mc_read_unc_blocks, | ||
925 | }; | ||
926 | |||
927 | MODULE_AUTHOR(DRIVER_AUTHOR); | ||
928 | MODULE_DESCRIPTION(DRIVER_DESC); | ||
929 | MODULE_LICENSE("GPL"); | ||
930 | |||
931 | EXPORT_SYMBOL(dib3000mc_attach); | ||
diff --git a/drivers/media/dvb/frontends/dib3000mc_priv.h b/drivers/media/dvb/frontends/dib3000mc_priv.h new file mode 100644 index 000000000000..2930aac7591b --- /dev/null +++ b/drivers/media/dvb/frontends/dib3000mc_priv.h | |||
@@ -0,0 +1,428 @@ | |||
1 | /* | ||
2 | * dib3000mc_priv.h | ||
3 | * | ||
4 | * Copyright (C) 2004 Patrick Boettcher (patrick.boettcher@desy.de) | ||
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 | * for more information see dib3000mc.c . | ||
11 | */ | ||
12 | |||
13 | #ifndef __DIB3000MC_PRIV_H__ | ||
14 | #define __DIB3000MC_PRIV_H__ | ||
15 | |||
16 | /* | ||
17 | * Demodulator parameters | ||
18 | * reg: 0 1 1 1 11 11 111 | ||
19 | * | | | | | | | ||
20 | * | | | | | +-- alpha (000=0, 001=1, 010=2, 100=4) | ||
21 | * | | | | +----- constellation (00=QPSK, 01=16QAM, 10=64QAM) | ||
22 | * | | | +-------- guard (00=1/32, 01=1/16, 10=1/8, 11=1/4) | ||
23 | * | | +----------- transmission mode (0=2k, 1=8k) | ||
24 | * | | | ||
25 | * | +-------------- restart autosearch for parameters | ||
26 | * +---------------- restart the demodulator | ||
27 | * reg: 181 1 111 1 | ||
28 | * | | | | ||
29 | * | | +- FEC applies for HP or LP (0=LP, 1=HP) | ||
30 | * | +---- FEC rate (001=1/2, 010=2/3, 011=3/4, 101=5/6, 111=7/8) | ||
31 | * +------- hierarchy on (0=no, 1=yes) | ||
32 | */ | ||
33 | |||
34 | /* demodulator tuning parameter and restart options */ | ||
35 | #define DIB3000MC_REG_DEMOD_PARM ( 0) | ||
36 | #define DIB3000MC_DEMOD_PARM(a,c,g,t) ( \ | ||
37 | (0x7 & a) | \ | ||
38 | ((0x3 & c) << 3) | \ | ||
39 | ((0x3 & g) << 5) | \ | ||
40 | ((0x1 & t) << 7) ) | ||
41 | #define DIB3000MC_DEMOD_RST_AUTO_SRCH_ON (1 << 8) | ||
42 | #define DIB3000MC_DEMOD_RST_AUTO_SRCH_OFF (0 << 8) | ||
43 | #define DIB3000MC_DEMOD_RST_DEMOD_ON (1 << 9) | ||
44 | #define DIB3000MC_DEMOD_RST_DEMOD_OFF (0 << 9) | ||
45 | |||
46 | /* register for hierarchy parameters */ | ||
47 | #define DIB3000MC_REG_HRCH_PARM ( 181) | ||
48 | #define DIB3000MC_HRCH_PARM(s,f,h) ( \ | ||
49 | (0x1 & s) | \ | ||
50 | ((0x7 & f) << 1) | \ | ||
51 | ((0x1 & h) << 4) ) | ||
52 | |||
53 | /* timeout ??? */ | ||
54 | #define DIB3000MC_REG_UNK_1 ( 1) | ||
55 | #define DIB3000MC_UNK_1 ( 0x04) | ||
56 | |||
57 | /* timeout ??? */ | ||
58 | #define DIB3000MC_REG_UNK_2 ( 2) | ||
59 | #define DIB3000MC_UNK_2 ( 0x04) | ||
60 | |||
61 | /* timeout ??? */ | ||
62 | #define DIB3000MC_REG_UNK_3 ( 3) | ||
63 | #define DIB3000MC_UNK_3 (0x1000) | ||
64 | |||
65 | #define DIB3000MC_REG_UNK_4 ( 4) | ||
66 | #define DIB3000MC_UNK_4 (0x0814) | ||
67 | |||
68 | /* timeout ??? */ | ||
69 | #define DIB3000MC_REG_SEQ_TPS ( 5) | ||
70 | #define DIB3000MC_SEQ_TPS_DEFAULT ( 1) | ||
71 | #define DIB3000MC_SEQ_TPS(s,t) ( \ | ||
72 | ((s & 0x0f) << 4) | \ | ||
73 | ((t & 0x01) << 8) ) | ||
74 | #define DIB3000MC_IS_TPS(v) ((v << 8) & 0x1) | ||
75 | #define DIB3000MC_IS_AS(v) ((v >> 4) & 0xf) | ||
76 | |||
77 | /* parameters for the bandwidth */ | ||
78 | #define DIB3000MC_REG_BW_TIMOUT_MSB ( 6) | ||
79 | #define DIB3000MC_REG_BW_TIMOUT_LSB ( 7) | ||
80 | |||
81 | static u16 dib3000mc_reg_bandwidth[] = { 6,7,8,9,10,11,16,17 }; | ||
82 | |||
83 | /*static u16 dib3000mc_bandwidth_5mhz[] = | ||
84 | { 0x28, 0x9380, 0x87, 0x4100, 0x2a4, 0x4500, 0x1, 0xb0d0 };*/ | ||
85 | |||
86 | static u16 dib3000mc_bandwidth_6mhz[] = | ||
87 | { 0x21, 0xd040, 0x70, 0xb62b, 0x233, 0x8ed5, 0x1, 0xb0d0 }; | ||
88 | |||
89 | static u16 dib3000mc_bandwidth_7mhz[] = | ||
90 | { 0x1c, 0xfba5, 0x60, 0x9c25, 0x1e3, 0x0cb7, 0x1, 0xb0d0 }; | ||
91 | |||
92 | static u16 dib3000mc_bandwidth_8mhz[] = | ||
93 | { 0x19, 0x5c30, 0x54, 0x88a0, 0x1a6, 0xab20, 0x1, 0xb0d0 }; | ||
94 | |||
95 | static u16 dib3000mc_reg_bandwidth_general[] = { 12,13,14,15 }; | ||
96 | static u16 dib3000mc_bandwidth_general[] = { 0x0000, 0x03e8, 0x0000, 0x03f2 }; | ||
97 | |||
98 | /* lock mask */ | ||
99 | #define DIB3000MC_REG_LOCK_MASK ( 15) | ||
100 | #define DIB3000MC_ACTIVATE_LOCK_MASK (0x0800) | ||
101 | |||
102 | /* reset the uncorrected packet count (??? do it 5 times) */ | ||
103 | #define DIB3000MC_REG_RST_UNC ( 18) | ||
104 | #define DIB3000MC_RST_UNC_ON ( 1) | ||
105 | #define DIB3000MC_RST_UNC_OFF ( 0) | ||
106 | |||
107 | #define DIB3000MC_REG_UNK_19 ( 19) | ||
108 | #define DIB3000MC_UNK_19 ( 0) | ||
109 | |||
110 | /* DDS frequency value (IF position) and inversion bit */ | ||
111 | #define DIB3000MC_REG_INVERSION ( 21) | ||
112 | #define DIB3000MC_REG_SET_DDS_FREQ_MSB ( 21) | ||
113 | #define DIB3000MC_DDS_FREQ_MSB_INV_OFF (0x0164) | ||
114 | #define DIB3000MC_DDS_FREQ_MSB_INV_ON (0x0364) | ||
115 | |||
116 | #define DIB3000MC_REG_SET_DDS_FREQ_LSB ( 22) | ||
117 | #define DIB3000MC_DDS_FREQ_LSB (0x463d) | ||
118 | |||
119 | /* timing frequencies setting */ | ||
120 | #define DIB3000MC_REG_TIMING_FREQ_MSB ( 23) | ||
121 | #define DIB3000MC_REG_TIMING_FREQ_LSB ( 24) | ||
122 | #define DIB3000MC_CLOCK_REF (0x151fd1) | ||
123 | |||
124 | //static u16 dib3000mc_reg_timing_freq[] = { 23,24 }; | ||
125 | |||
126 | //static u16 dib3000mc_timing_freq[][2] = { | ||
127 | // { 0x69, 0x9f18 }, /* 5 MHz */ | ||
128 | // { 0x7e ,0xbee9 }, /* 6 MHz */ | ||
129 | // { 0x93 ,0xdebb }, /* 7 MHz */ | ||
130 | // { 0xa8 ,0xfe8c }, /* 8 MHz */ | ||
131 | //}; | ||
132 | |||
133 | /* timeout ??? */ | ||
134 | static u16 dib3000mc_reg_offset[] = { 26,33 }; | ||
135 | |||
136 | static u16 dib3000mc_offset[][2] = { | ||
137 | { 26240, 5 }, /* default */ | ||
138 | { 30336, 6 }, /* 8K */ | ||
139 | { 38528, 8 }, /* 2K */ | ||
140 | }; | ||
141 | |||
142 | #define DIB3000MC_REG_ISI ( 29) | ||
143 | #define DIB3000MC_ISI_DEFAULT (0x1073) | ||
144 | #define DIB3000MC_ISI_ACTIVATE (0x0000) | ||
145 | #define DIB3000MC_ISI_INHIBIT (0x0200) | ||
146 | |||
147 | /* impulse noise control */ | ||
148 | static u16 dib3000mc_reg_imp_noise_ctl[] = { 34,35 }; | ||
149 | |||
150 | static u16 dib3000mc_imp_noise_ctl[][2] = { | ||
151 | { 0x1294, 0x1ff8 }, /* mode 0 */ | ||
152 | { 0x1294, 0x1ff8 }, /* mode 1 */ | ||
153 | { 0x1294, 0x1ff8 }, /* mode 2 */ | ||
154 | { 0x1294, 0x1ff8 }, /* mode 3 */ | ||
155 | { 0x1294, 0x1ff8 }, /* mode 4 */ | ||
156 | }; | ||
157 | |||
158 | /* AGC registers */ | ||
159 | static u16 dib3000mc_reg_agc[] = { | ||
160 | 36,37,38,39,42,43,44,45,46,47,48,49 | ||
161 | }; | ||
162 | |||
163 | static u16 dib3000mc_agc_tuner[][12] = { | ||
164 | { 0x0051, 0x301d, 0x0000, 0x1cc7, 0xcf5c, 0x6666, | ||
165 | 0xbae1, 0xa148, 0x3b5e, 0x3c1c, 0x001a, 0x2019 | ||
166 | }, /* TUNER_PANASONIC_ENV77H04D5, */ | ||
167 | |||
168 | { 0x0051, 0x301d, 0x0000, 0x1cc7, 0xdc29, 0x570a, | ||
169 | 0xbae1, 0x8ccd, 0x3b6d, 0x551d, 0x000a, 0x951e | ||
170 | }, /* TUNER_PANASONIC_ENV57H13D5, TUNER_PANASONIC_ENV57H12D5 */ | ||
171 | |||
172 | { 0x0051, 0x301d, 0x0000, 0x1cc7, 0xffff, 0xffff, | ||
173 | 0xffff, 0x0000, 0xfdfd, 0x4040, 0x00fd, 0x4040 | ||
174 | }, /* TUNER_SAMSUNG_DTOS333IH102, TUNER_RFAGCIN_UNKNOWN */ | ||
175 | |||
176 | { 0x0196, 0x301d, 0x0000, 0x1cc7, 0xbd71, 0x5c29, | ||
177 | 0xb5c3, 0x6148, 0x6569, 0x5127, 0x0033, 0x3537 | ||
178 | }, /* TUNER_PROVIDER_X */ | ||
179 | /* TODO TUNER_PANASONIC_ENV57H10D8, TUNER_PANASONIC_ENV57H11D8 */ | ||
180 | }; | ||
181 | |||
182 | /* AGC loop bandwidth */ | ||
183 | static u16 dib3000mc_reg_agc_bandwidth[] = { 40,41 }; | ||
184 | static u16 dib3000mc_agc_bandwidth[] = { 0x119,0x330 }; | ||
185 | |||
186 | static u16 dib3000mc_reg_agc_bandwidth_general[] = { 50,51,52,53,54 }; | ||
187 | static u16 dib3000mc_agc_bandwidth_general[] = | ||
188 | { 0x8000, 0x91ca, 0x01ba, 0x0087, 0x0087 }; | ||
189 | |||
190 | #define DIB3000MC_REG_IMP_NOISE_55 ( 55) | ||
191 | #define DIB3000MC_IMP_NEW_ALGO(w) (w | (1<<10)) | ||
192 | |||
193 | /* Impulse noise params */ | ||
194 | static u16 dib3000mc_reg_impulse_noise[] = { 55,56,57 }; | ||
195 | static u16 dib3000mc_impluse_noise[][3] = { | ||
196 | { 0x489, 0x89, 0x72 }, /* 5 MHz */ | ||
197 | { 0x4a5, 0xa5, 0x89 }, /* 6 MHz */ | ||
198 | { 0x4c0, 0xc0, 0xa0 }, /* 7 MHz */ | ||
199 | { 0x4db, 0xdb, 0xb7 }, /* 8 Mhz */ | ||
200 | }; | ||
201 | |||
202 | static u16 dib3000mc_reg_fft[] = { | ||
203 | 58,59,60,61,62,63,64,65,66,67,68,69, | ||
204 | 70,71,72,73,74,75,76,77,78,79,80,81, | ||
205 | 82,83,84,85,86 | ||
206 | }; | ||
207 | |||
208 | static u16 dib3000mc_fft_modes[][29] = { | ||
209 | { 0x38, 0x6d9, 0x3f28, 0x7a7, 0x3a74, 0x196, 0x32a, 0x48c, | ||
210 | 0x3ffe, 0x7f3, 0x2d94, 0x76, 0x53d, | ||
211 | 0x3ff8, 0x7e3, 0x3320, 0x76, 0x5b3, | ||
212 | 0x3feb, 0x7d2, 0x365e, 0x76, 0x48c, | ||
213 | 0x3ffe, 0x5b3, 0x3feb, 0x76, 0x0, 0xd | ||
214 | }, /* fft mode 0 */ | ||
215 | { 0x3b, 0x6d9, 0x3f28, 0x7a7, 0x3a74, 0x196, 0x32a, 0x48c, | ||
216 | 0x3ffe, 0x7f3, 0x2d94, 0x76, 0x53d, | ||
217 | 0x3ff8, 0x7e3, 0x3320, 0x76, 0x5b3, | ||
218 | 0x3feb, 0x7d2, 0x365e, 0x76, 0x48c, | ||
219 | 0x3ffe, 0x5b3, 0x3feb, 0x0, 0x8200, 0xd | ||
220 | }, /* fft mode 1 */ | ||
221 | }; | ||
222 | |||
223 | #define DIB3000MC_REG_UNK_88 ( 88) | ||
224 | #define DIB3000MC_UNK_88 (0x0410) | ||
225 | |||
226 | static u16 dib3000mc_reg_bw[] = { 93,94,95,96,97,98 }; | ||
227 | static u16 dib3000mc_bw[][6] = { | ||
228 | { 0,0,0,0,0,0 }, /* 5 MHz */ | ||
229 | { 0,0,0,0,0,0 }, /* 6 MHz */ | ||
230 | { 0,0,0,0,0,0 }, /* 7 MHz */ | ||
231 | { 0x20, 0x21, 0x20, 0x23, 0x20, 0x27 }, /* 8 MHz */ | ||
232 | }; | ||
233 | |||
234 | |||
235 | /* phase noise control */ | ||
236 | #define DIB3000MC_REG_UNK_99 ( 99) | ||
237 | #define DIB3000MC_UNK_99 (0x0220) | ||
238 | |||
239 | #define DIB3000MC_REG_SCAN_BOOST ( 100) | ||
240 | #define DIB3000MC_SCAN_BOOST_ON ((11 << 6) + 6) | ||
241 | #define DIB3000MC_SCAN_BOOST_OFF ((16 << 6) + 9) | ||
242 | |||
243 | /* timeout ??? */ | ||
244 | #define DIB3000MC_REG_UNK_110 ( 110) | ||
245 | #define DIB3000MC_UNK_110 ( 3277) | ||
246 | |||
247 | #define DIB3000MC_REG_UNK_111 ( 111) | ||
248 | #define DIB3000MC_UNK_111_PH_N_MODE_0 ( 0) | ||
249 | #define DIB3000MC_UNK_111_PH_N_MODE_1 (1 << 1) | ||
250 | |||
251 | /* superious rm config */ | ||
252 | #define DIB3000MC_REG_UNK_120 ( 120) | ||
253 | #define DIB3000MC_UNK_120 ( 8207) | ||
254 | |||
255 | #define DIB3000MC_REG_UNK_133 ( 133) | ||
256 | #define DIB3000MC_UNK_133 ( 15564) | ||
257 | |||
258 | #define DIB3000MC_REG_UNK_134 ( 134) | ||
259 | #define DIB3000MC_UNK_134 ( 0) | ||
260 | |||
261 | /* adapter config for constellation */ | ||
262 | static u16 dib3000mc_reg_adp_cfg[] = { 129, 130, 131, 132 }; | ||
263 | |||
264 | static u16 dib3000mc_adp_cfg[][4] = { | ||
265 | { 0x99a, 0x7fae, 0x333, 0x7ff0 }, /* QPSK */ | ||
266 | { 0x23d, 0x7fdf, 0x0a4, 0x7ff0 }, /* 16-QAM */ | ||
267 | { 0x148, 0x7ff0, 0x0a4, 0x7ff8 }, /* 64-QAM */ | ||
268 | }; | ||
269 | |||
270 | static u16 dib3000mc_reg_mobile_mode[] = { 139, 140, 141, 175, 1032 }; | ||
271 | |||
272 | static u16 dib3000mc_mobile_mode[][5] = { | ||
273 | { 0x01, 0x0, 0x0, 0x00, 0x12c }, /* fixed */ | ||
274 | { 0x01, 0x0, 0x0, 0x00, 0x12c }, /* portable */ | ||
275 | { 0x00, 0x0, 0x0, 0x02, 0x000 }, /* mobile */ | ||
276 | { 0x00, 0x0, 0x0, 0x02, 0x000 }, /* auto */ | ||
277 | }; | ||
278 | |||
279 | #define DIB3000MC_REG_DIVERSITY1 ( 177) | ||
280 | #define DIB3000MC_DIVERSITY1_DEFAULT ( 1) | ||
281 | |||
282 | #define DIB3000MC_REG_DIVERSITY2 ( 178) | ||
283 | #define DIB3000MC_DIVERSITY2_DEFAULT ( 1) | ||
284 | |||
285 | #define DIB3000MC_REG_DIVERSITY3 ( 180) | ||
286 | #define DIB3000MC_DIVERSITY3_IN_OFF (0xfff0) | ||
287 | #define DIB3000MC_DIVERSITY3_IN_ON (0xfff6) | ||
288 | |||
289 | #define DIB3000MC_REG_FEC_CFG ( 195) | ||
290 | #define DIB3000MC_FEC_CFG ( 0x10) | ||
291 | |||
292 | /* | ||
293 | * reg 206, output mode | ||
294 | * 1111 1111 | ||
295 | * |||| |||| | ||
296 | * |||| |||+- unk | ||
297 | * |||| ||+-- unk | ||
298 | * |||| |+--- unk (on by default) | ||
299 | * |||| +---- fifo_ctrl (1 = inhibit (flushed), 0 = active (unflushed)) | ||
300 | * |||+------ pid_parse (1 = enabled, 0 = disabled) | ||
301 | * ||+------- outp_188 (1 = TS packet size 188, 0 = packet size 204) | ||
302 | * |+-------- unk | ||
303 | * +--------- unk | ||
304 | */ | ||
305 | |||
306 | #define DIB3000MC_REG_SMO_MODE ( 206) | ||
307 | #define DIB3000MC_SMO_MODE_DEFAULT (1 << 2) | ||
308 | #define DIB3000MC_SMO_MODE_FIFO_FLUSH (1 << 3) | ||
309 | #define DIB3000MC_SMO_MODE_FIFO_UNFLUSH (0xfff7) | ||
310 | #define DIB3000MC_SMO_MODE_PID_PARSE (1 << 4) | ||
311 | #define DIB3000MC_SMO_MODE_NO_PID_PARSE (0xffef) | ||
312 | #define DIB3000MC_SMO_MODE_188 (1 << 5) | ||
313 | #define DIB3000MC_SMO_MODE_SLAVE (DIB3000MC_SMO_MODE_DEFAULT | \ | ||
314 | DIB3000MC_SMO_MODE_188 | DIB3000MC_SMO_MODE_PID_PARSE | (1<<1)) | ||
315 | |||
316 | #define DIB3000MC_REG_FIFO_THRESHOLD ( 207) | ||
317 | #define DIB3000MC_FIFO_THRESHOLD_DEFAULT ( 1792) | ||
318 | #define DIB3000MC_FIFO_THRESHOLD_SLAVE ( 512) | ||
319 | /* | ||
320 | * pidfilter | ||
321 | * it is not a hardware pidfilter but a filter which drops all pids | ||
322 | * except the ones set. When connected to USB1.1 bandwidth this is important. | ||
323 | * DiB3000P/M-C can filter up to 32 PIDs | ||
324 | */ | ||
325 | #define DIB3000MC_REG_FIRST_PID ( 212) | ||
326 | #define DIB3000MC_NUM_PIDS ( 32) | ||
327 | |||
328 | #define DIB3000MC_REG_OUTMODE ( 244) | ||
329 | #define DIB3000MC_OM_PARALLEL_GATED_CLK ( 0) | ||
330 | #define DIB3000MC_OM_PAR_CONT_CLK (1 << 11) | ||
331 | #define DIB3000MC_OM_SERIAL (2 << 11) | ||
332 | #define DIB3000MC_OM_DIVOUT_ON (4 << 11) | ||
333 | #define DIB3000MC_OM_SLAVE (DIB3000MC_OM_DIVOUT_ON | DIB3000MC_OM_PAR_CONT_CLK) | ||
334 | |||
335 | #define DIB3000MC_REG_RF_POWER ( 392) | ||
336 | |||
337 | #define DIB3000MC_REG_FFT_POSITION ( 407) | ||
338 | |||
339 | #define DIB3000MC_REG_DDS_FREQ_MSB ( 414) | ||
340 | #define DIB3000MC_REG_DDS_FREQ_LSB ( 415) | ||
341 | |||
342 | #define DIB3000MC_REG_TIMING_OFFS_MSB ( 416) | ||
343 | #define DIB3000MC_REG_TIMING_OFFS_LSB ( 417) | ||
344 | |||
345 | #define DIB3000MC_REG_TUNING_PARM ( 458) | ||
346 | #define DIB3000MC_TP_QAM(v) ((v >> 13) & 0x03) | ||
347 | #define DIB3000MC_TP_HRCH(v) ((v >> 12) & 0x01) | ||
348 | #define DIB3000MC_TP_ALPHA(v) ((v >> 9) & 0x07) | ||
349 | #define DIB3000MC_TP_FFT(v) ((v >> 8) & 0x01) | ||
350 | #define DIB3000MC_TP_FEC_CR_HP(v) ((v >> 5) & 0x07) | ||
351 | #define DIB3000MC_TP_FEC_CR_LP(v) ((v >> 2) & 0x07) | ||
352 | #define DIB3000MC_TP_GUARD(v) (v & 0x03) | ||
353 | |||
354 | #define DIB3000MC_REG_SIGNAL_NOISE_MSB ( 483) | ||
355 | #define DIB3000MC_REG_SIGNAL_NOISE_LSB ( 484) | ||
356 | |||
357 | #define DIB3000MC_REG_MER ( 485) | ||
358 | |||
359 | #define DIB3000MC_REG_BER_MSB ( 500) | ||
360 | #define DIB3000MC_REG_BER_LSB ( 501) | ||
361 | |||
362 | #define DIB3000MC_REG_PACKET_ERRORS ( 503) | ||
363 | |||
364 | #define DIB3000MC_REG_PACKET_ERROR_COUNT ( 506) | ||
365 | |||
366 | #define DIB3000MC_REG_LOCK_507 ( 507) | ||
367 | #define DIB3000MC_LOCK_507 (0x0002) // ? name correct ? | ||
368 | |||
369 | #define DIB3000MC_REG_LOCKING ( 509) | ||
370 | #define DIB3000MC_AGC_LOCK(v) (v & 0x8000) | ||
371 | #define DIB3000MC_CARRIER_LOCK(v) (v & 0x2000) | ||
372 | #define DIB3000MC_MPEG_SYNC_LOCK(v) (v & 0x0080) | ||
373 | #define DIB3000MC_MPEG_DATA_LOCK(v) (v & 0x0040) | ||
374 | #define DIB3000MC_TPS_LOCK(v) (v & 0x0004) | ||
375 | |||
376 | #define DIB3000MC_REG_AS_IRQ ( 511) | ||
377 | #define DIB3000MC_AS_IRQ_SUCCESS (1 << 1) | ||
378 | #define DIB3000MC_AS_IRQ_FAIL ( 1) | ||
379 | |||
380 | #define DIB3000MC_REG_TUNER ( 769) | ||
381 | |||
382 | #define DIB3000MC_REG_RST_I2C_ADDR ( 1024) | ||
383 | #define DIB3000MC_DEMOD_ADDR_ON ( 1) | ||
384 | #define DIB3000MC_DEMOD_ADDR(a) ((a << 4) & 0x03F0) | ||
385 | |||
386 | #define DIB3000MC_REG_RESTART ( 1027) | ||
387 | #define DIB3000MC_RESTART_OFF (0x0000) | ||
388 | #define DIB3000MC_RESTART_AGC (0x0800) | ||
389 | #define DIB3000MC_RESTART_CONFIG (0x8000) | ||
390 | |||
391 | #define DIB3000MC_REG_RESTART_VIT ( 1028) | ||
392 | #define DIB3000MC_RESTART_VIT_OFF ( 0) | ||
393 | #define DIB3000MC_RESTART_VIT_ON ( 1) | ||
394 | |||
395 | #define DIB3000MC_REG_CLK_CFG_1 ( 1031) | ||
396 | #define DIB3000MC_CLK_CFG_1_POWER_UP ( 0) | ||
397 | #define DIB3000MC_CLK_CFG_1_POWER_DOWN (0xffff) | ||
398 | |||
399 | #define DIB3000MC_REG_CLK_CFG_2 ( 1032) | ||
400 | #define DIB3000MC_CLK_CFG_2_PUP_FIXED (0x012c) | ||
401 | #define DIB3000MC_CLK_CFG_2_PUP_PORT (0x0104) | ||
402 | #define DIB3000MC_CLK_CFG_2_PUP_MOBILE (0x0000) | ||
403 | #define DIB3000MC_CLK_CFG_2_POWER_DOWN (0xffff) | ||
404 | |||
405 | #define DIB3000MC_REG_CLK_CFG_3 ( 1033) | ||
406 | #define DIB3000MC_CLK_CFG_3_POWER_UP ( 0) | ||
407 | #define DIB3000MC_CLK_CFG_3_POWER_DOWN (0xfff5) | ||
408 | |||
409 | #define DIB3000MC_REG_CLK_CFG_7 ( 1037) | ||
410 | #define DIB3000MC_CLK_CFG_7_INIT ( 12592) | ||
411 | #define DIB3000MC_CLK_CFG_7_POWER_UP (~0x0003) | ||
412 | #define DIB3000MC_CLK_CFG_7_PWR_DOWN (0x0003) | ||
413 | #define DIB3000MC_CLK_CFG_7_DIV_IN_OFF (1 << 8) | ||
414 | |||
415 | /* was commented out ??? */ | ||
416 | #define DIB3000MC_REG_CLK_CFG_8 ( 1038) | ||
417 | #define DIB3000MC_CLK_CFG_8_POWER_UP (0x160c) | ||
418 | |||
419 | #define DIB3000MC_REG_CLK_CFG_9 ( 1039) | ||
420 | #define DIB3000MC_CLK_CFG_9_POWER_UP ( 0) | ||
421 | |||
422 | /* also clock ??? */ | ||
423 | #define DIB3000MC_REG_ELEC_OUT ( 1040) | ||
424 | #define DIB3000MC_ELEC_OUT_HIGH_Z ( 0) | ||
425 | #define DIB3000MC_ELEC_OUT_DIV_OUT_ON ( 1) | ||
426 | #define DIB3000MC_ELEC_OUT_SLAVE ( 3) | ||
427 | |||
428 | #endif | ||
diff --git a/drivers/media/dvb/frontends/dvb-pll.c b/drivers/media/dvb/frontends/dvb-pll.c new file mode 100644 index 000000000000..2a3c2ce7b2aa --- /dev/null +++ b/drivers/media/dvb/frontends/dvb-pll.c | |||
@@ -0,0 +1,168 @@ | |||
1 | /* | ||
2 | * $Id: dvb-pll.c,v 1.7 2005/02/10 11:52:02 kraxel Exp $ | ||
3 | * | ||
4 | * descriptions + helper functions for simple dvb plls. | ||
5 | * | ||
6 | * (c) 2004 Gerd Knorr <kraxel@bytesex.org> [SuSE Labs] | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License as published by | ||
10 | * the Free Software Foundation; either version 2 of the License, or | ||
11 | * (at your option) any later version. | ||
12 | * | ||
13 | * This program is distributed in the hope that it will be useful, | ||
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
16 | * GNU General Public License for more details. | ||
17 | * | ||
18 | * You should have received a copy of the GNU General Public License | ||
19 | * along with this program; if not, write to the Free Software | ||
20 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
21 | */ | ||
22 | |||
23 | #include <linux/module.h> | ||
24 | #include <linux/dvb/frontend.h> | ||
25 | #include <asm/types.h> | ||
26 | |||
27 | #include "dvb-pll.h" | ||
28 | |||
29 | /* ----------------------------------------------------------- */ | ||
30 | /* descriptions */ | ||
31 | |||
32 | struct dvb_pll_desc dvb_pll_thomson_dtt7579 = { | ||
33 | .name = "Thomson dtt7579", | ||
34 | .min = 177000000, | ||
35 | .max = 858000000, | ||
36 | .count = 5, | ||
37 | .entries = { | ||
38 | { 0, 36166667, 166666, 0xb4, 0x03 }, /* go sleep */ | ||
39 | { 443250000, 36166667, 166666, 0xb4, 0x02 }, | ||
40 | { 542000000, 36166667, 166666, 0xb4, 0x08 }, | ||
41 | { 771000000, 36166667, 166666, 0xbc, 0x08 }, | ||
42 | { 999999999, 36166667, 166666, 0xf4, 0x08 }, | ||
43 | }, | ||
44 | }; | ||
45 | EXPORT_SYMBOL(dvb_pll_thomson_dtt7579); | ||
46 | |||
47 | struct dvb_pll_desc dvb_pll_thomson_dtt7610 = { | ||
48 | .name = "Thomson dtt7610", | ||
49 | .min = 44000000, | ||
50 | .max = 958000000, | ||
51 | .count = 3, | ||
52 | .entries = { | ||
53 | { 157250000, 44000000, 62500, 0x8e, 0x39 }, | ||
54 | { 454000000, 44000000, 62500, 0x8e, 0x3a }, | ||
55 | { 999999999, 44000000, 62500, 0x8e, 0x3c }, | ||
56 | }, | ||
57 | }; | ||
58 | EXPORT_SYMBOL(dvb_pll_thomson_dtt7610); | ||
59 | |||
60 | static void thomson_dtt759x_bw(u8 *buf, int bandwidth) | ||
61 | { | ||
62 | if (BANDWIDTH_7_MHZ == bandwidth) | ||
63 | buf[3] |= 0x10; | ||
64 | } | ||
65 | |||
66 | struct dvb_pll_desc dvb_pll_thomson_dtt759x = { | ||
67 | .name = "Thomson dtt759x", | ||
68 | .min = 177000000, | ||
69 | .max = 896000000, | ||
70 | .setbw = thomson_dtt759x_bw, | ||
71 | .count = 6, | ||
72 | .entries = { | ||
73 | { 0, 36166667, 166666, 0x84, 0x03 }, | ||
74 | { 264000000, 36166667, 166666, 0xb4, 0x02 }, | ||
75 | { 470000000, 36166667, 166666, 0xbc, 0x02 }, | ||
76 | { 735000000, 36166667, 166666, 0xbc, 0x08 }, | ||
77 | { 835000000, 36166667, 166666, 0xf4, 0x08 }, | ||
78 | { 999999999, 36166667, 166666, 0xfc, 0x08 }, | ||
79 | }, | ||
80 | }; | ||
81 | EXPORT_SYMBOL(dvb_pll_thomson_dtt759x); | ||
82 | |||
83 | struct dvb_pll_desc dvb_pll_lg_z201 = { | ||
84 | .name = "LG z201", | ||
85 | .min = 174000000, | ||
86 | .max = 862000000, | ||
87 | .count = 5, | ||
88 | .entries = { | ||
89 | { 0, 36166667, 166666, 0xbc, 0x03 }, | ||
90 | { 443250000, 36166667, 166666, 0xbc, 0x01 }, | ||
91 | { 542000000, 36166667, 166666, 0xbc, 0x02 }, | ||
92 | { 830000000, 36166667, 166666, 0xf4, 0x02 }, | ||
93 | { 999999999, 36166667, 166666, 0xfc, 0x02 }, | ||
94 | }, | ||
95 | }; | ||
96 | EXPORT_SYMBOL(dvb_pll_lg_z201); | ||
97 | |||
98 | struct dvb_pll_desc dvb_pll_unknown_1 = { | ||
99 | .name = "unknown 1", /* used by dntv live dvb-t */ | ||
100 | .min = 174000000, | ||
101 | .max = 862000000, | ||
102 | .count = 9, | ||
103 | .entries = { | ||
104 | { 150000000, 36166667, 166666, 0xb4, 0x01 }, | ||
105 | { 173000000, 36166667, 166666, 0xbc, 0x01 }, | ||
106 | { 250000000, 36166667, 166666, 0xb4, 0x02 }, | ||
107 | { 400000000, 36166667, 166666, 0xbc, 0x02 }, | ||
108 | { 420000000, 36166667, 166666, 0xf4, 0x02 }, | ||
109 | { 470000000, 36166667, 166666, 0xfc, 0x02 }, | ||
110 | { 600000000, 36166667, 166666, 0xbc, 0x08 }, | ||
111 | { 730000000, 36166667, 166666, 0xf4, 0x08 }, | ||
112 | { 999999999, 36166667, 166666, 0xfc, 0x08 }, | ||
113 | }, | ||
114 | }; | ||
115 | EXPORT_SYMBOL(dvb_pll_unknown_1); | ||
116 | |||
117 | /* ----------------------------------------------------------- */ | ||
118 | /* code */ | ||
119 | |||
120 | static int debug = 0; | ||
121 | module_param(debug, int, 0644); | ||
122 | MODULE_PARM_DESC(debug, "enable verbose debug messages"); | ||
123 | |||
124 | int dvb_pll_configure(struct dvb_pll_desc *desc, u8 *buf, | ||
125 | u32 freq, int bandwidth) | ||
126 | { | ||
127 | u32 div; | ||
128 | int i; | ||
129 | |||
130 | if (freq != 0 && (freq < desc->min || freq > desc->max)) | ||
131 | return -EINVAL; | ||
132 | |||
133 | for (i = 0; i < desc->count; i++) { | ||
134 | if (freq > desc->entries[i].limit) | ||
135 | continue; | ||
136 | break; | ||
137 | } | ||
138 | if (debug) | ||
139 | printk("pll: %s: freq=%d bw=%d | i=%d/%d\n", | ||
140 | desc->name, freq, bandwidth, i, desc->count); | ||
141 | BUG_ON(i == desc->count); | ||
142 | |||
143 | div = (freq + desc->entries[i].offset) / desc->entries[i].stepsize; | ||
144 | buf[0] = div >> 8; | ||
145 | buf[1] = div & 0xff; | ||
146 | buf[2] = desc->entries[i].cb1; | ||
147 | buf[3] = desc->entries[i].cb2; | ||
148 | |||
149 | if (desc->setbw) | ||
150 | desc->setbw(buf, bandwidth); | ||
151 | |||
152 | if (debug) | ||
153 | printk("pll: %s: div=%d | buf=0x%02x,0x%02x,0x%02x,0x%02x\n", | ||
154 | desc->name, div, buf[0], buf[1], buf[2], buf[3]); | ||
155 | |||
156 | return 0; | ||
157 | } | ||
158 | EXPORT_SYMBOL(dvb_pll_configure); | ||
159 | |||
160 | MODULE_DESCRIPTION("dvb pll library"); | ||
161 | MODULE_AUTHOR("Gerd Knorr"); | ||
162 | MODULE_LICENSE("GPL"); | ||
163 | |||
164 | /* | ||
165 | * Local variables: | ||
166 | * c-basic-offset: 8 | ||
167 | * End: | ||
168 | */ | ||
diff --git a/drivers/media/dvb/frontends/dvb-pll.h b/drivers/media/dvb/frontends/dvb-pll.h new file mode 100644 index 000000000000..016c794a5677 --- /dev/null +++ b/drivers/media/dvb/frontends/dvb-pll.h | |||
@@ -0,0 +1,34 @@ | |||
1 | /* | ||
2 | * $Id: dvb-pll.h,v 1.2 2005/02/10 11:43:41 kraxel Exp $ | ||
3 | */ | ||
4 | |||
5 | struct dvb_pll_desc { | ||
6 | char *name; | ||
7 | u32 min; | ||
8 | u32 max; | ||
9 | void (*setbw)(u8 *buf, int bandwidth); | ||
10 | int count; | ||
11 | struct { | ||
12 | u32 limit; | ||
13 | u32 offset; | ||
14 | u32 stepsize; | ||
15 | u8 cb1; | ||
16 | u8 cb2; | ||
17 | } entries[9]; | ||
18 | }; | ||
19 | |||
20 | extern struct dvb_pll_desc dvb_pll_thomson_dtt7579; | ||
21 | extern struct dvb_pll_desc dvb_pll_thomson_dtt759x; | ||
22 | extern struct dvb_pll_desc dvb_pll_thomson_dtt7610; | ||
23 | extern struct dvb_pll_desc dvb_pll_lg_z201; | ||
24 | extern struct dvb_pll_desc dvb_pll_unknown_1; | ||
25 | |||
26 | int dvb_pll_configure(struct dvb_pll_desc *desc, u8 *buf, | ||
27 | u32 freq, int bandwidth); | ||
28 | |||
29 | /* | ||
30 | * Local variables: | ||
31 | * c-basic-offset: 8 | ||
32 | * compile-command: "make DVB=1" | ||
33 | * End: | ||
34 | */ | ||
diff --git a/drivers/media/dvb/frontends/dvb_dummy_fe.c b/drivers/media/dvb/frontends/dvb_dummy_fe.c new file mode 100644 index 000000000000..c05a9b05600c --- /dev/null +++ b/drivers/media/dvb/frontends/dvb_dummy_fe.c | |||
@@ -0,0 +1,279 @@ | |||
1 | /* | ||
2 | * Driver for Dummy Frontend | ||
3 | * | ||
4 | * Written by Emard <emard@softhome.net> | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License as published by | ||
8 | * the Free Software Foundation; either version 2 of the License, or | ||
9 | * (at your option) any later version. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * | ||
15 | * GNU General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program; if not, write to the Free Software | ||
19 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.= | ||
20 | */ | ||
21 | |||
22 | #include <linux/module.h> | ||
23 | #include <linux/moduleparam.h> | ||
24 | #include <linux/init.h> | ||
25 | |||
26 | #include "dvb_frontend.h" | ||
27 | #include "dvb_dummy_fe.h" | ||
28 | |||
29 | |||
30 | struct dvb_dummy_fe_state { | ||
31 | struct dvb_frontend_ops ops; | ||
32 | struct dvb_frontend frontend; | ||
33 | }; | ||
34 | |||
35 | |||
36 | static int dvb_dummy_fe_read_status(struct dvb_frontend* fe, fe_status_t* status) | ||
37 | { | ||
38 | *status = FE_HAS_SIGNAL | ||
39 | | FE_HAS_CARRIER | ||
40 | | FE_HAS_VITERBI | ||
41 | | FE_HAS_SYNC | ||
42 | | FE_HAS_LOCK; | ||
43 | |||
44 | return 0; | ||
45 | } | ||
46 | |||
47 | static int dvb_dummy_fe_read_ber(struct dvb_frontend* fe, u32* ber) | ||
48 | { | ||
49 | *ber = 0; | ||
50 | return 0; | ||
51 | } | ||
52 | |||
53 | static int dvb_dummy_fe_read_signal_strength(struct dvb_frontend* fe, u16* strength) | ||
54 | { | ||
55 | *strength = 0; | ||
56 | return 0; | ||
57 | } | ||
58 | |||
59 | static int dvb_dummy_fe_read_snr(struct dvb_frontend* fe, u16* snr) | ||
60 | { | ||
61 | *snr = 0; | ||
62 | return 0; | ||
63 | } | ||
64 | |||
65 | static int dvb_dummy_fe_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks) | ||
66 | { | ||
67 | *ucblocks = 0; | ||
68 | return 0; | ||
69 | } | ||
70 | |||
71 | static int dvb_dummy_fe_get_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p) | ||
72 | { | ||
73 | return 0; | ||
74 | } | ||
75 | |||
76 | static int dvb_dummy_fe_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p) | ||
77 | { | ||
78 | return 0; | ||
79 | } | ||
80 | |||
81 | static int dvb_dummy_fe_sleep(struct dvb_frontend* fe) | ||
82 | { | ||
83 | return 0; | ||
84 | } | ||
85 | |||
86 | static int dvb_dummy_fe_init(struct dvb_frontend* fe) | ||
87 | { | ||
88 | return 0; | ||
89 | } | ||
90 | |||
91 | static int dvb_dummy_fe_set_tone(struct dvb_frontend* fe, fe_sec_tone_mode_t tone) | ||
92 | { | ||
93 | return 0; | ||
94 | } | ||
95 | |||
96 | static int dvb_dummy_fe_set_voltage(struct dvb_frontend* fe, fe_sec_voltage_t voltage) | ||
97 | { | ||
98 | return 0; | ||
99 | } | ||
100 | |||
101 | static void dvb_dummy_fe_release(struct dvb_frontend* fe) | ||
102 | { | ||
103 | struct dvb_dummy_fe_state* state = (struct dvb_dummy_fe_state*) fe->demodulator_priv; | ||
104 | kfree(state); | ||
105 | } | ||
106 | |||
107 | static struct dvb_frontend_ops dvb_dummy_fe_ofdm_ops; | ||
108 | |||
109 | struct dvb_frontend* dvb_dummy_fe_ofdm_attach(void) | ||
110 | { | ||
111 | struct dvb_dummy_fe_state* state = NULL; | ||
112 | |||
113 | /* allocate memory for the internal state */ | ||
114 | state = (struct dvb_dummy_fe_state*) kmalloc(sizeof(struct dvb_dummy_fe_state), GFP_KERNEL); | ||
115 | if (state == NULL) goto error; | ||
116 | |||
117 | /* setup the state */ | ||
118 | memcpy(&state->ops, &dvb_dummy_fe_ofdm_ops, sizeof(struct dvb_frontend_ops)); | ||
119 | |||
120 | /* create dvb_frontend */ | ||
121 | state->frontend.ops = &state->ops; | ||
122 | state->frontend.demodulator_priv = state; | ||
123 | return &state->frontend; | ||
124 | |||
125 | error: | ||
126 | kfree(state); | ||
127 | return NULL; | ||
128 | } | ||
129 | |||
130 | static struct dvb_frontend_ops dvb_dummy_fe_qpsk_ops; | ||
131 | |||
132 | struct dvb_frontend* dvb_dummy_fe_qpsk_attach() | ||
133 | { | ||
134 | struct dvb_dummy_fe_state* state = NULL; | ||
135 | |||
136 | /* allocate memory for the internal state */ | ||
137 | state = (struct dvb_dummy_fe_state*) kmalloc(sizeof(struct dvb_dummy_fe_state), GFP_KERNEL); | ||
138 | if (state == NULL) goto error; | ||
139 | |||
140 | /* setup the state */ | ||
141 | memcpy(&state->ops, &dvb_dummy_fe_qpsk_ops, sizeof(struct dvb_frontend_ops)); | ||
142 | |||
143 | /* create dvb_frontend */ | ||
144 | state->frontend.ops = &state->ops; | ||
145 | state->frontend.demodulator_priv = state; | ||
146 | return &state->frontend; | ||
147 | |||
148 | error: | ||
149 | if (state) kfree(state); | ||
150 | return NULL; | ||
151 | } | ||
152 | |||
153 | static struct dvb_frontend_ops dvb_dummy_fe_qam_ops; | ||
154 | |||
155 | struct dvb_frontend* dvb_dummy_fe_qam_attach() | ||
156 | { | ||
157 | struct dvb_dummy_fe_state* state = NULL; | ||
158 | |||
159 | /* allocate memory for the internal state */ | ||
160 | state = (struct dvb_dummy_fe_state*) kmalloc(sizeof(struct dvb_dummy_fe_state), GFP_KERNEL); | ||
161 | if (state == NULL) goto error; | ||
162 | |||
163 | /* setup the state */ | ||
164 | memcpy(&state->ops, &dvb_dummy_fe_qam_ops, sizeof(struct dvb_frontend_ops)); | ||
165 | |||
166 | /* create dvb_frontend */ | ||
167 | state->frontend.ops = &state->ops; | ||
168 | state->frontend.demodulator_priv = state; | ||
169 | return &state->frontend; | ||
170 | |||
171 | error: | ||
172 | if (state) kfree(state); | ||
173 | return NULL; | ||
174 | } | ||
175 | |||
176 | static struct dvb_frontend_ops dvb_dummy_fe_ofdm_ops = { | ||
177 | |||
178 | .info = { | ||
179 | .name = "Dummy DVB-T", | ||
180 | .type = FE_OFDM, | ||
181 | .frequency_min = 0, | ||
182 | .frequency_max = 863250000, | ||
183 | .frequency_stepsize = 62500, | ||
184 | .caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | | ||
185 | FE_CAN_FEC_4_5 | FE_CAN_FEC_5_6 | FE_CAN_FEC_6_7 | | ||
186 | FE_CAN_FEC_7_8 | FE_CAN_FEC_8_9 | FE_CAN_FEC_AUTO | | ||
187 | FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO | | ||
188 | FE_CAN_TRANSMISSION_MODE_AUTO | | ||
189 | FE_CAN_GUARD_INTERVAL_AUTO | | ||
190 | FE_CAN_HIERARCHY_AUTO, | ||
191 | }, | ||
192 | |||
193 | .release = dvb_dummy_fe_release, | ||
194 | |||
195 | .init = dvb_dummy_fe_init, | ||
196 | .sleep = dvb_dummy_fe_sleep, | ||
197 | |||
198 | .set_frontend = dvb_dummy_fe_set_frontend, | ||
199 | .get_frontend = dvb_dummy_fe_get_frontend, | ||
200 | |||
201 | .read_status = dvb_dummy_fe_read_status, | ||
202 | .read_ber = dvb_dummy_fe_read_ber, | ||
203 | .read_signal_strength = dvb_dummy_fe_read_signal_strength, | ||
204 | .read_snr = dvb_dummy_fe_read_snr, | ||
205 | .read_ucblocks = dvb_dummy_fe_read_ucblocks, | ||
206 | }; | ||
207 | |||
208 | static struct dvb_frontend_ops dvb_dummy_fe_qam_ops = { | ||
209 | |||
210 | .info = { | ||
211 | .name = "Dummy DVB-C", | ||
212 | .type = FE_QAM, | ||
213 | .frequency_stepsize = 62500, | ||
214 | .frequency_min = 51000000, | ||
215 | .frequency_max = 858000000, | ||
216 | .symbol_rate_min = (57840000/2)/64, /* SACLK/64 == (XIN/2)/64 */ | ||
217 | .symbol_rate_max = (57840000/2)/4, /* SACLK/4 */ | ||
218 | .caps = FE_CAN_QAM_16 | FE_CAN_QAM_32 | FE_CAN_QAM_64 | | ||
219 | FE_CAN_QAM_128 | FE_CAN_QAM_256 | | ||
220 | FE_CAN_FEC_AUTO | FE_CAN_INVERSION_AUTO | ||
221 | }, | ||
222 | |||
223 | .release = dvb_dummy_fe_release, | ||
224 | |||
225 | .init = dvb_dummy_fe_init, | ||
226 | .sleep = dvb_dummy_fe_sleep, | ||
227 | |||
228 | .set_frontend = dvb_dummy_fe_set_frontend, | ||
229 | .get_frontend = dvb_dummy_fe_get_frontend, | ||
230 | |||
231 | .read_status = dvb_dummy_fe_read_status, | ||
232 | .read_ber = dvb_dummy_fe_read_ber, | ||
233 | .read_signal_strength = dvb_dummy_fe_read_signal_strength, | ||
234 | .read_snr = dvb_dummy_fe_read_snr, | ||
235 | .read_ucblocks = dvb_dummy_fe_read_ucblocks, | ||
236 | }; | ||
237 | |||
238 | static struct dvb_frontend_ops dvb_dummy_fe_qpsk_ops = { | ||
239 | |||
240 | .info = { | ||
241 | .name = "Dummy DVB-S", | ||
242 | .type = FE_QPSK, | ||
243 | .frequency_min = 950000, | ||
244 | .frequency_max = 2150000, | ||
245 | .frequency_stepsize = 250, /* kHz for QPSK frontends */ | ||
246 | .frequency_tolerance = 29500, | ||
247 | .symbol_rate_min = 1000000, | ||
248 | .symbol_rate_max = 45000000, | ||
249 | .caps = FE_CAN_INVERSION_AUTO | | ||
250 | FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | | ||
251 | FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO | | ||
252 | FE_CAN_QPSK | ||
253 | }, | ||
254 | |||
255 | .release = dvb_dummy_fe_release, | ||
256 | |||
257 | .init = dvb_dummy_fe_init, | ||
258 | .sleep = dvb_dummy_fe_sleep, | ||
259 | |||
260 | .set_frontend = dvb_dummy_fe_set_frontend, | ||
261 | .get_frontend = dvb_dummy_fe_get_frontend, | ||
262 | |||
263 | .read_status = dvb_dummy_fe_read_status, | ||
264 | .read_ber = dvb_dummy_fe_read_ber, | ||
265 | .read_signal_strength = dvb_dummy_fe_read_signal_strength, | ||
266 | .read_snr = dvb_dummy_fe_read_snr, | ||
267 | .read_ucblocks = dvb_dummy_fe_read_ucblocks, | ||
268 | |||
269 | .set_voltage = dvb_dummy_fe_set_voltage, | ||
270 | .set_tone = dvb_dummy_fe_set_tone, | ||
271 | }; | ||
272 | |||
273 | MODULE_DESCRIPTION("DVB DUMMY Frontend"); | ||
274 | MODULE_AUTHOR("Emard"); | ||
275 | MODULE_LICENSE("GPL"); | ||
276 | |||
277 | EXPORT_SYMBOL(dvb_dummy_fe_ofdm_attach); | ||
278 | EXPORT_SYMBOL(dvb_dummy_fe_qam_attach); | ||
279 | EXPORT_SYMBOL(dvb_dummy_fe_qpsk_attach); | ||
diff --git a/drivers/media/dvb/frontends/dvb_dummy_fe.h b/drivers/media/dvb/frontends/dvb_dummy_fe.h new file mode 100644 index 000000000000..8210f19d56ce --- /dev/null +++ b/drivers/media/dvb/frontends/dvb_dummy_fe.h | |||
@@ -0,0 +1,32 @@ | |||
1 | /* | ||
2 | * Driver for Dummy Frontend | ||
3 | * | ||
4 | * Written by Emard <emard@softhome.net> | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License as published by | ||
8 | * the Free Software Foundation; either version 2 of the License, or | ||
9 | * (at your option) any later version. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * | ||
15 | * GNU General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program; if not, write to the Free Software | ||
19 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.= | ||
20 | */ | ||
21 | |||
22 | #ifndef DVB_DUMMY_FE_H | ||
23 | #define DVB_DUMMY_FE_H | ||
24 | |||
25 | #include <linux/dvb/frontend.h> | ||
26 | #include "dvb_frontend.h" | ||
27 | |||
28 | extern struct dvb_frontend* dvb_dummy_fe_ofdm_attach(void); | ||
29 | extern struct dvb_frontend* dvb_dummy_fe_qpsk_attach(void); | ||
30 | extern struct dvb_frontend* dvb_dummy_fe_qam_attach(void); | ||
31 | |||
32 | #endif // DVB_DUMMY_FE_H | ||
diff --git a/drivers/media/dvb/frontends/l64781.c b/drivers/media/dvb/frontends/l64781.c new file mode 100644 index 000000000000..9ac95de9834d --- /dev/null +++ b/drivers/media/dvb/frontends/l64781.c | |||
@@ -0,0 +1,602 @@ | |||
1 | /* | ||
2 | driver for LSI L64781 COFDM demodulator | ||
3 | |||
4 | Copyright (C) 2001 Holger Waechtler for Convergence Integrated Media GmbH | ||
5 | Marko Kohtala <marko.kohtala@luukku.com> | ||
6 | |||
7 | This program is free software; you can redistribute it and/or modify | ||
8 | it under the terms of the GNU General Public License as published by | ||
9 | the Free Software Foundation; either version 2 of the License, or | ||
10 | (at your option) any later version. | ||
11 | |||
12 | This program is distributed in the hope that it will be useful, | ||
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | GNU General Public License for more details. | ||
16 | |||
17 | You should have received a copy of the GNU General Public License | ||
18 | along with this program; if not, write to the Free Software | ||
19 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
20 | |||
21 | */ | ||
22 | |||
23 | #include <linux/init.h> | ||
24 | #include <linux/kernel.h> | ||
25 | #include <linux/module.h> | ||
26 | #include <linux/moduleparam.h> | ||
27 | #include <linux/string.h> | ||
28 | #include <linux/slab.h> | ||
29 | #include "dvb_frontend.h" | ||
30 | #include "l64781.h" | ||
31 | |||
32 | |||
33 | struct l64781_state { | ||
34 | struct i2c_adapter* i2c; | ||
35 | struct dvb_frontend_ops ops; | ||
36 | const struct l64781_config* config; | ||
37 | struct dvb_frontend frontend; | ||
38 | |||
39 | /* private demodulator data */ | ||
40 | int first:1; | ||
41 | }; | ||
42 | |||
43 | #define dprintk(args...) \ | ||
44 | do { \ | ||
45 | if (debug) printk(KERN_DEBUG "l64781: " args); \ | ||
46 | } while (0) | ||
47 | |||
48 | static int debug; | ||
49 | |||
50 | module_param(debug, int, 0644); | ||
51 | MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off)."); | ||
52 | |||
53 | |||
54 | static int l64781_writereg (struct l64781_state* state, u8 reg, u8 data) | ||
55 | { | ||
56 | int ret; | ||
57 | u8 buf [] = { reg, data }; | ||
58 | struct i2c_msg msg = { .addr = state->config->demod_address, .flags = 0, .buf = buf, .len = 2 }; | ||
59 | |||
60 | if ((ret = i2c_transfer(state->i2c, &msg, 1)) != 1) | ||
61 | dprintk ("%s: write_reg error (reg == %02x) = %02x!\n", | ||
62 | __FUNCTION__, reg, ret); | ||
63 | |||
64 | return (ret != 1) ? -1 : 0; | ||
65 | } | ||
66 | |||
67 | static int l64781_readreg (struct l64781_state* state, u8 reg) | ||
68 | { | ||
69 | int ret; | ||
70 | u8 b0 [] = { reg }; | ||
71 | u8 b1 [] = { 0 }; | ||
72 | struct i2c_msg msg [] = { { .addr = state->config->demod_address, .flags = 0, .buf = b0, .len = 1 }, | ||
73 | { .addr = state->config->demod_address, .flags = I2C_M_RD, .buf = b1, .len = 1 } }; | ||
74 | |||
75 | ret = i2c_transfer(state->i2c, msg, 2); | ||
76 | |||
77 | if (ret != 2) return ret; | ||
78 | |||
79 | return b1[0]; | ||
80 | } | ||
81 | |||
82 | static void apply_tps (struct l64781_state* state) | ||
83 | { | ||
84 | l64781_writereg (state, 0x2a, 0x00); | ||
85 | l64781_writereg (state, 0x2a, 0x01); | ||
86 | |||
87 | /* This here is a little bit questionable because it enables | ||
88 | the automatic update of TPS registers. I think we'd need to | ||
89 | handle the IRQ from FE to update some other registers as | ||
90 | well, or at least implement some magic to tuning to correct | ||
91 | to the TPS received from transmission. */ | ||
92 | l64781_writereg (state, 0x2a, 0x02); | ||
93 | } | ||
94 | |||
95 | |||
96 | static void reset_afc (struct l64781_state* state) | ||
97 | { | ||
98 | /* Set AFC stall for the AFC_INIT_FRQ setting, TIM_STALL for | ||
99 | timing offset */ | ||
100 | l64781_writereg (state, 0x07, 0x9e); /* stall AFC */ | ||
101 | l64781_writereg (state, 0x08, 0); /* AFC INIT FREQ */ | ||
102 | l64781_writereg (state, 0x09, 0); | ||
103 | l64781_writereg (state, 0x0a, 0); | ||
104 | l64781_writereg (state, 0x07, 0x8e); | ||
105 | l64781_writereg (state, 0x0e, 0); /* AGC gain to zero in beginning */ | ||
106 | l64781_writereg (state, 0x11, 0x80); /* stall TIM */ | ||
107 | l64781_writereg (state, 0x10, 0); /* TIM_OFFSET_LSB */ | ||
108 | l64781_writereg (state, 0x12, 0); | ||
109 | l64781_writereg (state, 0x13, 0); | ||
110 | l64781_writereg (state, 0x11, 0x00); | ||
111 | } | ||
112 | |||
113 | static int reset_and_configure (struct l64781_state* state) | ||
114 | { | ||
115 | u8 buf [] = { 0x06 }; | ||
116 | struct i2c_msg msg = { .addr = 0x00, .flags = 0, .buf = buf, .len = 1 }; | ||
117 | // NOTE: this is correct in writing to address 0x00 | ||
118 | |||
119 | return (i2c_transfer(state->i2c, &msg, 1) == 1) ? 0 : -ENODEV; | ||
120 | } | ||
121 | |||
122 | static int apply_frontend_param (struct dvb_frontend* fe, struct dvb_frontend_parameters *param) | ||
123 | { | ||
124 | struct l64781_state* state = (struct l64781_state*) fe->demodulator_priv; | ||
125 | /* The coderates for FEC_NONE, FEC_4_5 and FEC_FEC_6_7 are arbitrary */ | ||
126 | static const u8 fec_tab[] = { 7, 0, 1, 2, 9, 3, 10, 4 }; | ||
127 | /* QPSK, QAM_16, QAM_64 */ | ||
128 | static const u8 qam_tab [] = { 2, 4, 0, 6 }; | ||
129 | static const u8 bw_tab [] = { 8, 7, 6 }; /* 8Mhz, 7MHz, 6MHz */ | ||
130 | static const u8 guard_tab [] = { 1, 2, 4, 8 }; | ||
131 | /* The Grundig 29504-401.04 Tuner comes with 18.432MHz crystal. */ | ||
132 | static const u32 ppm = 8000; | ||
133 | struct dvb_ofdm_parameters *p = ¶m->u.ofdm; | ||
134 | u32 ddfs_offset_fixed; | ||
135 | /* u32 ddfs_offset_variable = 0x6000-((1000000UL+ppm)/ */ | ||
136 | /* bw_tab[p->bandWidth]<<10)/15625; */ | ||
137 | u32 init_freq; | ||
138 | u32 spi_bias; | ||
139 | u8 val0x04; | ||
140 | u8 val0x05; | ||
141 | u8 val0x06; | ||
142 | int bw = p->bandwidth - BANDWIDTH_8_MHZ; | ||
143 | |||
144 | state->config->pll_set(fe, param); | ||
145 | |||
146 | if (param->inversion != INVERSION_ON && | ||
147 | param->inversion != INVERSION_OFF) | ||
148 | return -EINVAL; | ||
149 | |||
150 | if (bw < 0 || bw > 2) | ||
151 | return -EINVAL; | ||
152 | |||
153 | if (p->code_rate_HP != FEC_1_2 && p->code_rate_HP != FEC_2_3 && | ||
154 | p->code_rate_HP != FEC_3_4 && p->code_rate_HP != FEC_5_6 && | ||
155 | p->code_rate_HP != FEC_7_8) | ||
156 | return -EINVAL; | ||
157 | |||
158 | if (p->hierarchy_information != HIERARCHY_NONE && | ||
159 | (p->code_rate_LP != FEC_1_2 && p->code_rate_LP != FEC_2_3 && | ||
160 | p->code_rate_LP != FEC_3_4 && p->code_rate_LP != FEC_5_6 && | ||
161 | p->code_rate_LP != FEC_7_8)) | ||
162 | return -EINVAL; | ||
163 | |||
164 | if (p->constellation != QPSK && p->constellation != QAM_16 && | ||
165 | p->constellation != QAM_64) | ||
166 | return -EINVAL; | ||
167 | |||
168 | if (p->transmission_mode != TRANSMISSION_MODE_2K && | ||
169 | p->transmission_mode != TRANSMISSION_MODE_8K) | ||
170 | return -EINVAL; | ||
171 | |||
172 | if (p->guard_interval < GUARD_INTERVAL_1_32 || | ||
173 | p->guard_interval > GUARD_INTERVAL_1_4) | ||
174 | return -EINVAL; | ||
175 | |||
176 | if (p->hierarchy_information < HIERARCHY_NONE || | ||
177 | p->hierarchy_information > HIERARCHY_4) | ||
178 | return -EINVAL; | ||
179 | |||
180 | ddfs_offset_fixed = 0x4000-(ppm<<16)/bw_tab[p->bandwidth]/1000000; | ||
181 | |||
182 | /* This works up to 20000 ppm, it overflows if too large ppm! */ | ||
183 | init_freq = (((8UL<<25) + (8UL<<19) / 25*ppm / (15625/25)) / | ||
184 | bw_tab[p->bandwidth] & 0xFFFFFF); | ||
185 | |||
186 | /* SPI bias calculation is slightly modified to fit in 32bit */ | ||
187 | /* will work for high ppm only... */ | ||
188 | spi_bias = 378 * (1 << 10); | ||
189 | spi_bias *= 16; | ||
190 | spi_bias *= bw_tab[p->bandwidth]; | ||
191 | spi_bias *= qam_tab[p->constellation]; | ||
192 | spi_bias /= p->code_rate_HP + 1; | ||
193 | spi_bias /= (guard_tab[p->guard_interval] + 32); | ||
194 | spi_bias *= 1000ULL; | ||
195 | spi_bias /= 1000ULL + ppm/1000; | ||
196 | spi_bias *= p->code_rate_HP; | ||
197 | |||
198 | val0x04 = (p->transmission_mode << 2) | p->guard_interval; | ||
199 | val0x05 = fec_tab[p->code_rate_HP]; | ||
200 | |||
201 | if (p->hierarchy_information != HIERARCHY_NONE) | ||
202 | val0x05 |= (p->code_rate_LP - FEC_1_2) << 3; | ||
203 | |||
204 | val0x06 = (p->hierarchy_information << 2) | p->constellation; | ||
205 | |||
206 | l64781_writereg (state, 0x04, val0x04); | ||
207 | l64781_writereg (state, 0x05, val0x05); | ||
208 | l64781_writereg (state, 0x06, val0x06); | ||
209 | |||
210 | reset_afc (state); | ||
211 | |||
212 | /* Technical manual section 2.6.1, TIM_IIR_GAIN optimal values */ | ||
213 | l64781_writereg (state, 0x15, | ||
214 | p->transmission_mode == TRANSMISSION_MODE_2K ? 1 : 3); | ||
215 | l64781_writereg (state, 0x16, init_freq & 0xff); | ||
216 | l64781_writereg (state, 0x17, (init_freq >> 8) & 0xff); | ||
217 | l64781_writereg (state, 0x18, (init_freq >> 16) & 0xff); | ||
218 | |||
219 | l64781_writereg (state, 0x1b, spi_bias & 0xff); | ||
220 | l64781_writereg (state, 0x1c, (spi_bias >> 8) & 0xff); | ||
221 | l64781_writereg (state, 0x1d, ((spi_bias >> 16) & 0x7f) | | ||
222 | (param->inversion == INVERSION_ON ? 0x80 : 0x00)); | ||
223 | |||
224 | l64781_writereg (state, 0x22, ddfs_offset_fixed & 0xff); | ||
225 | l64781_writereg (state, 0x23, (ddfs_offset_fixed >> 8) & 0x3f); | ||
226 | |||
227 | l64781_readreg (state, 0x00); /* clear interrupt registers... */ | ||
228 | l64781_readreg (state, 0x01); /* dto. */ | ||
229 | |||
230 | apply_tps (state); | ||
231 | |||
232 | return 0; | ||
233 | } | ||
234 | |||
235 | static int get_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters* param) | ||
236 | { | ||
237 | struct l64781_state* state = (struct l64781_state*) fe->demodulator_priv; | ||
238 | int tmp; | ||
239 | |||
240 | |||
241 | tmp = l64781_readreg(state, 0x04); | ||
242 | switch(tmp & 3) { | ||
243 | case 0: | ||
244 | param->u.ofdm.guard_interval = GUARD_INTERVAL_1_32; | ||
245 | break; | ||
246 | case 1: | ||
247 | param->u.ofdm.guard_interval = GUARD_INTERVAL_1_16; | ||
248 | break; | ||
249 | case 2: | ||
250 | param->u.ofdm.guard_interval = GUARD_INTERVAL_1_8; | ||
251 | break; | ||
252 | case 3: | ||
253 | param->u.ofdm.guard_interval = GUARD_INTERVAL_1_4; | ||
254 | break; | ||
255 | } | ||
256 | switch((tmp >> 2) & 3) { | ||
257 | case 0: | ||
258 | param->u.ofdm.transmission_mode = TRANSMISSION_MODE_2K; | ||
259 | break; | ||
260 | case 1: | ||
261 | param->u.ofdm.transmission_mode = TRANSMISSION_MODE_8K; | ||
262 | break; | ||
263 | default: | ||
264 | printk("Unexpected value for transmission_mode\n"); | ||
265 | } | ||
266 | |||
267 | |||
268 | |||
269 | tmp = l64781_readreg(state, 0x05); | ||
270 | switch(tmp & 7) { | ||
271 | case 0: | ||
272 | param->u.ofdm.code_rate_HP = FEC_1_2; | ||
273 | break; | ||
274 | case 1: | ||
275 | param->u.ofdm.code_rate_HP = FEC_2_3; | ||
276 | break; | ||
277 | case 2: | ||
278 | param->u.ofdm.code_rate_HP = FEC_3_4; | ||
279 | break; | ||
280 | case 3: | ||
281 | param->u.ofdm.code_rate_HP = FEC_5_6; | ||
282 | break; | ||
283 | case 4: | ||
284 | param->u.ofdm.code_rate_HP = FEC_7_8; | ||
285 | break; | ||
286 | default: | ||
287 | printk("Unexpected value for code_rate_HP\n"); | ||
288 | } | ||
289 | switch((tmp >> 3) & 7) { | ||
290 | case 0: | ||
291 | param->u.ofdm.code_rate_LP = FEC_1_2; | ||
292 | break; | ||
293 | case 1: | ||
294 | param->u.ofdm.code_rate_LP = FEC_2_3; | ||
295 | break; | ||
296 | case 2: | ||
297 | param->u.ofdm.code_rate_LP = FEC_3_4; | ||
298 | break; | ||
299 | case 3: | ||
300 | param->u.ofdm.code_rate_LP = FEC_5_6; | ||
301 | break; | ||
302 | case 4: | ||
303 | param->u.ofdm.code_rate_LP = FEC_7_8; | ||
304 | break; | ||
305 | default: | ||
306 | printk("Unexpected value for code_rate_LP\n"); | ||
307 | } | ||
308 | |||
309 | |||
310 | tmp = l64781_readreg(state, 0x06); | ||
311 | switch(tmp & 3) { | ||
312 | case 0: | ||
313 | param->u.ofdm.constellation = QPSK; | ||
314 | break; | ||
315 | case 1: | ||
316 | param->u.ofdm.constellation = QAM_16; | ||
317 | break; | ||
318 | case 2: | ||
319 | param->u.ofdm.constellation = QAM_64; | ||
320 | break; | ||
321 | default: | ||
322 | printk("Unexpected value for constellation\n"); | ||
323 | } | ||
324 | switch((tmp >> 2) & 7) { | ||
325 | case 0: | ||
326 | param->u.ofdm.hierarchy_information = HIERARCHY_NONE; | ||
327 | break; | ||
328 | case 1: | ||
329 | param->u.ofdm.hierarchy_information = HIERARCHY_1; | ||
330 | break; | ||
331 | case 2: | ||
332 | param->u.ofdm.hierarchy_information = HIERARCHY_2; | ||
333 | break; | ||
334 | case 3: | ||
335 | param->u.ofdm.hierarchy_information = HIERARCHY_4; | ||
336 | break; | ||
337 | default: | ||
338 | printk("Unexpected value for hierarchy\n"); | ||
339 | } | ||
340 | |||
341 | |||
342 | tmp = l64781_readreg (state, 0x1d); | ||
343 | param->inversion = (tmp & 0x80) ? INVERSION_ON : INVERSION_OFF; | ||
344 | |||
345 | tmp = (int) (l64781_readreg (state, 0x08) | | ||
346 | (l64781_readreg (state, 0x09) << 8) | | ||
347 | (l64781_readreg (state, 0x0a) << 16)); | ||
348 | param->frequency += tmp; | ||
349 | |||
350 | return 0; | ||
351 | } | ||
352 | |||
353 | static int l64781_read_status(struct dvb_frontend* fe, fe_status_t* status) | ||
354 | { | ||
355 | struct l64781_state* state = (struct l64781_state*) fe->demodulator_priv; | ||
356 | int sync = l64781_readreg (state, 0x32); | ||
357 | int gain = l64781_readreg (state, 0x0e); | ||
358 | |||
359 | l64781_readreg (state, 0x00); /* clear interrupt registers... */ | ||
360 | l64781_readreg (state, 0x01); /* dto. */ | ||
361 | |||
362 | *status = 0; | ||
363 | |||
364 | if (gain > 5) | ||
365 | *status |= FE_HAS_SIGNAL; | ||
366 | |||
367 | if (sync & 0x02) /* VCXO locked, this criteria should be ok */ | ||
368 | *status |= FE_HAS_CARRIER; | ||
369 | |||
370 | if (sync & 0x20) | ||
371 | *status |= FE_HAS_VITERBI; | ||
372 | |||
373 | if (sync & 0x40) | ||
374 | *status |= FE_HAS_SYNC; | ||
375 | |||
376 | if (sync == 0x7f) | ||
377 | *status |= FE_HAS_LOCK; | ||
378 | |||
379 | return 0; | ||
380 | } | ||
381 | |||
382 | static int l64781_read_ber(struct dvb_frontend* fe, u32* ber) | ||
383 | { | ||
384 | struct l64781_state* state = (struct l64781_state*) fe->demodulator_priv; | ||
385 | |||
386 | /* XXX FIXME: set up counting period (reg 0x26...0x28) | ||
387 | */ | ||
388 | *ber = l64781_readreg (state, 0x39) | ||
389 | | (l64781_readreg (state, 0x3a) << 8); | ||
390 | |||
391 | return 0; | ||
392 | } | ||
393 | |||
394 | static int l64781_read_signal_strength(struct dvb_frontend* fe, u16* signal_strength) | ||
395 | { | ||
396 | struct l64781_state* state = (struct l64781_state*) fe->demodulator_priv; | ||
397 | |||
398 | u8 gain = l64781_readreg (state, 0x0e); | ||
399 | *signal_strength = (gain << 8) | gain; | ||
400 | |||
401 | return 0; | ||
402 | } | ||
403 | |||
404 | static int l64781_read_snr(struct dvb_frontend* fe, u16* snr) | ||
405 | { | ||
406 | struct l64781_state* state = (struct l64781_state*) fe->demodulator_priv; | ||
407 | |||
408 | u8 avg_quality = 0xff - l64781_readreg (state, 0x33); | ||
409 | *snr = (avg_quality << 8) | avg_quality; /* not exact, but...*/ | ||
410 | |||
411 | return 0; | ||
412 | } | ||
413 | |||
414 | static int l64781_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks) | ||
415 | { | ||
416 | struct l64781_state* state = (struct l64781_state*) fe->demodulator_priv; | ||
417 | |||
418 | *ucblocks = l64781_readreg (state, 0x37) | ||
419 | | (l64781_readreg (state, 0x38) << 8); | ||
420 | |||
421 | return 0; | ||
422 | } | ||
423 | |||
424 | static int l64781_sleep(struct dvb_frontend* fe) | ||
425 | { | ||
426 | struct l64781_state* state = (struct l64781_state*) fe->demodulator_priv; | ||
427 | |||
428 | /* Power down */ | ||
429 | return l64781_writereg (state, 0x3e, 0x5a); | ||
430 | } | ||
431 | |||
432 | static int l64781_init(struct dvb_frontend* fe) | ||
433 | { | ||
434 | struct l64781_state* state = (struct l64781_state*) fe->demodulator_priv; | ||
435 | |||
436 | reset_and_configure (state); | ||
437 | |||
438 | /* Power up */ | ||
439 | l64781_writereg (state, 0x3e, 0xa5); | ||
440 | |||
441 | /* Reset hard */ | ||
442 | l64781_writereg (state, 0x2a, 0x04); | ||
443 | l64781_writereg (state, 0x2a, 0x00); | ||
444 | |||
445 | /* Set tuner specific things */ | ||
446 | /* AFC_POL, set also in reset_afc */ | ||
447 | l64781_writereg (state, 0x07, 0x8e); | ||
448 | |||
449 | /* Use internal ADC */ | ||
450 | l64781_writereg (state, 0x0b, 0x81); | ||
451 | |||
452 | /* AGC loop gain, and polarity is positive */ | ||
453 | l64781_writereg (state, 0x0c, 0x84); | ||
454 | |||
455 | /* Internal ADC outputs two's complement */ | ||
456 | l64781_writereg (state, 0x0d, 0x8c); | ||
457 | |||
458 | /* With ppm=8000, it seems the DTR_SENSITIVITY will result in | ||
459 | value of 2 with all possible bandwidths and guard | ||
460 | intervals, which is the initial value anyway. */ | ||
461 | /*l64781_writereg (state, 0x19, 0x92);*/ | ||
462 | |||
463 | /* Everything is two's complement, soft bit and CSI_OUT too */ | ||
464 | l64781_writereg (state, 0x1e, 0x09); | ||
465 | |||
466 | if (state->config->pll_init) state->config->pll_init(fe); | ||
467 | |||
468 | /* delay a bit after first init attempt */ | ||
469 | if (state->first) { | ||
470 | state->first = 0; | ||
471 | msleep(200); | ||
472 | } | ||
473 | |||
474 | return 0; | ||
475 | } | ||
476 | |||
477 | static int l64781_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings* fesettings) | ||
478 | { | ||
479 | fesettings->min_delay_ms = 200; | ||
480 | fesettings->step_size = 166667; | ||
481 | fesettings->max_drift = 166667*2; | ||
482 | return 0; | ||
483 | } | ||
484 | |||
485 | static void l64781_release(struct dvb_frontend* fe) | ||
486 | { | ||
487 | struct l64781_state* state = (struct l64781_state*) fe->demodulator_priv; | ||
488 | kfree(state); | ||
489 | } | ||
490 | |||
491 | static struct dvb_frontend_ops l64781_ops; | ||
492 | |||
493 | struct dvb_frontend* l64781_attach(const struct l64781_config* config, | ||
494 | struct i2c_adapter* i2c) | ||
495 | { | ||
496 | struct l64781_state* state = NULL; | ||
497 | int reg0x3e = -1; | ||
498 | u8 b0 [] = { 0x1a }; | ||
499 | u8 b1 [] = { 0x00 }; | ||
500 | struct i2c_msg msg [] = { { .addr = config->demod_address, .flags = 0, .buf = b0, .len = 1 }, | ||
501 | { .addr = config->demod_address, .flags = I2C_M_RD, .buf = b1, .len = 1 } }; | ||
502 | |||
503 | /* allocate memory for the internal state */ | ||
504 | state = (struct l64781_state*) kmalloc(sizeof(struct l64781_state), GFP_KERNEL); | ||
505 | if (state == NULL) goto error; | ||
506 | |||
507 | /* setup the state */ | ||
508 | state->config = config; | ||
509 | state->i2c = i2c; | ||
510 | memcpy(&state->ops, &l64781_ops, sizeof(struct dvb_frontend_ops)); | ||
511 | state->first = 1; | ||
512 | |||
513 | /** | ||
514 | * the L64781 won't show up before we send the reset_and_configure() | ||
515 | * broadcast. If nothing responds there is no L64781 on the bus... | ||
516 | */ | ||
517 | if (reset_and_configure(state) < 0) { | ||
518 | dprintk("No response to reset and configure broadcast...\n"); | ||
519 | goto error; | ||
520 | } | ||
521 | |||
522 | /* The chip always responds to reads */ | ||
523 | if (i2c_transfer(state->i2c, msg, 2) != 2) { | ||
524 | dprintk("No response to read on I2C bus\n"); | ||
525 | goto error; | ||
526 | } | ||
527 | |||
528 | /* Save current register contents for bailout */ | ||
529 | reg0x3e = l64781_readreg(state, 0x3e); | ||
530 | |||
531 | /* Reading the POWER_DOWN register always returns 0 */ | ||
532 | if (reg0x3e != 0) { | ||
533 | dprintk("Device doesn't look like L64781\n"); | ||
534 | goto error; | ||
535 | } | ||
536 | |||
537 | /* Turn the chip off */ | ||
538 | l64781_writereg (state, 0x3e, 0x5a); | ||
539 | |||
540 | /* Responds to all reads with 0 */ | ||
541 | if (l64781_readreg(state, 0x1a) != 0) { | ||
542 | dprintk("Read 1 returned unexpcted value\n"); | ||
543 | goto error; | ||
544 | } | ||
545 | |||
546 | /* Turn the chip on */ | ||
547 | l64781_writereg (state, 0x3e, 0xa5); | ||
548 | |||
549 | /* Responds with register default value */ | ||
550 | if (l64781_readreg(state, 0x1a) != 0xa1) { | ||
551 | dprintk("Read 2 returned unexpcted value\n"); | ||
552 | goto error; | ||
553 | } | ||
554 | |||
555 | /* create dvb_frontend */ | ||
556 | state->frontend.ops = &state->ops; | ||
557 | state->frontend.demodulator_priv = state; | ||
558 | return &state->frontend; | ||
559 | |||
560 | error: | ||
561 | if (reg0x3e >= 0) l64781_writereg (state, 0x3e, reg0x3e); /* restore reg 0x3e */ | ||
562 | kfree(state); | ||
563 | return NULL; | ||
564 | } | ||
565 | |||
566 | static struct dvb_frontend_ops l64781_ops = { | ||
567 | |||
568 | .info = { | ||
569 | .name = "LSI L64781 DVB-T", | ||
570 | .type = FE_OFDM, | ||
571 | /* .frequency_min = ???,*/ | ||
572 | /* .frequency_max = ???,*/ | ||
573 | .frequency_stepsize = 166666, | ||
574 | /* .frequency_tolerance = ???,*/ | ||
575 | /* .symbol_rate_tolerance = ???,*/ | ||
576 | .caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | | ||
577 | FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | | ||
578 | FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | | ||
579 | FE_CAN_MUTE_TS | ||
580 | }, | ||
581 | |||
582 | .release = l64781_release, | ||
583 | |||
584 | .init = l64781_init, | ||
585 | .sleep = l64781_sleep, | ||
586 | |||
587 | .set_frontend = apply_frontend_param, | ||
588 | .get_frontend = get_frontend, | ||
589 | .get_tune_settings = l64781_get_tune_settings, | ||
590 | |||
591 | .read_status = l64781_read_status, | ||
592 | .read_ber = l64781_read_ber, | ||
593 | .read_signal_strength = l64781_read_signal_strength, | ||
594 | .read_snr = l64781_read_snr, | ||
595 | .read_ucblocks = l64781_read_ucblocks, | ||
596 | }; | ||
597 | |||
598 | MODULE_DESCRIPTION("LSI L64781 DVB-T Demodulator driver"); | ||
599 | MODULE_AUTHOR("Holger Waechtler, Marko Kohtala"); | ||
600 | MODULE_LICENSE("GPL"); | ||
601 | |||
602 | EXPORT_SYMBOL(l64781_attach); | ||
diff --git a/drivers/media/dvb/frontends/l64781.h b/drivers/media/dvb/frontends/l64781.h new file mode 100644 index 000000000000..7e30fb0fdfa7 --- /dev/null +++ b/drivers/media/dvb/frontends/l64781.h | |||
@@ -0,0 +1,42 @@ | |||
1 | /* | ||
2 | driver for LSI L64781 COFDM demodulator | ||
3 | |||
4 | Copyright (C) 2001 Holger Waechtler for Convergence Integrated Media GmbH | ||
5 | Marko Kohtala <marko.kohtala@luukku.com> | ||
6 | |||
7 | This program is free software; you can redistribute it and/or modify | ||
8 | it under the terms of the GNU General Public License as published by | ||
9 | the Free Software Foundation; either version 2 of the License, or | ||
10 | (at your option) any later version. | ||
11 | |||
12 | This program is distributed in the hope that it will be useful, | ||
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | GNU General Public License for more details. | ||
16 | |||
17 | You should have received a copy of the GNU General Public License | ||
18 | along with this program; if not, write to the Free Software | ||
19 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
20 | |||
21 | */ | ||
22 | |||
23 | #ifndef L64781_H | ||
24 | #define L64781_H | ||
25 | |||
26 | #include <linux/dvb/frontend.h> | ||
27 | |||
28 | struct l64781_config | ||
29 | { | ||
30 | /* the demodulator's i2c address */ | ||
31 | u8 demod_address; | ||
32 | |||
33 | /* PLL maintenance */ | ||
34 | int (*pll_init)(struct dvb_frontend* fe); | ||
35 | int (*pll_set)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params); | ||
36 | }; | ||
37 | |||
38 | |||
39 | extern struct dvb_frontend* l64781_attach(const struct l64781_config* config, | ||
40 | struct i2c_adapter* i2c); | ||
41 | |||
42 | #endif // L64781_H | ||
diff --git a/drivers/media/dvb/frontends/mt312.c b/drivers/media/dvb/frontends/mt312.c new file mode 100644 index 000000000000..176a22e3441b --- /dev/null +++ b/drivers/media/dvb/frontends/mt312.c | |||
@@ -0,0 +1,729 @@ | |||
1 | /* | ||
2 | Driver for Zarlink VP310/MT312 Satellite Channel Decoder | ||
3 | |||
4 | Copyright (C) 2003 Andreas Oberritter <obi@linuxtv.org> | ||
5 | |||
6 | This program is free software; you can redistribute it and/or modify | ||
7 | it under the terms of the GNU General Public License as published by | ||
8 | the Free Software Foundation; either version 2 of the License, or | ||
9 | (at your option) any later version. | ||
10 | |||
11 | This program is distributed in the hope that it will be useful, | ||
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | |||
15 | GNU General Public License for more details. | ||
16 | |||
17 | You should have received a copy of the GNU General Public License | ||
18 | along with this program; if not, write to the Free Software | ||
19 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
20 | |||
21 | References: | ||
22 | http://products.zarlink.com/product_profiles/MT312.htm | ||
23 | http://products.zarlink.com/product_profiles/SL1935.htm | ||
24 | */ | ||
25 | |||
26 | #include <linux/delay.h> | ||
27 | #include <linux/errno.h> | ||
28 | #include <linux/init.h> | ||
29 | #include <linux/kernel.h> | ||
30 | #include <linux/module.h> | ||
31 | #include <linux/moduleparam.h> | ||
32 | |||
33 | #include "dvb_frontend.h" | ||
34 | #include "mt312_priv.h" | ||
35 | #include "mt312.h" | ||
36 | |||
37 | |||
38 | struct mt312_state { | ||
39 | struct i2c_adapter* i2c; | ||
40 | struct dvb_frontend_ops ops; | ||
41 | /* configuration settings */ | ||
42 | const struct mt312_config* config; | ||
43 | struct dvb_frontend frontend; | ||
44 | |||
45 | u8 id; | ||
46 | u8 frequency; | ||
47 | }; | ||
48 | |||
49 | static int debug; | ||
50 | #define dprintk(args...) \ | ||
51 | do { \ | ||
52 | if (debug) printk(KERN_DEBUG "mt312: " args); \ | ||
53 | } while (0) | ||
54 | |||
55 | #define MT312_SYS_CLK 90000000UL /* 90 MHz */ | ||
56 | #define MT312_LPOWER_SYS_CLK 60000000UL /* 60 MHz */ | ||
57 | #define MT312_PLL_CLK 10000000UL /* 10 MHz */ | ||
58 | |||
59 | static int mt312_read(struct mt312_state* state, const enum mt312_reg_addr reg, | ||
60 | void *buf, const size_t count) | ||
61 | { | ||
62 | int ret; | ||
63 | struct i2c_msg msg[2]; | ||
64 | u8 regbuf[1] = { reg }; | ||
65 | |||
66 | msg[0].addr = state->config->demod_address; | ||
67 | msg[0].flags = 0; | ||
68 | msg[0].buf = regbuf; | ||
69 | msg[0].len = 1; | ||
70 | msg[1].addr = state->config->demod_address; | ||
71 | msg[1].flags = I2C_M_RD; | ||
72 | msg[1].buf = buf; | ||
73 | msg[1].len = count; | ||
74 | |||
75 | ret = i2c_transfer(state->i2c, msg, 2); | ||
76 | |||
77 | if (ret != 2) { | ||
78 | printk(KERN_ERR "%s: ret == %d\n", __FUNCTION__, ret); | ||
79 | return -EREMOTEIO; | ||
80 | } | ||
81 | |||
82 | if(debug) { | ||
83 | int i; | ||
84 | dprintk("R(%d):", reg & 0x7f); | ||
85 | for (i = 0; i < count; i++) | ||
86 | printk(" %02x", ((const u8 *) buf)[i]); | ||
87 | printk("\n"); | ||
88 | } | ||
89 | |||
90 | return 0; | ||
91 | } | ||
92 | |||
93 | static int mt312_write(struct mt312_state* state, const enum mt312_reg_addr reg, | ||
94 | const void *src, const size_t count) | ||
95 | { | ||
96 | int ret; | ||
97 | u8 buf[count + 1]; | ||
98 | struct i2c_msg msg; | ||
99 | |||
100 | if(debug) { | ||
101 | int i; | ||
102 | dprintk("W(%d):", reg & 0x7f); | ||
103 | for (i = 0; i < count; i++) | ||
104 | printk(" %02x", ((const u8 *) src)[i]); | ||
105 | printk("\n"); | ||
106 | } | ||
107 | |||
108 | buf[0] = reg; | ||
109 | memcpy(&buf[1], src, count); | ||
110 | |||
111 | msg.addr = state->config->demod_address; | ||
112 | msg.flags = 0; | ||
113 | msg.buf = buf; | ||
114 | msg.len = count + 1; | ||
115 | |||
116 | ret = i2c_transfer(state->i2c, &msg, 1); | ||
117 | |||
118 | if (ret != 1) { | ||
119 | dprintk("%s: ret == %d\n", __FUNCTION__, ret); | ||
120 | return -EREMOTEIO; | ||
121 | } | ||
122 | |||
123 | return 0; | ||
124 | } | ||
125 | |||
126 | static inline int mt312_readreg(struct mt312_state* state, | ||
127 | const enum mt312_reg_addr reg, u8 *val) | ||
128 | { | ||
129 | return mt312_read(state, reg, val, 1); | ||
130 | } | ||
131 | |||
132 | static inline int mt312_writereg(struct mt312_state* state, | ||
133 | const enum mt312_reg_addr reg, const u8 val) | ||
134 | { | ||
135 | return mt312_write(state, reg, &val, 1); | ||
136 | } | ||
137 | |||
138 | static inline u32 mt312_div(u32 a, u32 b) | ||
139 | { | ||
140 | return (a + (b / 2)) / b; | ||
141 | } | ||
142 | |||
143 | static int mt312_reset(struct mt312_state* state, const u8 full) | ||
144 | { | ||
145 | return mt312_writereg(state, RESET, full ? 0x80 : 0x40); | ||
146 | } | ||
147 | |||
148 | static int mt312_get_inversion(struct mt312_state* state, | ||
149 | fe_spectral_inversion_t *i) | ||
150 | { | ||
151 | int ret; | ||
152 | u8 vit_mode; | ||
153 | |||
154 | if ((ret = mt312_readreg(state, VIT_MODE, &vit_mode)) < 0) | ||
155 | return ret; | ||
156 | |||
157 | if (vit_mode & 0x80) /* auto inversion was used */ | ||
158 | *i = (vit_mode & 0x40) ? INVERSION_ON : INVERSION_OFF; | ||
159 | |||
160 | return 0; | ||
161 | } | ||
162 | |||
163 | static int mt312_get_symbol_rate(struct mt312_state* state, u32 *sr) | ||
164 | { | ||
165 | int ret; | ||
166 | u8 sym_rate_h; | ||
167 | u8 dec_ratio; | ||
168 | u16 sym_rat_op; | ||
169 | u16 monitor; | ||
170 | u8 buf[2]; | ||
171 | |||
172 | if ((ret = mt312_readreg(state, SYM_RATE_H, &sym_rate_h)) < 0) | ||
173 | return ret; | ||
174 | |||
175 | if (sym_rate_h & 0x80) { /* symbol rate search was used */ | ||
176 | if ((ret = mt312_writereg(state, MON_CTRL, 0x03)) < 0) | ||
177 | return ret; | ||
178 | |||
179 | if ((ret = mt312_read(state, MONITOR_H, buf, sizeof(buf))) < 0) | ||
180 | return ret; | ||
181 | |||
182 | monitor = (buf[0] << 8) | buf[1]; | ||
183 | |||
184 | dprintk(KERN_DEBUG "sr(auto) = %u\n", | ||
185 | mt312_div(monitor * 15625, 4)); | ||
186 | } else { | ||
187 | if ((ret = mt312_writereg(state, MON_CTRL, 0x05)) < 0) | ||
188 | return ret; | ||
189 | |||
190 | if ((ret = mt312_read(state, MONITOR_H, buf, sizeof(buf))) < 0) | ||
191 | return ret; | ||
192 | |||
193 | dec_ratio = ((buf[0] >> 5) & 0x07) * 32; | ||
194 | |||
195 | if ((ret = mt312_read(state, SYM_RAT_OP_H, buf, sizeof(buf))) < 0) | ||
196 | return ret; | ||
197 | |||
198 | sym_rat_op = (buf[0] << 8) | buf[1]; | ||
199 | |||
200 | dprintk(KERN_DEBUG "sym_rat_op=%d dec_ratio=%d\n", | ||
201 | sym_rat_op, dec_ratio); | ||
202 | dprintk(KERN_DEBUG "*sr(manual) = %lu\n", | ||
203 | (((MT312_PLL_CLK * 8192) / (sym_rat_op + 8192)) * | ||
204 | 2) - dec_ratio); | ||
205 | } | ||
206 | |||
207 | return 0; | ||
208 | } | ||
209 | |||
210 | static int mt312_get_code_rate(struct mt312_state* state, fe_code_rate_t *cr) | ||
211 | { | ||
212 | const fe_code_rate_t fec_tab[8] = | ||
213 | { FEC_1_2, FEC_2_3, FEC_3_4, FEC_5_6, FEC_6_7, FEC_7_8, | ||
214 | FEC_AUTO, FEC_AUTO }; | ||
215 | |||
216 | int ret; | ||
217 | u8 fec_status; | ||
218 | |||
219 | if ((ret = mt312_readreg(state, FEC_STATUS, &fec_status)) < 0) | ||
220 | return ret; | ||
221 | |||
222 | *cr = fec_tab[(fec_status >> 4) & 0x07]; | ||
223 | |||
224 | return 0; | ||
225 | } | ||
226 | |||
227 | static int mt312_initfe(struct dvb_frontend* fe) | ||
228 | { | ||
229 | struct mt312_state *state = (struct mt312_state*) fe->demodulator_priv; | ||
230 | int ret; | ||
231 | u8 buf[2]; | ||
232 | |||
233 | /* wake up */ | ||
234 | if ((ret = mt312_writereg(state, CONFIG, (state->frequency == 60 ? 0x88 : 0x8c))) < 0) | ||
235 | return ret; | ||
236 | |||
237 | /* wait at least 150 usec */ | ||
238 | udelay(150); | ||
239 | |||
240 | /* full reset */ | ||
241 | if ((ret = mt312_reset(state, 1)) < 0) | ||
242 | return ret; | ||
243 | |||
244 | // Per datasheet, write correct values. 09/28/03 ACCJr. | ||
245 | // If we don't do this, we won't get FE_HAS_VITERBI in the VP310. | ||
246 | { | ||
247 | u8 buf_def[8]={0x14, 0x12, 0x03, 0x02, 0x01, 0x00, 0x00, 0x00}; | ||
248 | |||
249 | if ((ret = mt312_write(state, VIT_SETUP, buf_def, sizeof(buf_def))) < 0) | ||
250 | return ret; | ||
251 | } | ||
252 | |||
253 | /* SYS_CLK */ | ||
254 | buf[0] = mt312_div((state->frequency == 60 ? MT312_LPOWER_SYS_CLK : MT312_SYS_CLK) * 2, 1000000); | ||
255 | |||
256 | /* DISEQC_RATIO */ | ||
257 | buf[1] = mt312_div(MT312_PLL_CLK, 15000 * 4); | ||
258 | |||
259 | if ((ret = mt312_write(state, SYS_CLK, buf, sizeof(buf))) < 0) | ||
260 | return ret; | ||
261 | |||
262 | if ((ret = mt312_writereg(state, SNR_THS_HIGH, 0x32)) < 0) | ||
263 | return ret; | ||
264 | |||
265 | if ((ret = mt312_writereg(state, OP_CTRL, 0x53)) < 0) | ||
266 | return ret; | ||
267 | |||
268 | /* TS_SW_LIM */ | ||
269 | buf[0] = 0x8c; | ||
270 | buf[1] = 0x98; | ||
271 | |||
272 | if ((ret = mt312_write(state, TS_SW_LIM_L, buf, sizeof(buf))) < 0) | ||
273 | return ret; | ||
274 | |||
275 | if ((ret = mt312_writereg(state, CS_SW_LIM, 0x69)) < 0) | ||
276 | return ret; | ||
277 | |||
278 | if (state->config->pll_init) { | ||
279 | mt312_writereg(state, GPP_CTRL, 0x40); | ||
280 | state->config->pll_init(fe); | ||
281 | mt312_writereg(state, GPP_CTRL, 0x00); | ||
282 | } | ||
283 | |||
284 | return 0; | ||
285 | } | ||
286 | |||
287 | static int mt312_send_master_cmd(struct dvb_frontend* fe, | ||
288 | struct dvb_diseqc_master_cmd *c) | ||
289 | { | ||
290 | struct mt312_state *state = (struct mt312_state*) fe->demodulator_priv; | ||
291 | int ret; | ||
292 | u8 diseqc_mode; | ||
293 | |||
294 | if ((c->msg_len == 0) || (c->msg_len > sizeof(c->msg))) | ||
295 | return -EINVAL; | ||
296 | |||
297 | if ((ret = mt312_readreg(state, DISEQC_MODE, &diseqc_mode)) < 0) | ||
298 | return ret; | ||
299 | |||
300 | if ((ret = | ||
301 | mt312_write(state, (0x80 | DISEQC_INSTR), c->msg, c->msg_len)) < 0) | ||
302 | return ret; | ||
303 | |||
304 | if ((ret = | ||
305 | mt312_writereg(state, DISEQC_MODE, | ||
306 | (diseqc_mode & 0x40) | ((c->msg_len - 1) << 3) | ||
307 | | 0x04)) < 0) | ||
308 | return ret; | ||
309 | |||
310 | /* set DISEQC_MODE[2:0] to zero if a return message is expected */ | ||
311 | if (c->msg[0] & 0x02) | ||
312 | if ((ret = | ||
313 | mt312_writereg(state, DISEQC_MODE, (diseqc_mode & 0x40))) < 0) | ||
314 | return ret; | ||
315 | |||
316 | return 0; | ||
317 | } | ||
318 | |||
319 | static int mt312_send_burst(struct dvb_frontend* fe, const fe_sec_mini_cmd_t c) | ||
320 | { | ||
321 | struct mt312_state *state = (struct mt312_state*) fe->demodulator_priv; | ||
322 | const u8 mini_tab[2] = { 0x02, 0x03 }; | ||
323 | |||
324 | int ret; | ||
325 | u8 diseqc_mode; | ||
326 | |||
327 | if (c > SEC_MINI_B) | ||
328 | return -EINVAL; | ||
329 | |||
330 | if ((ret = mt312_readreg(state, DISEQC_MODE, &diseqc_mode)) < 0) | ||
331 | return ret; | ||
332 | |||
333 | if ((ret = | ||
334 | mt312_writereg(state, DISEQC_MODE, | ||
335 | (diseqc_mode & 0x40) | mini_tab[c])) < 0) | ||
336 | return ret; | ||
337 | |||
338 | return 0; | ||
339 | } | ||
340 | |||
341 | static int mt312_set_tone(struct dvb_frontend* fe, const fe_sec_tone_mode_t t) | ||
342 | { | ||
343 | struct mt312_state *state = (struct mt312_state*) fe->demodulator_priv; | ||
344 | const u8 tone_tab[2] = { 0x01, 0x00 }; | ||
345 | |||
346 | int ret; | ||
347 | u8 diseqc_mode; | ||
348 | |||
349 | if (t > SEC_TONE_OFF) | ||
350 | return -EINVAL; | ||
351 | |||
352 | if ((ret = mt312_readreg(state, DISEQC_MODE, &diseqc_mode)) < 0) | ||
353 | return ret; | ||
354 | |||
355 | if ((ret = | ||
356 | mt312_writereg(state, DISEQC_MODE, | ||
357 | (diseqc_mode & 0x40) | tone_tab[t])) < 0) | ||
358 | return ret; | ||
359 | |||
360 | return 0; | ||
361 | } | ||
362 | |||
363 | static int mt312_set_voltage(struct dvb_frontend* fe, const fe_sec_voltage_t v) | ||
364 | { | ||
365 | struct mt312_state *state = (struct mt312_state*) fe->demodulator_priv; | ||
366 | const u8 volt_tab[3] = { 0x00, 0x40, 0x00 }; | ||
367 | |||
368 | if (v > SEC_VOLTAGE_OFF) | ||
369 | return -EINVAL; | ||
370 | |||
371 | return mt312_writereg(state, DISEQC_MODE, volt_tab[v]); | ||
372 | } | ||
373 | |||
374 | static int mt312_read_status(struct dvb_frontend* fe, fe_status_t *s) | ||
375 | { | ||
376 | struct mt312_state *state = (struct mt312_state*) fe->demodulator_priv; | ||
377 | int ret; | ||
378 | u8 status[3]; | ||
379 | |||
380 | *s = 0; | ||
381 | |||
382 | if ((ret = mt312_read(state, QPSK_STAT_H, status, sizeof(status))) < 0) | ||
383 | return ret; | ||
384 | |||
385 | dprintk(KERN_DEBUG "QPSK_STAT_H: 0x%02x, QPSK_STAT_L: 0x%02x, FEC_STATUS: 0x%02x\n", status[0], status[1], status[2]); | ||
386 | |||
387 | if (status[0] & 0xc0) | ||
388 | *s |= FE_HAS_SIGNAL; /* signal noise ratio */ | ||
389 | if (status[0] & 0x04) | ||
390 | *s |= FE_HAS_CARRIER; /* qpsk carrier lock */ | ||
391 | if (status[2] & 0x02) | ||
392 | *s |= FE_HAS_VITERBI; /* viterbi lock */ | ||
393 | if (status[2] & 0x04) | ||
394 | *s |= FE_HAS_SYNC; /* byte align lock */ | ||
395 | if (status[0] & 0x01) | ||
396 | *s |= FE_HAS_LOCK; /* qpsk lock */ | ||
397 | |||
398 | return 0; | ||
399 | } | ||
400 | |||
401 | static int mt312_read_ber(struct dvb_frontend* fe, u32 *ber) | ||
402 | { | ||
403 | struct mt312_state *state = (struct mt312_state*) fe->demodulator_priv; | ||
404 | int ret; | ||
405 | u8 buf[3]; | ||
406 | |||
407 | if ((ret = mt312_read(state, RS_BERCNT_H, buf, 3)) < 0) | ||
408 | return ret; | ||
409 | |||
410 | *ber = ((buf[0] << 16) | (buf[1] << 8) | buf[2]) * 64; | ||
411 | |||
412 | return 0; | ||
413 | } | ||
414 | |||
415 | static int mt312_read_signal_strength(struct dvb_frontend* fe, u16 *signal_strength) | ||
416 | { | ||
417 | struct mt312_state *state = (struct mt312_state*) fe->demodulator_priv; | ||
418 | int ret; | ||
419 | u8 buf[3]; | ||
420 | u16 agc; | ||
421 | s16 err_db; | ||
422 | |||
423 | if ((ret = mt312_read(state, AGC_H, buf, sizeof(buf))) < 0) | ||
424 | return ret; | ||
425 | |||
426 | agc = (buf[0] << 6) | (buf[1] >> 2); | ||
427 | err_db = (s16) (((buf[1] & 0x03) << 14) | buf[2] << 6) >> 6; | ||
428 | |||
429 | *signal_strength = agc; | ||
430 | |||
431 | dprintk(KERN_DEBUG "agc=%08x err_db=%hd\n", agc, err_db); | ||
432 | |||
433 | return 0; | ||
434 | } | ||
435 | |||
436 | static int mt312_read_snr(struct dvb_frontend* fe, u16 *snr) | ||
437 | { | ||
438 | struct mt312_state *state = (struct mt312_state*) fe->demodulator_priv; | ||
439 | int ret; | ||
440 | u8 buf[2]; | ||
441 | |||
442 | if ((ret = mt312_read(state, M_SNR_H, &buf, sizeof(buf))) < 0) | ||
443 | return ret; | ||
444 | |||
445 | *snr = 0xFFFF - ((((buf[0] & 0x7f) << 8) | buf[1]) << 1); | ||
446 | |||
447 | return 0; | ||
448 | } | ||
449 | |||
450 | static int mt312_read_ucblocks(struct dvb_frontend* fe, u32 *ubc) | ||
451 | { | ||
452 | struct mt312_state *state = (struct mt312_state*) fe->demodulator_priv; | ||
453 | int ret; | ||
454 | u8 buf[2]; | ||
455 | |||
456 | if ((ret = mt312_read(state, RS_UBC_H, &buf, sizeof(buf))) < 0) | ||
457 | return ret; | ||
458 | |||
459 | *ubc = (buf[0] << 8) | buf[1]; | ||
460 | |||
461 | return 0; | ||
462 | } | ||
463 | |||
464 | static int mt312_set_frontend(struct dvb_frontend* fe, | ||
465 | struct dvb_frontend_parameters *p) | ||
466 | { | ||
467 | struct mt312_state *state = (struct mt312_state*) fe->demodulator_priv; | ||
468 | int ret; | ||
469 | u8 buf[5], config_val; | ||
470 | u16 sr; | ||
471 | |||
472 | const u8 fec_tab[10] = | ||
473 | { 0x00, 0x01, 0x02, 0x04, 0x3f, 0x08, 0x10, 0x20, 0x3f, 0x3f }; | ||
474 | const u8 inv_tab[3] = { 0x00, 0x40, 0x80 }; | ||
475 | |||
476 | dprintk("%s: Freq %d\n", __FUNCTION__, p->frequency); | ||
477 | |||
478 | if ((p->frequency < fe->ops->info.frequency_min) | ||
479 | || (p->frequency > fe->ops->info.frequency_max)) | ||
480 | return -EINVAL; | ||
481 | |||
482 | if ((p->inversion < INVERSION_OFF) | ||
483 | || (p->inversion > INVERSION_ON)) | ||
484 | return -EINVAL; | ||
485 | |||
486 | if ((p->u.qpsk.symbol_rate < fe->ops->info.symbol_rate_min) | ||
487 | || (p->u.qpsk.symbol_rate > fe->ops->info.symbol_rate_max)) | ||
488 | return -EINVAL; | ||
489 | |||
490 | if ((p->u.qpsk.fec_inner < FEC_NONE) | ||
491 | || (p->u.qpsk.fec_inner > FEC_AUTO)) | ||
492 | return -EINVAL; | ||
493 | |||
494 | if ((p->u.qpsk.fec_inner == FEC_4_5) | ||
495 | || (p->u.qpsk.fec_inner == FEC_8_9)) | ||
496 | return -EINVAL; | ||
497 | |||
498 | switch (state->id) { | ||
499 | case ID_VP310: | ||
500 | // For now we will do this only for the VP310. | ||
501 | // It should be better for the mt312 as well, but tunning will be slower. ACCJr 09/29/03 | ||
502 | if ((ret = mt312_readreg(state, CONFIG, &config_val) < 0)) | ||
503 | return ret; | ||
504 | if (p->u.qpsk.symbol_rate >= 30000000) //Note that 30MS/s should use 90MHz | ||
505 | { | ||
506 | if ((config_val & 0x0c) == 0x08) { //We are running 60MHz | ||
507 | state->frequency = 90; | ||
508 | if ((ret = mt312_initfe(fe)) < 0) | ||
509 | return ret; | ||
510 | } | ||
511 | } | ||
512 | else | ||
513 | { | ||
514 | if ((config_val & 0x0c) == 0x0C) { //We are running 90MHz | ||
515 | state->frequency = 60; | ||
516 | if ((ret = mt312_initfe(fe)) < 0) | ||
517 | return ret; | ||
518 | } | ||
519 | } | ||
520 | break; | ||
521 | |||
522 | case ID_MT312: | ||
523 | break; | ||
524 | |||
525 | default: | ||
526 | return -EINVAL; | ||
527 | } | ||
528 | |||
529 | mt312_writereg(state, GPP_CTRL, 0x40); | ||
530 | state->config->pll_set(fe, p); | ||
531 | mt312_writereg(state, GPP_CTRL, 0x00); | ||
532 | |||
533 | /* sr = (u16)(sr * 256.0 / 1000000.0) */ | ||
534 | sr = mt312_div(p->u.qpsk.symbol_rate * 4, 15625); | ||
535 | |||
536 | /* SYM_RATE */ | ||
537 | buf[0] = (sr >> 8) & 0x3f; | ||
538 | buf[1] = (sr >> 0) & 0xff; | ||
539 | |||
540 | /* VIT_MODE */ | ||
541 | buf[2] = inv_tab[p->inversion] | fec_tab[p->u.qpsk.fec_inner]; | ||
542 | |||
543 | /* QPSK_CTRL */ | ||
544 | buf[3] = 0x40; /* swap I and Q before QPSK demodulation */ | ||
545 | |||
546 | if (p->u.qpsk.symbol_rate < 10000000) | ||
547 | buf[3] |= 0x04; /* use afc mode */ | ||
548 | |||
549 | /* GO */ | ||
550 | buf[4] = 0x01; | ||
551 | |||
552 | if ((ret = mt312_write(state, SYM_RATE_H, buf, sizeof(buf))) < 0) | ||
553 | return ret; | ||
554 | |||
555 | mt312_reset(state, 0); | ||
556 | |||
557 | return 0; | ||
558 | } | ||
559 | |||
560 | static int mt312_get_frontend(struct dvb_frontend* fe, | ||
561 | struct dvb_frontend_parameters *p) | ||
562 | { | ||
563 | struct mt312_state *state = (struct mt312_state*) fe->demodulator_priv; | ||
564 | int ret; | ||
565 | |||
566 | if ((ret = mt312_get_inversion(state, &p->inversion)) < 0) | ||
567 | return ret; | ||
568 | |||
569 | if ((ret = mt312_get_symbol_rate(state, &p->u.qpsk.symbol_rate)) < 0) | ||
570 | return ret; | ||
571 | |||
572 | if ((ret = mt312_get_code_rate(state, &p->u.qpsk.fec_inner)) < 0) | ||
573 | return ret; | ||
574 | |||
575 | return 0; | ||
576 | } | ||
577 | |||
578 | static int mt312_sleep(struct dvb_frontend* fe) | ||
579 | { | ||
580 | struct mt312_state *state = (struct mt312_state*) fe->demodulator_priv; | ||
581 | int ret; | ||
582 | u8 config; | ||
583 | |||
584 | /* reset all registers to defaults */ | ||
585 | if ((ret = mt312_reset(state, 1)) < 0) | ||
586 | return ret; | ||
587 | |||
588 | if ((ret = mt312_readreg(state, CONFIG, &config)) < 0) | ||
589 | return ret; | ||
590 | |||
591 | /* enter standby */ | ||
592 | if ((ret = mt312_writereg(state, CONFIG, config & 0x7f)) < 0) | ||
593 | return ret; | ||
594 | |||
595 | return 0; | ||
596 | } | ||
597 | |||
598 | static int mt312_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings* fesettings) | ||
599 | { | ||
600 | fesettings->min_delay_ms = 50; | ||
601 | fesettings->step_size = 0; | ||
602 | fesettings->max_drift = 0; | ||
603 | return 0; | ||
604 | } | ||
605 | |||
606 | static void mt312_release(struct dvb_frontend* fe) | ||
607 | { | ||
608 | struct mt312_state* state = (struct mt312_state*) fe->demodulator_priv; | ||
609 | kfree(state); | ||
610 | } | ||
611 | |||
612 | static struct dvb_frontend_ops vp310_mt312_ops; | ||
613 | |||
614 | struct dvb_frontend* vp310_attach(const struct mt312_config* config, | ||
615 | struct i2c_adapter* i2c) | ||
616 | { | ||
617 | struct mt312_state* state = NULL; | ||
618 | |||
619 | /* allocate memory for the internal state */ | ||
620 | state = (struct mt312_state*) kmalloc(sizeof(struct mt312_state), GFP_KERNEL); | ||
621 | if (state == NULL) | ||
622 | goto error; | ||
623 | |||
624 | /* setup the state */ | ||
625 | state->config = config; | ||
626 | state->i2c = i2c; | ||
627 | memcpy(&state->ops, &vp310_mt312_ops, sizeof(struct dvb_frontend_ops)); | ||
628 | strcpy(state->ops.info.name, "Zarlink VP310 DVB-S"); | ||
629 | |||
630 | /* check if the demod is there */ | ||
631 | if (mt312_readreg(state, ID, &state->id) < 0) | ||
632 | goto error; | ||
633 | if (state->id != ID_VP310) { | ||
634 | goto error; | ||
635 | } | ||
636 | |||
637 | /* create dvb_frontend */ | ||
638 | state->frequency = 90; | ||
639 | state->frontend.ops = &state->ops; | ||
640 | state->frontend.demodulator_priv = state; | ||
641 | return &state->frontend; | ||
642 | |||
643 | error: | ||
644 | kfree(state); | ||
645 | return NULL; | ||
646 | } | ||
647 | |||
648 | struct dvb_frontend* mt312_attach(const struct mt312_config* config, | ||
649 | struct i2c_adapter* i2c) | ||
650 | { | ||
651 | struct mt312_state* state = NULL; | ||
652 | |||
653 | /* allocate memory for the internal state */ | ||
654 | state = (struct mt312_state*) kmalloc(sizeof(struct mt312_state), GFP_KERNEL); | ||
655 | if (state == NULL) | ||
656 | goto error; | ||
657 | |||
658 | /* setup the state */ | ||
659 | state->config = config; | ||
660 | state->i2c = i2c; | ||
661 | memcpy(&state->ops, &vp310_mt312_ops, sizeof(struct dvb_frontend_ops)); | ||
662 | strcpy(state->ops.info.name, "Zarlink MT312 DVB-S"); | ||
663 | |||
664 | /* check if the demod is there */ | ||
665 | if (mt312_readreg(state, ID, &state->id) < 0) | ||
666 | goto error; | ||
667 | if (state->id != ID_MT312) { | ||
668 | goto error; | ||
669 | } | ||
670 | |||
671 | /* create dvb_frontend */ | ||
672 | state->frequency = 60; | ||
673 | state->frontend.ops = &state->ops; | ||
674 | state->frontend.demodulator_priv = state; | ||
675 | return &state->frontend; | ||
676 | |||
677 | error: | ||
678 | if (state) | ||
679 | kfree(state); | ||
680 | return NULL; | ||
681 | } | ||
682 | |||
683 | static struct dvb_frontend_ops vp310_mt312_ops = { | ||
684 | |||
685 | .info = { | ||
686 | .name = "Zarlink ???? DVB-S", | ||
687 | .type = FE_QPSK, | ||
688 | .frequency_min = 950000, | ||
689 | .frequency_max = 2150000, | ||
690 | .frequency_stepsize = (MT312_PLL_CLK / 1000) / 128, | ||
691 | .symbol_rate_min = MT312_SYS_CLK / 128, | ||
692 | .symbol_rate_max = MT312_SYS_CLK / 2, | ||
693 | .caps = | ||
694 | FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | | ||
695 | FE_CAN_FEC_3_4 | FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | | ||
696 | FE_CAN_FEC_AUTO | FE_CAN_QPSK | FE_CAN_MUTE_TS | | ||
697 | FE_CAN_RECOVER | ||
698 | }, | ||
699 | |||
700 | .release = mt312_release, | ||
701 | |||
702 | .init = mt312_initfe, | ||
703 | .sleep = mt312_sleep, | ||
704 | |||
705 | .set_frontend = mt312_set_frontend, | ||
706 | .get_frontend = mt312_get_frontend, | ||
707 | .get_tune_settings = mt312_get_tune_settings, | ||
708 | |||
709 | .read_status = mt312_read_status, | ||
710 | .read_ber = mt312_read_ber, | ||
711 | .read_signal_strength = mt312_read_signal_strength, | ||
712 | .read_snr = mt312_read_snr, | ||
713 | .read_ucblocks = mt312_read_ucblocks, | ||
714 | |||
715 | .diseqc_send_master_cmd = mt312_send_master_cmd, | ||
716 | .diseqc_send_burst = mt312_send_burst, | ||
717 | .set_tone = mt312_set_tone, | ||
718 | .set_voltage = mt312_set_voltage, | ||
719 | }; | ||
720 | |||
721 | module_param(debug, int, 0644); | ||
722 | MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off)."); | ||
723 | |||
724 | MODULE_DESCRIPTION("Zarlink VP310/MT312 DVB-S Demodulator driver"); | ||
725 | MODULE_AUTHOR("Andreas Oberritter <obi@linuxtv.org>"); | ||
726 | MODULE_LICENSE("GPL"); | ||
727 | |||
728 | EXPORT_SYMBOL(mt312_attach); | ||
729 | EXPORT_SYMBOL(vp310_attach); | ||
diff --git a/drivers/media/dvb/frontends/mt312.h b/drivers/media/dvb/frontends/mt312.h new file mode 100644 index 000000000000..b3a53a73a117 --- /dev/null +++ b/drivers/media/dvb/frontends/mt312.h | |||
@@ -0,0 +1,47 @@ | |||
1 | /* | ||
2 | Driver for Zarlink MT312 Satellite Channel Decoder | ||
3 | |||
4 | Copyright (C) 2003 Andreas Oberritter <obi@linuxtv.org> | ||
5 | |||
6 | This program is free software; you can redistribute it and/or modify | ||
7 | it under the terms of the GNU General Public License as published by | ||
8 | the Free Software Foundation; either version 2 of the License, or | ||
9 | (at your option) any later version. | ||
10 | |||
11 | This program is distributed in the hope that it will be useful, | ||
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | |||
15 | GNU General Public License for more details. | ||
16 | |||
17 | You should have received a copy of the GNU General Public License | ||
18 | along with this program; if not, write to the Free Software | ||
19 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
20 | |||
21 | References: | ||
22 | http://products.zarlink.com/product_profiles/MT312.htm | ||
23 | http://products.zarlink.com/product_profiles/SL1935.htm | ||
24 | */ | ||
25 | |||
26 | #ifndef MT312_H | ||
27 | #define MT312_H | ||
28 | |||
29 | #include <linux/dvb/frontend.h> | ||
30 | |||
31 | struct mt312_config | ||
32 | { | ||
33 | /* the demodulator's i2c address */ | ||
34 | u8 demod_address; | ||
35 | |||
36 | /* PLL maintenance */ | ||
37 | int (*pll_init)(struct dvb_frontend* fe); | ||
38 | int (*pll_set)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params); | ||
39 | }; | ||
40 | |||
41 | extern struct dvb_frontend* mt312_attach(const struct mt312_config* config, | ||
42 | struct i2c_adapter* i2c); | ||
43 | |||
44 | extern struct dvb_frontend* vp310_attach(const struct mt312_config* config, | ||
45 | struct i2c_adapter* i2c); | ||
46 | |||
47 | #endif // MT312_H | ||
diff --git a/drivers/media/dvb/frontends/mt312_priv.h b/drivers/media/dvb/frontends/mt312_priv.h new file mode 100644 index 000000000000..5e0b95b5337b --- /dev/null +++ b/drivers/media/dvb/frontends/mt312_priv.h | |||
@@ -0,0 +1,162 @@ | |||
1 | /* | ||
2 | Driver for Zarlink MT312 QPSK Frontend | ||
3 | |||
4 | Copyright (C) 2003 Andreas Oberritter <obi@linuxtv.org> | ||
5 | |||
6 | This program is free software; you can redistribute it and/or modify | ||
7 | it under the terms of the GNU General Public License as published by | ||
8 | the Free Software Foundation; either version 2 of the License, or | ||
9 | (at your option) any later version. | ||
10 | |||
11 | This program is distributed in the hope that it will be useful, | ||
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | |||
15 | GNU General Public License for more details. | ||
16 | |||
17 | You should have received a copy of the GNU General Public License | ||
18 | along with this program; if not, write to the Free Software | ||
19 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
20 | |||
21 | */ | ||
22 | |||
23 | #ifndef _DVB_FRONTENDS_MT312_PRIV | ||
24 | #define _DVB_FRONTENDS_MT312_PRIV | ||
25 | |||
26 | enum mt312_reg_addr { | ||
27 | QPSK_INT_H = 0, | ||
28 | QPSK_INT_M = 1, | ||
29 | QPSK_INT_L = 2, | ||
30 | FEC_INT = 3, | ||
31 | QPSK_STAT_H = 4, | ||
32 | QPSK_STAT_L = 5, | ||
33 | FEC_STATUS = 6, | ||
34 | LNB_FREQ_H = 7, | ||
35 | LNB_FREQ_L = 8, | ||
36 | M_SNR_H = 9, | ||
37 | M_SNR_L = 10, | ||
38 | VIT_ERRCNT_H = 11, | ||
39 | VIT_ERRCNT_M = 12, | ||
40 | VIT_ERRCNT_L = 13, | ||
41 | RS_BERCNT_H = 14, | ||
42 | RS_BERCNT_M = 15, | ||
43 | RS_BERCNT_L = 16, | ||
44 | RS_UBC_H = 17, | ||
45 | RS_UBC_L = 18, | ||
46 | SIG_LEVEL = 19, | ||
47 | GPP_CTRL = 20, | ||
48 | RESET = 21, | ||
49 | DISEQC_MODE = 22, | ||
50 | SYM_RATE_H = 23, | ||
51 | SYM_RATE_L = 24, | ||
52 | VIT_MODE = 25, | ||
53 | QPSK_CTRL = 26, | ||
54 | GO = 27, | ||
55 | IE_QPSK_H = 28, | ||
56 | IE_QPSK_M = 29, | ||
57 | IE_QPSK_L = 30, | ||
58 | IE_FEC = 31, | ||
59 | QPSK_STAT_EN = 32, | ||
60 | FEC_STAT_EN = 33, | ||
61 | SYS_CLK = 34, | ||
62 | DISEQC_RATIO = 35, | ||
63 | DISEQC_INSTR = 36, | ||
64 | FR_LIM = 37, | ||
65 | FR_OFF = 38, | ||
66 | AGC_CTRL = 39, | ||
67 | AGC_INIT = 40, | ||
68 | AGC_REF = 41, | ||
69 | AGC_MAX = 42, | ||
70 | AGC_MIN = 43, | ||
71 | AGC_LK_TH = 44, | ||
72 | TS_AGC_LK_TH = 45, | ||
73 | AGC_PWR_SET = 46, | ||
74 | QPSK_MISC = 47, | ||
75 | SNR_THS_LOW = 48, | ||
76 | SNR_THS_HIGH = 49, | ||
77 | TS_SW_RATE = 50, | ||
78 | TS_SW_LIM_L = 51, | ||
79 | TS_SW_LIM_H = 52, | ||
80 | CS_SW_RATE_1 = 53, | ||
81 | CS_SW_RATE_2 = 54, | ||
82 | CS_SW_RATE_3 = 55, | ||
83 | CS_SW_RATE_4 = 56, | ||
84 | CS_SW_LIM = 57, | ||
85 | TS_LPK = 58, | ||
86 | TS_LPK_M = 59, | ||
87 | TS_LPK_L = 60, | ||
88 | CS_KPROP_H = 61, | ||
89 | CS_KPROP_L = 62, | ||
90 | CS_KINT_H = 63, | ||
91 | CS_KINT_L = 64, | ||
92 | QPSK_SCALE = 65, | ||
93 | TLD_OUTCLK_TH = 66, | ||
94 | TLD_INCLK_TH = 67, | ||
95 | FLD_TH = 68, | ||
96 | PLD_OUTLK3 = 69, | ||
97 | PLD_OUTLK2 = 70, | ||
98 | PLD_OUTLK1 = 71, | ||
99 | PLD_OUTLK0 = 72, | ||
100 | PLD_INLK3 = 73, | ||
101 | PLD_INLK2 = 74, | ||
102 | PLD_INLK1 = 75, | ||
103 | PLD_INLK0 = 76, | ||
104 | PLD_ACC_TIME = 77, | ||
105 | SWEEP_PAR = 78, | ||
106 | STARTUP_TIME = 79, | ||
107 | LOSSLOCK_TH = 80, | ||
108 | FEC_LOCK_TM = 81, | ||
109 | LOSSLOCK_TM = 82, | ||
110 | VIT_ERRPER_H = 83, | ||
111 | VIT_ERRPER_M = 84, | ||
112 | VIT_ERRPER_L = 85, | ||
113 | VIT_SETUP = 86, | ||
114 | VIT_REF0 = 87, | ||
115 | VIT_REF1 = 88, | ||
116 | VIT_REF2 = 89, | ||
117 | VIT_REF3 = 90, | ||
118 | VIT_REF4 = 91, | ||
119 | VIT_REF5 = 92, | ||
120 | VIT_REF6 = 93, | ||
121 | VIT_MAXERR = 94, | ||
122 | BA_SETUPT = 95, | ||
123 | OP_CTRL = 96, | ||
124 | FEC_SETUP = 97, | ||
125 | PROG_SYNC = 98, | ||
126 | AFC_SEAR_TH = 99, | ||
127 | CSACC_DIF_TH = 100, | ||
128 | QPSK_LK_CT = 101, | ||
129 | QPSK_ST_CT = 102, | ||
130 | MON_CTRL = 103, | ||
131 | QPSK_RESET = 104, | ||
132 | QPSK_TST_CT = 105, | ||
133 | QPSK_TST_ST = 106, | ||
134 | TEST_R = 107, | ||
135 | AGC_H = 108, | ||
136 | AGC_M = 109, | ||
137 | AGC_L = 110, | ||
138 | FREQ_ERR1_H = 111, | ||
139 | FREQ_ERR1_M = 112, | ||
140 | FREQ_ERR1_L = 113, | ||
141 | FREQ_ERR2_H = 114, | ||
142 | FREQ_ERR2_L = 115, | ||
143 | SYM_RAT_OP_H = 116, | ||
144 | SYM_RAT_OP_L = 117, | ||
145 | DESEQC2_INT = 118, | ||
146 | DISEQC2_STAT = 119, | ||
147 | DISEQC2_FIFO = 120, | ||
148 | DISEQC2_CTRL1 = 121, | ||
149 | DISEQC2_CTRL2 = 122, | ||
150 | MONITOR_H = 123, | ||
151 | MONITOR_L = 124, | ||
152 | TEST_MODE = 125, | ||
153 | ID = 126, | ||
154 | CONFIG = 127 | ||
155 | }; | ||
156 | |||
157 | enum mt312_model_id { | ||
158 | ID_VP310 = 1, | ||
159 | ID_MT312 = 3 | ||
160 | }; | ||
161 | |||
162 | #endif /* DVB_FRONTENDS_MT312_PRIV */ | ||
diff --git a/drivers/media/dvb/frontends/mt352.c b/drivers/media/dvb/frontends/mt352.c new file mode 100644 index 000000000000..50326c7248fa --- /dev/null +++ b/drivers/media/dvb/frontends/mt352.c | |||
@@ -0,0 +1,610 @@ | |||
1 | /* | ||
2 | * Driver for Zarlink DVB-T MT352 demodulator | ||
3 | * | ||
4 | * Written by Holger Waechtler <holger@qanu.de> | ||
5 | * and Daniel Mack <daniel@qanu.de> | ||
6 | * | ||
7 | * AVerMedia AVerTV DVB-T 771 support by | ||
8 | * Wolfram Joost <dbox2@frokaschwei.de> | ||
9 | * | ||
10 | * Support for Samsung TDTC9251DH01C(M) tuner | ||
11 | * Copyright (C) 2004 Antonio Mancuso <antonio.mancuso@digitaltelevision.it> | ||
12 | * Amauri Celani <acelani@essegi.net> | ||
13 | * | ||
14 | * DVICO FusionHDTV DVB-T1 and DVICO FusionHDTV DVB-T Lite support by | ||
15 | * Christopher Pascoe <c.pascoe@itee.uq.edu.au> | ||
16 | * | ||
17 | * This program is free software; you can redistribute it and/or modify | ||
18 | * it under the terms of the GNU General Public License as published by | ||
19 | * the Free Software Foundation; either version 2 of the License, or | ||
20 | * (at your option) any later version. | ||
21 | * | ||
22 | * This program is distributed in the hope that it will be useful, | ||
23 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
24 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
25 | * | ||
26 | * GNU General Public License for more details. | ||
27 | * | ||
28 | * You should have received a copy of the GNU General Public License | ||
29 | * along with this program; if not, write to the Free Software | ||
30 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.= | ||
31 | */ | ||
32 | |||
33 | #include <linux/kernel.h> | ||
34 | #include <linux/module.h> | ||
35 | #include <linux/moduleparam.h> | ||
36 | #include <linux/init.h> | ||
37 | #include <linux/delay.h> | ||
38 | |||
39 | #include "dvb_frontend.h" | ||
40 | #include "mt352_priv.h" | ||
41 | #include "mt352.h" | ||
42 | |||
43 | struct mt352_state { | ||
44 | struct i2c_adapter* i2c; | ||
45 | struct dvb_frontend frontend; | ||
46 | struct dvb_frontend_ops ops; | ||
47 | |||
48 | /* configuration settings */ | ||
49 | const struct mt352_config* config; | ||
50 | }; | ||
51 | |||
52 | static int debug; | ||
53 | #define dprintk(args...) \ | ||
54 | do { \ | ||
55 | if (debug) printk(KERN_DEBUG "mt352: " args); \ | ||
56 | } while (0) | ||
57 | |||
58 | static int mt352_single_write(struct dvb_frontend *fe, u8 reg, u8 val) | ||
59 | { | ||
60 | struct mt352_state* state = fe->demodulator_priv; | ||
61 | u8 buf[2] = { reg, val }; | ||
62 | struct i2c_msg msg = { .addr = state->config->demod_address, .flags = 0, | ||
63 | .buf = buf, .len = 2 }; | ||
64 | int err = i2c_transfer(state->i2c, &msg, 1); | ||
65 | if (err != 1) { | ||
66 | printk("mt352_write() to reg %x failed (err = %d)!\n", reg, err); | ||
67 | return err; | ||
68 | } | ||
69 | return 0; | ||
70 | } | ||
71 | |||
72 | int mt352_write(struct dvb_frontend* fe, u8* ibuf, int ilen) | ||
73 | { | ||
74 | int err,i; | ||
75 | for (i=0; i < ilen-1; i++) | ||
76 | if ((err = mt352_single_write(fe,ibuf[0]+i,ibuf[i+1]))) | ||
77 | return err; | ||
78 | |||
79 | return 0; | ||
80 | } | ||
81 | |||
82 | static int mt352_read_register(struct mt352_state* state, u8 reg) | ||
83 | { | ||
84 | int ret; | ||
85 | u8 b0 [] = { reg }; | ||
86 | u8 b1 [] = { 0 }; | ||
87 | struct i2c_msg msg [] = { { .addr = state->config->demod_address, | ||
88 | .flags = 0, | ||
89 | .buf = b0, .len = 1 }, | ||
90 | { .addr = state->config->demod_address, | ||
91 | .flags = I2C_M_RD, | ||
92 | .buf = b1, .len = 1 } }; | ||
93 | |||
94 | ret = i2c_transfer(state->i2c, msg, 2); | ||
95 | |||
96 | if (ret != 2) { | ||
97 | printk("%s: readreg error (reg=%d, ret==%i)\n", | ||
98 | __FUNCTION__, reg, ret); | ||
99 | return ret; | ||
100 | } | ||
101 | |||
102 | return b1[0]; | ||
103 | } | ||
104 | |||
105 | int mt352_read(struct dvb_frontend *fe, u8 reg) | ||
106 | { | ||
107 | return mt352_read_register(fe->demodulator_priv,reg); | ||
108 | } | ||
109 | |||
110 | static int mt352_sleep(struct dvb_frontend* fe) | ||
111 | { | ||
112 | static u8 mt352_softdown[] = { CLOCK_CTL, 0x20, 0x08 }; | ||
113 | |||
114 | mt352_write(fe, mt352_softdown, sizeof(mt352_softdown)); | ||
115 | return 0; | ||
116 | } | ||
117 | |||
118 | static void mt352_calc_nominal_rate(struct mt352_state* state, | ||
119 | enum fe_bandwidth bandwidth, | ||
120 | unsigned char *buf) | ||
121 | { | ||
122 | u32 adc_clock = 20480; /* 20.340 MHz */ | ||
123 | u32 bw,value; | ||
124 | |||
125 | switch (bandwidth) { | ||
126 | case BANDWIDTH_6_MHZ: | ||
127 | bw = 6; | ||
128 | break; | ||
129 | case BANDWIDTH_7_MHZ: | ||
130 | bw = 7; | ||
131 | break; | ||
132 | case BANDWIDTH_8_MHZ: | ||
133 | default: | ||
134 | bw = 8; | ||
135 | break; | ||
136 | } | ||
137 | if (state->config->adc_clock) | ||
138 | adc_clock = state->config->adc_clock; | ||
139 | |||
140 | value = 64 * bw * (1<<16) / (7 * 8); | ||
141 | value = value * 1000 / adc_clock; | ||
142 | dprintk("%s: bw %d, adc_clock %d => 0x%x\n", | ||
143 | __FUNCTION__, bw, adc_clock, value); | ||
144 | buf[0] = msb(value); | ||
145 | buf[1] = lsb(value); | ||
146 | } | ||
147 | |||
148 | static void mt352_calc_input_freq(struct mt352_state* state, | ||
149 | unsigned char *buf) | ||
150 | { | ||
151 | int adc_clock = 20480; /* 20.480000 MHz */ | ||
152 | int if2 = 36167; /* 36.166667 MHz */ | ||
153 | int ife,value; | ||
154 | |||
155 | if (state->config->adc_clock) | ||
156 | adc_clock = state->config->adc_clock; | ||
157 | if (state->config->if2) | ||
158 | if2 = state->config->if2; | ||
159 | |||
160 | ife = (2*adc_clock - if2); | ||
161 | value = -16374 * ife / adc_clock; | ||
162 | dprintk("%s: if2 %d, ife %d, adc_clock %d => %d / 0x%x\n", | ||
163 | __FUNCTION__, if2, ife, adc_clock, value, value & 0x3fff); | ||
164 | buf[0] = msb(value); | ||
165 | buf[1] = lsb(value); | ||
166 | } | ||
167 | |||
168 | static int mt352_set_parameters(struct dvb_frontend* fe, | ||
169 | struct dvb_frontend_parameters *param) | ||
170 | { | ||
171 | struct mt352_state* state = fe->demodulator_priv; | ||
172 | unsigned char buf[13]; | ||
173 | static unsigned char tuner_go[] = { 0x5d, 0x01 }; | ||
174 | static unsigned char fsm_go[] = { 0x5e, 0x01 }; | ||
175 | unsigned int tps = 0; | ||
176 | struct dvb_ofdm_parameters *op = ¶m->u.ofdm; | ||
177 | |||
178 | switch (op->code_rate_HP) { | ||
179 | case FEC_2_3: | ||
180 | tps |= (1 << 7); | ||
181 | break; | ||
182 | case FEC_3_4: | ||
183 | tps |= (2 << 7); | ||
184 | break; | ||
185 | case FEC_5_6: | ||
186 | tps |= (3 << 7); | ||
187 | break; | ||
188 | case FEC_7_8: | ||
189 | tps |= (4 << 7); | ||
190 | break; | ||
191 | case FEC_1_2: | ||
192 | case FEC_AUTO: | ||
193 | break; | ||
194 | default: | ||
195 | return -EINVAL; | ||
196 | } | ||
197 | |||
198 | switch (op->code_rate_LP) { | ||
199 | case FEC_2_3: | ||
200 | tps |= (1 << 4); | ||
201 | break; | ||
202 | case FEC_3_4: | ||
203 | tps |= (2 << 4); | ||
204 | break; | ||
205 | case FEC_5_6: | ||
206 | tps |= (3 << 4); | ||
207 | break; | ||
208 | case FEC_7_8: | ||
209 | tps |= (4 << 4); | ||
210 | break; | ||
211 | case FEC_1_2: | ||
212 | case FEC_AUTO: | ||
213 | break; | ||
214 | case FEC_NONE: | ||
215 | if (op->hierarchy_information == HIERARCHY_AUTO || | ||
216 | op->hierarchy_information == HIERARCHY_NONE) | ||
217 | break; | ||
218 | default: | ||
219 | return -EINVAL; | ||
220 | } | ||
221 | |||
222 | switch (op->constellation) { | ||
223 | case QPSK: | ||
224 | break; | ||
225 | case QAM_AUTO: | ||
226 | case QAM_16: | ||
227 | tps |= (1 << 13); | ||
228 | break; | ||
229 | case QAM_64: | ||
230 | tps |= (2 << 13); | ||
231 | break; | ||
232 | default: | ||
233 | return -EINVAL; | ||
234 | } | ||
235 | |||
236 | switch (op->transmission_mode) { | ||
237 | case TRANSMISSION_MODE_2K: | ||
238 | case TRANSMISSION_MODE_AUTO: | ||
239 | break; | ||
240 | case TRANSMISSION_MODE_8K: | ||
241 | tps |= (1 << 0); | ||
242 | break; | ||
243 | default: | ||
244 | return -EINVAL; | ||
245 | } | ||
246 | |||
247 | switch (op->guard_interval) { | ||
248 | case GUARD_INTERVAL_1_32: | ||
249 | case GUARD_INTERVAL_AUTO: | ||
250 | break; | ||
251 | case GUARD_INTERVAL_1_16: | ||
252 | tps |= (1 << 2); | ||
253 | break; | ||
254 | case GUARD_INTERVAL_1_8: | ||
255 | tps |= (2 << 2); | ||
256 | break; | ||
257 | case GUARD_INTERVAL_1_4: | ||
258 | tps |= (3 << 2); | ||
259 | break; | ||
260 | default: | ||
261 | return -EINVAL; | ||
262 | } | ||
263 | |||
264 | switch (op->hierarchy_information) { | ||
265 | case HIERARCHY_AUTO: | ||
266 | case HIERARCHY_NONE: | ||
267 | break; | ||
268 | case HIERARCHY_1: | ||
269 | tps |= (1 << 10); | ||
270 | break; | ||
271 | case HIERARCHY_2: | ||
272 | tps |= (2 << 10); | ||
273 | break; | ||
274 | case HIERARCHY_4: | ||
275 | tps |= (3 << 10); | ||
276 | break; | ||
277 | default: | ||
278 | return -EINVAL; | ||
279 | } | ||
280 | |||
281 | |||
282 | buf[0] = TPS_GIVEN_1; /* TPS_GIVEN_1 and following registers */ | ||
283 | |||
284 | buf[1] = msb(tps); /* TPS_GIVEN_(1|0) */ | ||
285 | buf[2] = lsb(tps); | ||
286 | |||
287 | buf[3] = 0x50; // old | ||
288 | // buf[3] = 0xf4; // pinnacle | ||
289 | |||
290 | mt352_calc_nominal_rate(state, op->bandwidth, buf+4); | ||
291 | mt352_calc_input_freq(state, buf+6); | ||
292 | state->config->pll_set(fe, param, buf+8); | ||
293 | |||
294 | mt352_write(fe, buf, sizeof(buf)); | ||
295 | if (state->config->no_tuner) { | ||
296 | /* start decoding */ | ||
297 | mt352_write(fe, fsm_go, 2); | ||
298 | } else { | ||
299 | /* start tuning */ | ||
300 | mt352_write(fe, tuner_go, 2); | ||
301 | } | ||
302 | return 0; | ||
303 | } | ||
304 | |||
305 | static int mt352_get_parameters(struct dvb_frontend* fe, | ||
306 | struct dvb_frontend_parameters *param) | ||
307 | { | ||
308 | struct mt352_state* state = fe->demodulator_priv; | ||
309 | u16 tps; | ||
310 | u16 div; | ||
311 | u8 trl; | ||
312 | struct dvb_ofdm_parameters *op = ¶m->u.ofdm; | ||
313 | static const u8 tps_fec_to_api[8] = | ||
314 | { | ||
315 | FEC_1_2, | ||
316 | FEC_2_3, | ||
317 | FEC_3_4, | ||
318 | FEC_5_6, | ||
319 | FEC_7_8, | ||
320 | FEC_AUTO, | ||
321 | FEC_AUTO, | ||
322 | FEC_AUTO | ||
323 | }; | ||
324 | |||
325 | if ( (mt352_read_register(state,0x00) & 0xC0) != 0xC0 ) | ||
326 | return -EINVAL; | ||
327 | |||
328 | /* Use TPS_RECEIVED-registers, not the TPS_CURRENT-registers because | ||
329 | * the mt352 sometimes works with the wrong parameters | ||
330 | */ | ||
331 | tps = (mt352_read_register(state, TPS_RECEIVED_1) << 8) | mt352_read_register(state, TPS_RECEIVED_0); | ||
332 | div = (mt352_read_register(state, CHAN_START_1) << 8) | mt352_read_register(state, CHAN_START_0); | ||
333 | trl = mt352_read_register(state, TRL_NOMINAL_RATE_1); | ||
334 | |||
335 | op->code_rate_HP = tps_fec_to_api[(tps >> 7) & 7]; | ||
336 | op->code_rate_LP = tps_fec_to_api[(tps >> 4) & 7]; | ||
337 | |||
338 | switch ( (tps >> 13) & 3) | ||
339 | { | ||
340 | case 0: | ||
341 | op->constellation = QPSK; | ||
342 | break; | ||
343 | case 1: | ||
344 | op->constellation = QAM_16; | ||
345 | break; | ||
346 | case 2: | ||
347 | op->constellation = QAM_64; | ||
348 | break; | ||
349 | default: | ||
350 | op->constellation = QAM_AUTO; | ||
351 | break; | ||
352 | } | ||
353 | |||
354 | op->transmission_mode = (tps & 0x01) ? TRANSMISSION_MODE_8K : TRANSMISSION_MODE_2K; | ||
355 | |||
356 | switch ( (tps >> 2) & 3) | ||
357 | { | ||
358 | case 0: | ||
359 | op->guard_interval = GUARD_INTERVAL_1_32; | ||
360 | break; | ||
361 | case 1: | ||
362 | op->guard_interval = GUARD_INTERVAL_1_16; | ||
363 | break; | ||
364 | case 2: | ||
365 | op->guard_interval = GUARD_INTERVAL_1_8; | ||
366 | break; | ||
367 | case 3: | ||
368 | op->guard_interval = GUARD_INTERVAL_1_4; | ||
369 | break; | ||
370 | default: | ||
371 | op->guard_interval = GUARD_INTERVAL_AUTO; | ||
372 | break; | ||
373 | } | ||
374 | |||
375 | switch ( (tps >> 10) & 7) | ||
376 | { | ||
377 | case 0: | ||
378 | op->hierarchy_information = HIERARCHY_NONE; | ||
379 | break; | ||
380 | case 1: | ||
381 | op->hierarchy_information = HIERARCHY_1; | ||
382 | break; | ||
383 | case 2: | ||
384 | op->hierarchy_information = HIERARCHY_2; | ||
385 | break; | ||
386 | case 3: | ||
387 | op->hierarchy_information = HIERARCHY_4; | ||
388 | break; | ||
389 | default: | ||
390 | op->hierarchy_information = HIERARCHY_AUTO; | ||
391 | break; | ||
392 | } | ||
393 | |||
394 | param->frequency = ( 500 * (div - IF_FREQUENCYx6) ) / 3 * 1000; | ||
395 | |||
396 | if (trl == 0x72) | ||
397 | op->bandwidth = BANDWIDTH_8_MHZ; | ||
398 | else if (trl == 0x64) | ||
399 | op->bandwidth = BANDWIDTH_7_MHZ; | ||
400 | else | ||
401 | op->bandwidth = BANDWIDTH_6_MHZ; | ||
402 | |||
403 | |||
404 | if (mt352_read_register(state, STATUS_2) & 0x02) | ||
405 | param->inversion = INVERSION_OFF; | ||
406 | else | ||
407 | param->inversion = INVERSION_ON; | ||
408 | |||
409 | return 0; | ||
410 | } | ||
411 | |||
412 | static int mt352_read_status(struct dvb_frontend* fe, fe_status_t* status) | ||
413 | { | ||
414 | struct mt352_state* state = fe->demodulator_priv; | ||
415 | int s0, s1, s3; | ||
416 | |||
417 | /* FIXME: | ||
418 | * | ||
419 | * The MT352 design manual from Zarlink states (page 46-47): | ||
420 | * | ||
421 | * Notes about the TUNER_GO register: | ||
422 | * | ||
423 | * If the Read_Tuner_Byte (bit-1) is activated, then the tuner status | ||
424 | * byte is copied from the tuner to the STATUS_3 register and | ||
425 | * completion of the read operation is indicated by bit-5 of the | ||
426 | * INTERRUPT_3 register. | ||
427 | */ | ||
428 | |||
429 | if ((s0 = mt352_read_register(state, STATUS_0)) < 0) | ||
430 | return -EREMOTEIO; | ||
431 | if ((s1 = mt352_read_register(state, STATUS_1)) < 0) | ||
432 | return -EREMOTEIO; | ||
433 | if ((s3 = mt352_read_register(state, STATUS_3)) < 0) | ||
434 | return -EREMOTEIO; | ||
435 | |||
436 | *status = 0; | ||
437 | if (s0 & (1 << 4)) | ||
438 | *status |= FE_HAS_CARRIER; | ||
439 | if (s0 & (1 << 1)) | ||
440 | *status |= FE_HAS_VITERBI; | ||
441 | if (s0 & (1 << 5)) | ||
442 | *status |= FE_HAS_LOCK; | ||
443 | if (s1 & (1 << 1)) | ||
444 | *status |= FE_HAS_SYNC; | ||
445 | if (s3 & (1 << 6)) | ||
446 | *status |= FE_HAS_SIGNAL; | ||
447 | |||
448 | if ((*status & (FE_HAS_CARRIER | FE_HAS_VITERBI | FE_HAS_SYNC)) != | ||
449 | (FE_HAS_CARRIER | FE_HAS_VITERBI | FE_HAS_SYNC)) | ||
450 | *status &= ~FE_HAS_LOCK; | ||
451 | |||
452 | return 0; | ||
453 | } | ||
454 | |||
455 | static int mt352_read_ber(struct dvb_frontend* fe, u32* ber) | ||
456 | { | ||
457 | struct mt352_state* state = fe->demodulator_priv; | ||
458 | |||
459 | *ber = (mt352_read_register (state, RS_ERR_CNT_2) << 16) | | ||
460 | (mt352_read_register (state, RS_ERR_CNT_1) << 8) | | ||
461 | (mt352_read_register (state, RS_ERR_CNT_0)); | ||
462 | |||
463 | return 0; | ||
464 | } | ||
465 | |||
466 | static int mt352_read_signal_strength(struct dvb_frontend* fe, u16* strength) | ||
467 | { | ||
468 | struct mt352_state* state = fe->demodulator_priv; | ||
469 | |||
470 | u16 signal = ((mt352_read_register(state, AGC_GAIN_1) << 8) & 0x0f) | | ||
471 | (mt352_read_register(state, AGC_GAIN_0)); | ||
472 | |||
473 | *strength = ~signal; | ||
474 | return 0; | ||
475 | } | ||
476 | |||
477 | static int mt352_read_snr(struct dvb_frontend* fe, u16* snr) | ||
478 | { | ||
479 | struct mt352_state* state = fe->demodulator_priv; | ||
480 | |||
481 | u8 _snr = mt352_read_register (state, SNR); | ||
482 | *snr = (_snr << 8) | _snr; | ||
483 | |||
484 | return 0; | ||
485 | } | ||
486 | |||
487 | static int mt352_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks) | ||
488 | { | ||
489 | struct mt352_state* state = fe->demodulator_priv; | ||
490 | |||
491 | *ucblocks = (mt352_read_register (state, RS_UBC_1) << 8) | | ||
492 | (mt352_read_register (state, RS_UBC_0)); | ||
493 | |||
494 | return 0; | ||
495 | } | ||
496 | |||
497 | static int mt352_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings* fe_tune_settings) | ||
498 | { | ||
499 | fe_tune_settings->min_delay_ms = 800; | ||
500 | fe_tune_settings->step_size = 0; | ||
501 | fe_tune_settings->max_drift = 0; | ||
502 | |||
503 | return 0; | ||
504 | } | ||
505 | |||
506 | static int mt352_init(struct dvb_frontend* fe) | ||
507 | { | ||
508 | struct mt352_state* state = fe->demodulator_priv; | ||
509 | |||
510 | static u8 mt352_reset_attach [] = { RESET, 0xC0 }; | ||
511 | |||
512 | dprintk("%s: hello\n",__FUNCTION__); | ||
513 | |||
514 | if ((mt352_read_register(state, CLOCK_CTL) & 0x10) == 0 || | ||
515 | (mt352_read_register(state, CONFIG) & 0x20) == 0) { | ||
516 | |||
517 | /* Do a "hard" reset */ | ||
518 | mt352_write(fe, mt352_reset_attach, sizeof(mt352_reset_attach)); | ||
519 | return state->config->demod_init(fe); | ||
520 | } | ||
521 | |||
522 | return 0; | ||
523 | } | ||
524 | |||
525 | static void mt352_release(struct dvb_frontend* fe) | ||
526 | { | ||
527 | struct mt352_state* state = fe->demodulator_priv; | ||
528 | kfree(state); | ||
529 | } | ||
530 | |||
531 | static struct dvb_frontend_ops mt352_ops; | ||
532 | |||
533 | struct dvb_frontend* mt352_attach(const struct mt352_config* config, | ||
534 | struct i2c_adapter* i2c) | ||
535 | { | ||
536 | struct mt352_state* state = NULL; | ||
537 | |||
538 | /* allocate memory for the internal state */ | ||
539 | state = kmalloc(sizeof(struct mt352_state), GFP_KERNEL); | ||
540 | if (state == NULL) goto error; | ||
541 | memset(state,0,sizeof(*state)); | ||
542 | |||
543 | /* setup the state */ | ||
544 | state->config = config; | ||
545 | state->i2c = i2c; | ||
546 | memcpy(&state->ops, &mt352_ops, sizeof(struct dvb_frontend_ops)); | ||
547 | |||
548 | /* check if the demod is there */ | ||
549 | if (mt352_read_register(state, CHIP_ID) != ID_MT352) goto error; | ||
550 | |||
551 | /* create dvb_frontend */ | ||
552 | state->frontend.ops = &state->ops; | ||
553 | state->frontend.demodulator_priv = state; | ||
554 | return &state->frontend; | ||
555 | |||
556 | error: | ||
557 | kfree(state); | ||
558 | return NULL; | ||
559 | } | ||
560 | |||
561 | static struct dvb_frontend_ops mt352_ops = { | ||
562 | |||
563 | .info = { | ||
564 | .name = "Zarlink MT352 DVB-T", | ||
565 | .type = FE_OFDM, | ||
566 | .frequency_min = 174000000, | ||
567 | .frequency_max = 862000000, | ||
568 | .frequency_stepsize = 166667, | ||
569 | .frequency_tolerance = 0, | ||
570 | .caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | | ||
571 | FE_CAN_FEC_3_4 | FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | | ||
572 | FE_CAN_FEC_AUTO | | ||
573 | FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO | | ||
574 | FE_CAN_TRANSMISSION_MODE_AUTO | FE_CAN_GUARD_INTERVAL_AUTO | | ||
575 | FE_CAN_HIERARCHY_AUTO | FE_CAN_RECOVER | | ||
576 | FE_CAN_MUTE_TS | ||
577 | }, | ||
578 | |||
579 | .release = mt352_release, | ||
580 | |||
581 | .init = mt352_init, | ||
582 | .sleep = mt352_sleep, | ||
583 | |||
584 | .set_frontend = mt352_set_parameters, | ||
585 | .get_frontend = mt352_get_parameters, | ||
586 | .get_tune_settings = mt352_get_tune_settings, | ||
587 | |||
588 | .read_status = mt352_read_status, | ||
589 | .read_ber = mt352_read_ber, | ||
590 | .read_signal_strength = mt352_read_signal_strength, | ||
591 | .read_snr = mt352_read_snr, | ||
592 | .read_ucblocks = mt352_read_ucblocks, | ||
593 | }; | ||
594 | |||
595 | module_param(debug, int, 0644); | ||
596 | MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off)."); | ||
597 | |||
598 | MODULE_DESCRIPTION("Zarlink MT352 DVB-T Demodulator driver"); | ||
599 | MODULE_AUTHOR("Holger Waechtler, Daniel Mack, Antonio Mancuso"); | ||
600 | MODULE_LICENSE("GPL"); | ||
601 | |||
602 | EXPORT_SYMBOL(mt352_attach); | ||
603 | EXPORT_SYMBOL(mt352_write); | ||
604 | EXPORT_SYMBOL(mt352_read); | ||
605 | /* | ||
606 | * Local variables: | ||
607 | * c-basic-offset: 8 | ||
608 | * compile-command: "make DVB=1" | ||
609 | * End: | ||
610 | */ | ||
diff --git a/drivers/media/dvb/frontends/mt352.h b/drivers/media/dvb/frontends/mt352.h new file mode 100644 index 000000000000..f5d8a5aed8a9 --- /dev/null +++ b/drivers/media/dvb/frontends/mt352.h | |||
@@ -0,0 +1,72 @@ | |||
1 | /* | ||
2 | * Driver for Zarlink DVB-T MT352 demodulator | ||
3 | * | ||
4 | * Written by Holger Waechtler <holger@qanu.de> | ||
5 | * and Daniel Mack <daniel@qanu.de> | ||
6 | * | ||
7 | * AVerMedia AVerTV DVB-T 771 support by | ||
8 | * Wolfram Joost <dbox2@frokaschwei.de> | ||
9 | * | ||
10 | * Support for Samsung TDTC9251DH01C(M) tuner | ||
11 | * Copyright (C) 2004 Antonio Mancuso <antonio.mancuso@digitaltelevision.it> | ||
12 | * Amauri Celani <acelani@essegi.net> | ||
13 | * | ||
14 | * DVICO FusionHDTV DVB-T1 and DVICO FusionHDTV DVB-T Lite support by | ||
15 | * Christopher Pascoe <c.pascoe@itee.uq.edu.au> | ||
16 | * | ||
17 | * This program is free software; you can redistribute it and/or modify | ||
18 | * it under the terms of the GNU General Public License as published by | ||
19 | * the Free Software Foundation; either version 2 of the License, or | ||
20 | * (at your option) any later version. | ||
21 | * | ||
22 | * This program is distributed in the hope that it will be useful, | ||
23 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
24 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
25 | * | ||
26 | * GNU General Public License for more details. | ||
27 | * | ||
28 | * You should have received a copy of the GNU General Public License | ||
29 | * along with this program; if not, write to the Free Software | ||
30 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.= | ||
31 | */ | ||
32 | |||
33 | #ifndef MT352_H | ||
34 | #define MT352_H | ||
35 | |||
36 | #include <linux/dvb/frontend.h> | ||
37 | |||
38 | struct mt352_config | ||
39 | { | ||
40 | /* the demodulator's i2c address */ | ||
41 | u8 demod_address; | ||
42 | |||
43 | /* frequencies in kHz */ | ||
44 | int adc_clock; // default: 20480 | ||
45 | int if2; // default: 36166 | ||
46 | |||
47 | /* set if no pll is connected to the secondary i2c bus */ | ||
48 | int no_tuner; | ||
49 | |||
50 | /* Initialise the demodulator and PLL. Cannot be NULL */ | ||
51 | int (*demod_init)(struct dvb_frontend* fe); | ||
52 | |||
53 | /* PLL setup - fill out the supplied 5 byte buffer with your PLL settings. | ||
54 | * byte0: Set to pll i2c address (nonlinux; left shifted by 1) | ||
55 | * byte1-4: PLL configuration. | ||
56 | */ | ||
57 | int (*pll_set)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params, u8* pllbuf); | ||
58 | }; | ||
59 | |||
60 | extern struct dvb_frontend* mt352_attach(const struct mt352_config* config, | ||
61 | struct i2c_adapter* i2c); | ||
62 | |||
63 | extern int mt352_write(struct dvb_frontend* fe, u8* ibuf, int ilen); | ||
64 | extern int mt352_read(struct dvb_frontend *fe, u8 reg); | ||
65 | |||
66 | #endif // MT352_H | ||
67 | |||
68 | /* | ||
69 | * Local variables: | ||
70 | * c-basic-offset: 8 | ||
71 | * End: | ||
72 | */ | ||
diff --git a/drivers/media/dvb/frontends/mt352_priv.h b/drivers/media/dvb/frontends/mt352_priv.h new file mode 100644 index 000000000000..44ad0d4c8f12 --- /dev/null +++ b/drivers/media/dvb/frontends/mt352_priv.h | |||
@@ -0,0 +1,127 @@ | |||
1 | /* | ||
2 | * Driver for Zarlink DVB-T MT352 demodulator | ||
3 | * | ||
4 | * Written by Holger Waechtler <holger@qanu.de> | ||
5 | * and Daniel Mack <daniel@qanu.de> | ||
6 | * | ||
7 | * AVerMedia AVerTV DVB-T 771 support by | ||
8 | * Wolfram Joost <dbox2@frokaschwei.de> | ||
9 | * | ||
10 | * Support for Samsung TDTC9251DH01C(M) tuner | ||
11 | * Copyright (C) 2004 Antonio Mancuso <antonio.mancuso@digitaltelevision.it> | ||
12 | * Amauri Celani <acelani@essegi.net> | ||
13 | * | ||
14 | * DVICO FusionHDTV DVB-T1 and DVICO FusionHDTV DVB-T Lite support by | ||
15 | * Christopher Pascoe <c.pascoe@itee.uq.edu.au> | ||
16 | * | ||
17 | * This program is free software; you can redistribute it and/or modify | ||
18 | * it under the terms of the GNU General Public License as published by | ||
19 | * the Free Software Foundation; either version 2 of the License, or | ||
20 | * (at your option) any later version. | ||
21 | * | ||
22 | * This program is distributed in the hope that it will be useful, | ||
23 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
24 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
25 | * | ||
26 | * GNU General Public License for more details. | ||
27 | * | ||
28 | * You should have received a copy of the GNU General Public License | ||
29 | * along with this program; if not, write to the Free Software | ||
30 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.= | ||
31 | */ | ||
32 | |||
33 | #ifndef _MT352_PRIV_ | ||
34 | #define _MT352_PRIV_ | ||
35 | |||
36 | #define ID_MT352 0x13 | ||
37 | |||
38 | #define msb(x) (((x) >> 8) & 0xff) | ||
39 | #define lsb(x) ((x) & 0xff) | ||
40 | |||
41 | enum mt352_reg_addr { | ||
42 | STATUS_0 = 0x00, | ||
43 | STATUS_1 = 0x01, | ||
44 | STATUS_2 = 0x02, | ||
45 | STATUS_3 = 0x03, | ||
46 | STATUS_4 = 0x04, | ||
47 | INTERRUPT_0 = 0x05, | ||
48 | INTERRUPT_1 = 0x06, | ||
49 | INTERRUPT_2 = 0x07, | ||
50 | INTERRUPT_3 = 0x08, | ||
51 | SNR = 0x09, | ||
52 | VIT_ERR_CNT_2 = 0x0A, | ||
53 | VIT_ERR_CNT_1 = 0x0B, | ||
54 | VIT_ERR_CNT_0 = 0x0C, | ||
55 | RS_ERR_CNT_2 = 0x0D, | ||
56 | RS_ERR_CNT_1 = 0x0E, | ||
57 | RS_ERR_CNT_0 = 0x0F, | ||
58 | RS_UBC_1 = 0x10, | ||
59 | RS_UBC_0 = 0x11, | ||
60 | AGC_GAIN_3 = 0x12, | ||
61 | AGC_GAIN_2 = 0x13, | ||
62 | AGC_GAIN_1 = 0x14, | ||
63 | AGC_GAIN_0 = 0x15, | ||
64 | FREQ_OFFSET_2 = 0x17, | ||
65 | FREQ_OFFSET_1 = 0x18, | ||
66 | FREQ_OFFSET_0 = 0x19, | ||
67 | TIMING_OFFSET_1 = 0x1A, | ||
68 | TIMING_OFFSET_0 = 0x1B, | ||
69 | CHAN_FREQ_1 = 0x1C, | ||
70 | CHAN_FREQ_0 = 0x1D, | ||
71 | TPS_RECEIVED_1 = 0x1E, | ||
72 | TPS_RECEIVED_0 = 0x1F, | ||
73 | TPS_CURRENT_1 = 0x20, | ||
74 | TPS_CURRENT_0 = 0x21, | ||
75 | TPS_CELL_ID_1 = 0x22, | ||
76 | TPS_CELL_ID_0 = 0x23, | ||
77 | TPS_MISC_DATA_2 = 0x24, | ||
78 | TPS_MISC_DATA_1 = 0x25, | ||
79 | TPS_MISC_DATA_0 = 0x26, | ||
80 | RESET = 0x50, | ||
81 | TPS_GIVEN_1 = 0x51, | ||
82 | TPS_GIVEN_0 = 0x52, | ||
83 | ACQ_CTL = 0x53, | ||
84 | TRL_NOMINAL_RATE_1 = 0x54, | ||
85 | TRL_NOMINAL_RATE_0 = 0x55, | ||
86 | INPUT_FREQ_1 = 0x56, | ||
87 | INPUT_FREQ_0 = 0x57, | ||
88 | TUNER_ADDR = 0x58, | ||
89 | CHAN_START_1 = 0x59, | ||
90 | CHAN_START_0 = 0x5A, | ||
91 | CONT_1 = 0x5B, | ||
92 | CONT_0 = 0x5C, | ||
93 | TUNER_GO = 0x5D, | ||
94 | STATUS_EN_0 = 0x5F, | ||
95 | STATUS_EN_1 = 0x60, | ||
96 | INTERRUPT_EN_0 = 0x61, | ||
97 | INTERRUPT_EN_1 = 0x62, | ||
98 | INTERRUPT_EN_2 = 0x63, | ||
99 | INTERRUPT_EN_3 = 0x64, | ||
100 | AGC_TARGET = 0x67, | ||
101 | AGC_CTL = 0x68, | ||
102 | CAPT_RANGE = 0x75, | ||
103 | SNR_SELECT_1 = 0x79, | ||
104 | SNR_SELECT_0 = 0x7A, | ||
105 | RS_ERR_PER_1 = 0x7C, | ||
106 | RS_ERR_PER_0 = 0x7D, | ||
107 | CHIP_ID = 0x7F, | ||
108 | CHAN_STOP_1 = 0x80, | ||
109 | CHAN_STOP_0 = 0x81, | ||
110 | CHAN_STEP_1 = 0x82, | ||
111 | CHAN_STEP_0 = 0x83, | ||
112 | FEC_LOCK_TIME = 0x85, | ||
113 | OFDM_LOCK_TIME = 0x86, | ||
114 | ACQ_DELAY = 0x87, | ||
115 | SCAN_CTL = 0x88, | ||
116 | CLOCK_CTL = 0x89, | ||
117 | CONFIG = 0x8A, | ||
118 | MCLK_RATIO = 0x8B, | ||
119 | GPP_CTL = 0x8C, | ||
120 | ADC_CTL_1 = 0x8E, | ||
121 | ADC_CTL_0 = 0x8F | ||
122 | }; | ||
123 | |||
124 | /* here we assume 1/6MHz == 166.66kHz stepsize */ | ||
125 | #define IF_FREQUENCYx6 217 /* 6 * 36.16666666667MHz */ | ||
126 | |||
127 | #endif /* _MT352_PRIV_ */ | ||
diff --git a/drivers/media/dvb/frontends/nxt2002.c b/drivers/media/dvb/frontends/nxt2002.c new file mode 100644 index 000000000000..4743aa17406e --- /dev/null +++ b/drivers/media/dvb/frontends/nxt2002.c | |||
@@ -0,0 +1,705 @@ | |||
1 | /* | ||
2 | Support for B2C2/BBTI Technisat Air2PC - ATSC | ||
3 | |||
4 | Copyright (C) 2004 Taylor Jacob <rtjacob@earthlink.net> | ||
5 | |||
6 | This program is free software; you can redistribute it and/or modify | ||
7 | it under the terms of the GNU General Public License as published by | ||
8 | the Free Software Foundation; either version 2 of the License, or | ||
9 | (at your option) any later version. | ||
10 | |||
11 | This program is distributed in the hope that it will be useful, | ||
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | GNU General Public License for more details. | ||
15 | |||
16 | You should have received a copy of the GNU General Public License | ||
17 | along with this program; if not, write to the Free Software | ||
18 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
19 | |||
20 | */ | ||
21 | |||
22 | /* | ||
23 | * This driver needs external firmware. Please use the command | ||
24 | * "<kerneldir>/Documentation/dvb/get_dvb_firmware nxt2002" to | ||
25 | * download/extract it, and then copy it to /usr/lib/hotplug/firmware. | ||
26 | */ | ||
27 | #define NXT2002_DEFAULT_FIRMWARE "dvb-fe-nxt2002.fw" | ||
28 | #define CRC_CCIT_MASK 0x1021 | ||
29 | |||
30 | #include <linux/init.h> | ||
31 | #include <linux/module.h> | ||
32 | #include <linux/moduleparam.h> | ||
33 | #include <linux/device.h> | ||
34 | #include <linux/firmware.h> | ||
35 | |||
36 | #include "dvb_frontend.h" | ||
37 | #include "nxt2002.h" | ||
38 | |||
39 | struct nxt2002_state { | ||
40 | |||
41 | struct i2c_adapter* i2c; | ||
42 | struct dvb_frontend_ops ops; | ||
43 | const struct nxt2002_config* config; | ||
44 | struct dvb_frontend frontend; | ||
45 | |||
46 | /* demodulator private data */ | ||
47 | u8 initialised:1; | ||
48 | }; | ||
49 | |||
50 | static int debug; | ||
51 | #define dprintk(args...) \ | ||
52 | do { \ | ||
53 | if (debug) printk(KERN_DEBUG "nxt2002: " args); \ | ||
54 | } while (0) | ||
55 | |||
56 | static int i2c_writebytes (struct nxt2002_state* state, u8 reg, u8 *buf, u8 len) | ||
57 | { | ||
58 | /* probbably a much better way or doing this */ | ||
59 | u8 buf2 [256],x; | ||
60 | int err; | ||
61 | struct i2c_msg msg = { .addr = state->config->demod_address, .flags = 0, .buf = buf2, .len = len + 1 }; | ||
62 | |||
63 | buf2[0] = reg; | ||
64 | for (x = 0 ; x < len ; x++) | ||
65 | buf2[x+1] = buf[x]; | ||
66 | |||
67 | if ((err = i2c_transfer (state->i2c, &msg, 1)) != 1) { | ||
68 | printk ("%s: i2c write error (addr %02x, err == %i)\n", | ||
69 | __FUNCTION__, state->config->demod_address, err); | ||
70 | return -EREMOTEIO; | ||
71 | } | ||
72 | |||
73 | return 0; | ||
74 | } | ||
75 | |||
76 | static u8 i2c_readbytes (struct nxt2002_state* state, u8 reg, u8* buf, u8 len) | ||
77 | { | ||
78 | u8 reg2 [] = { reg }; | ||
79 | |||
80 | struct i2c_msg msg [] = { { .addr = state->config->demod_address, .flags = 0, .buf = reg2, .len = 1 }, | ||
81 | { .addr = state->config->demod_address, .flags = I2C_M_RD, .buf = buf, .len = len } }; | ||
82 | |||
83 | int err; | ||
84 | |||
85 | if ((err = i2c_transfer (state->i2c, msg, 2)) != 2) { | ||
86 | printk ("%s: i2c read error (addr %02x, err == %i)\n", | ||
87 | __FUNCTION__, state->config->demod_address, err); | ||
88 | return -EREMOTEIO; | ||
89 | } | ||
90 | |||
91 | return 0; | ||
92 | } | ||
93 | |||
94 | static u16 nxt2002_crc(u16 crc, u8 c) | ||
95 | { | ||
96 | |||
97 | u8 i; | ||
98 | u16 input = (u16) c & 0xFF; | ||
99 | |||
100 | input<<=8; | ||
101 | for(i=0 ;i<8 ;i++) { | ||
102 | if((crc ^ input) & 0x8000) | ||
103 | crc=(crc<<1)^CRC_CCIT_MASK; | ||
104 | else | ||
105 | crc<<=1; | ||
106 | input<<=1; | ||
107 | } | ||
108 | return crc; | ||
109 | } | ||
110 | |||
111 | static int nxt2002_writereg_multibyte (struct nxt2002_state* state, u8 reg, u8* data, u8 len) | ||
112 | { | ||
113 | u8 buf; | ||
114 | dprintk("%s\n", __FUNCTION__); | ||
115 | |||
116 | /* set multi register length */ | ||
117 | i2c_writebytes(state,0x34,&len,1); | ||
118 | |||
119 | /* set mutli register register */ | ||
120 | i2c_writebytes(state,0x35,®,1); | ||
121 | |||
122 | /* send the actual data */ | ||
123 | i2c_writebytes(state,0x36,data,len); | ||
124 | |||
125 | /* toggle the multireg write bit*/ | ||
126 | buf = 0x02; | ||
127 | i2c_writebytes(state,0x21,&buf,1); | ||
128 | |||
129 | i2c_readbytes(state,0x21,&buf,1); | ||
130 | |||
131 | if ((buf & 0x02) == 0) | ||
132 | return 0; | ||
133 | |||
134 | dprintk("Error writing multireg register %02X\n",reg); | ||
135 | |||
136 | return 0; | ||
137 | } | ||
138 | |||
139 | static int nxt2002_readreg_multibyte (struct nxt2002_state* state, u8 reg, u8* data, u8 len) | ||
140 | { | ||
141 | u8 len2; | ||
142 | dprintk("%s\n", __FUNCTION__); | ||
143 | |||
144 | /* set multi register length */ | ||
145 | len2 = len & 0x80; | ||
146 | i2c_writebytes(state,0x34,&len2,1); | ||
147 | |||
148 | /* set mutli register register */ | ||
149 | i2c_writebytes(state,0x35,®,1); | ||
150 | |||
151 | /* send the actual data */ | ||
152 | i2c_readbytes(state,reg,data,len); | ||
153 | |||
154 | return 0; | ||
155 | } | ||
156 | |||
157 | static void nxt2002_microcontroller_stop (struct nxt2002_state* state) | ||
158 | { | ||
159 | u8 buf[2],counter = 0; | ||
160 | dprintk("%s\n", __FUNCTION__); | ||
161 | |||
162 | buf[0] = 0x80; | ||
163 | i2c_writebytes(state,0x22,buf,1); | ||
164 | |||
165 | while (counter < 20) { | ||
166 | i2c_readbytes(state,0x31,buf,1); | ||
167 | if (buf[0] & 0x40) | ||
168 | return; | ||
169 | msleep(10); | ||
170 | counter++; | ||
171 | } | ||
172 | |||
173 | dprintk("Timeout waiting for micro to stop.. This is ok after firmware upload\n"); | ||
174 | return; | ||
175 | } | ||
176 | |||
177 | static void nxt2002_microcontroller_start (struct nxt2002_state* state) | ||
178 | { | ||
179 | u8 buf; | ||
180 | dprintk("%s\n", __FUNCTION__); | ||
181 | |||
182 | buf = 0x00; | ||
183 | i2c_writebytes(state,0x22,&buf,1); | ||
184 | } | ||
185 | |||
186 | static int nxt2002_writetuner (struct nxt2002_state* state, u8* data) | ||
187 | { | ||
188 | u8 buf,count = 0; | ||
189 | |||
190 | dprintk("Tuner Bytes: %02X %02X %02X %02X\n",data[0],data[1],data[2],data[3]); | ||
191 | |||
192 | dprintk("%s\n", __FUNCTION__); | ||
193 | /* stop the micro first */ | ||
194 | nxt2002_microcontroller_stop(state); | ||
195 | |||
196 | /* set the i2c transfer speed to the tuner */ | ||
197 | buf = 0x03; | ||
198 | i2c_writebytes(state,0x20,&buf,1); | ||
199 | |||
200 | /* setup to transfer 4 bytes via i2c */ | ||
201 | buf = 0x04; | ||
202 | i2c_writebytes(state,0x34,&buf,1); | ||
203 | |||
204 | /* write actual tuner bytes */ | ||
205 | i2c_writebytes(state,0x36,data,4); | ||
206 | |||
207 | /* set tuner i2c address */ | ||
208 | buf = 0xC2; | ||
209 | i2c_writebytes(state,0x35,&buf,1); | ||
210 | |||
211 | /* write UC Opmode to begin transfer */ | ||
212 | buf = 0x80; | ||
213 | i2c_writebytes(state,0x21,&buf,1); | ||
214 | |||
215 | while (count < 20) { | ||
216 | i2c_readbytes(state,0x21,&buf,1); | ||
217 | if ((buf & 0x80)== 0x00) | ||
218 | return 0; | ||
219 | msleep(100); | ||
220 | count++; | ||
221 | } | ||
222 | |||
223 | printk("nxt2002: timeout error writing tuner\n"); | ||
224 | return 0; | ||
225 | } | ||
226 | |||
227 | static void nxt2002_agc_reset(struct nxt2002_state* state) | ||
228 | { | ||
229 | u8 buf; | ||
230 | dprintk("%s\n", __FUNCTION__); | ||
231 | |||
232 | buf = 0x08; | ||
233 | i2c_writebytes(state,0x08,&buf,1); | ||
234 | |||
235 | buf = 0x00; | ||
236 | i2c_writebytes(state,0x08,&buf,1); | ||
237 | |||
238 | return; | ||
239 | } | ||
240 | |||
241 | static int nxt2002_load_firmware (struct dvb_frontend* fe, const struct firmware *fw) | ||
242 | { | ||
243 | |||
244 | struct nxt2002_state* state = (struct nxt2002_state*) fe->demodulator_priv; | ||
245 | u8 buf[256],written = 0,chunkpos = 0; | ||
246 | u16 rambase,position,crc = 0; | ||
247 | |||
248 | dprintk("%s\n", __FUNCTION__); | ||
249 | dprintk("Firmware is %zu bytes\n",fw->size); | ||
250 | |||
251 | /* Get the RAM base for this nxt2002 */ | ||
252 | i2c_readbytes(state,0x10,buf,1); | ||
253 | |||
254 | if (buf[0] & 0x10) | ||
255 | rambase = 0x1000; | ||
256 | else | ||
257 | rambase = 0x0000; | ||
258 | |||
259 | dprintk("rambase on this nxt2002 is %04X\n",rambase); | ||
260 | |||
261 | /* Hold the micro in reset while loading firmware */ | ||
262 | buf[0] = 0x80; | ||
263 | i2c_writebytes(state,0x2B,buf,1); | ||
264 | |||
265 | for (position = 0; position < fw->size ; position++) { | ||
266 | if (written == 0) { | ||
267 | crc = 0; | ||
268 | chunkpos = 0x28; | ||
269 | buf[0] = ((rambase + position) >> 8); | ||
270 | buf[1] = (rambase + position) & 0xFF; | ||
271 | buf[2] = 0x81; | ||
272 | /* write starting address */ | ||
273 | i2c_writebytes(state,0x29,buf,3); | ||
274 | } | ||
275 | written++; | ||
276 | chunkpos++; | ||
277 | |||
278 | if ((written % 4) == 0) | ||
279 | i2c_writebytes(state,chunkpos,&fw->data[position-3],4); | ||
280 | |||
281 | crc = nxt2002_crc(crc,fw->data[position]); | ||
282 | |||
283 | if ((written == 255) || (position+1 == fw->size)) { | ||
284 | /* write remaining bytes of firmware */ | ||
285 | i2c_writebytes(state, chunkpos+4-(written %4), | ||
286 | &fw->data[position-(written %4) + 1], | ||
287 | written %4); | ||
288 | buf[0] = crc << 8; | ||
289 | buf[1] = crc & 0xFF; | ||
290 | |||
291 | /* write crc */ | ||
292 | i2c_writebytes(state,0x2C,buf,2); | ||
293 | |||
294 | /* do a read to stop things */ | ||
295 | i2c_readbytes(state,0x2A,buf,1); | ||
296 | |||
297 | /* set transfer mode to complete */ | ||
298 | buf[0] = 0x80; | ||
299 | i2c_writebytes(state,0x2B,buf,1); | ||
300 | |||
301 | written = 0; | ||
302 | } | ||
303 | } | ||
304 | |||
305 | printk ("done.\n"); | ||
306 | return 0; | ||
307 | }; | ||
308 | |||
309 | static int nxt2002_setup_frontend_parameters (struct dvb_frontend* fe, | ||
310 | struct dvb_frontend_parameters *p) | ||
311 | { | ||
312 | struct nxt2002_state* state = (struct nxt2002_state*) fe->demodulator_priv; | ||
313 | u32 freq = 0; | ||
314 | u16 tunerfreq = 0; | ||
315 | u8 buf[4]; | ||
316 | |||
317 | freq = 44000 + ( p->frequency / 1000 ); | ||
318 | |||
319 | dprintk("freq = %d p->frequency = %d\n",freq,p->frequency); | ||
320 | |||
321 | tunerfreq = freq * 24/4000; | ||
322 | |||
323 | buf[0] = (tunerfreq >> 8) & 0x7F; | ||
324 | buf[1] = (tunerfreq & 0xFF); | ||
325 | |||
326 | if (p->frequency <= 214000000) { | ||
327 | buf[2] = 0x84 + (0x06 << 3); | ||
328 | buf[3] = (p->frequency <= 172000000) ? 0x01 : 0x02; | ||
329 | } else if (p->frequency <= 721000000) { | ||
330 | buf[2] = 0x84 + (0x07 << 3); | ||
331 | buf[3] = (p->frequency <= 467000000) ? 0x02 : 0x08; | ||
332 | } else if (p->frequency <= 841000000) { | ||
333 | buf[2] = 0x84 + (0x0E << 3); | ||
334 | buf[3] = 0x08; | ||
335 | } else { | ||
336 | buf[2] = 0x84 + (0x0F << 3); | ||
337 | buf[3] = 0x02; | ||
338 | } | ||
339 | |||
340 | /* write frequency information */ | ||
341 | nxt2002_writetuner(state,buf); | ||
342 | |||
343 | /* reset the agc now that tuning has been completed */ | ||
344 | nxt2002_agc_reset(state); | ||
345 | |||
346 | |||
347 | |||
348 | /* set target power level */ | ||
349 | switch (p->u.vsb.modulation) { | ||
350 | case QAM_64: | ||
351 | case QAM_256: | ||
352 | buf[0] = 0x74; | ||
353 | break; | ||
354 | case VSB_8: | ||
355 | buf[0] = 0x70; | ||
356 | break; | ||
357 | default: | ||
358 | return -EINVAL; | ||
359 | break; | ||
360 | } | ||
361 | i2c_writebytes(state,0x42,buf,1); | ||
362 | |||
363 | /* configure sdm */ | ||
364 | buf[0] = 0x87; | ||
365 | i2c_writebytes(state,0x57,buf,1); | ||
366 | |||
367 | /* write sdm1 input */ | ||
368 | buf[0] = 0x10; | ||
369 | buf[1] = 0x00; | ||
370 | nxt2002_writereg_multibyte(state,0x58,buf,2); | ||
371 | |||
372 | /* write sdmx input */ | ||
373 | switch (p->u.vsb.modulation) { | ||
374 | case QAM_64: | ||
375 | buf[0] = 0x68; | ||
376 | break; | ||
377 | case QAM_256: | ||
378 | buf[0] = 0x64; | ||
379 | break; | ||
380 | case VSB_8: | ||
381 | buf[0] = 0x60; | ||
382 | break; | ||
383 | default: | ||
384 | return -EINVAL; | ||
385 | break; | ||
386 | } | ||
387 | buf[1] = 0x00; | ||
388 | nxt2002_writereg_multibyte(state,0x5C,buf,2); | ||
389 | |||
390 | /* write adc power lpf fc */ | ||
391 | buf[0] = 0x05; | ||
392 | i2c_writebytes(state,0x43,buf,1); | ||
393 | |||
394 | /* write adc power lpf fc */ | ||
395 | buf[0] = 0x05; | ||
396 | i2c_writebytes(state,0x43,buf,1); | ||
397 | |||
398 | /* write accumulator2 input */ | ||
399 | buf[0] = 0x80; | ||
400 | buf[1] = 0x00; | ||
401 | nxt2002_writereg_multibyte(state,0x4B,buf,2); | ||
402 | |||
403 | /* write kg1 */ | ||
404 | buf[0] = 0x00; | ||
405 | i2c_writebytes(state,0x4D,buf,1); | ||
406 | |||
407 | /* write sdm12 lpf fc */ | ||
408 | buf[0] = 0x44; | ||
409 | i2c_writebytes(state,0x55,buf,1); | ||
410 | |||
411 | /* write agc control reg */ | ||
412 | buf[0] = 0x04; | ||
413 | i2c_writebytes(state,0x41,buf,1); | ||
414 | |||
415 | /* write agc ucgp0 */ | ||
416 | switch (p->u.vsb.modulation) { | ||
417 | case QAM_64: | ||
418 | buf[0] = 0x02; | ||
419 | break; | ||
420 | case QAM_256: | ||
421 | buf[0] = 0x03; | ||
422 | break; | ||
423 | case VSB_8: | ||
424 | buf[0] = 0x00; | ||
425 | break; | ||
426 | default: | ||
427 | return -EINVAL; | ||
428 | break; | ||
429 | } | ||
430 | i2c_writebytes(state,0x30,buf,1); | ||
431 | |||
432 | /* write agc control reg */ | ||
433 | buf[0] = 0x00; | ||
434 | i2c_writebytes(state,0x41,buf,1); | ||
435 | |||
436 | /* write accumulator2 input */ | ||
437 | buf[0] = 0x80; | ||
438 | buf[1] = 0x00; | ||
439 | nxt2002_writereg_multibyte(state,0x49,buf,2); | ||
440 | nxt2002_writereg_multibyte(state,0x4B,buf,2); | ||
441 | |||
442 | /* write agc control reg */ | ||
443 | buf[0] = 0x04; | ||
444 | i2c_writebytes(state,0x41,buf,1); | ||
445 | |||
446 | nxt2002_microcontroller_start(state); | ||
447 | |||
448 | /* adjacent channel detection should be done here, but I don't | ||
449 | have any stations with this need so I cannot test it */ | ||
450 | |||
451 | return 0; | ||
452 | } | ||
453 | |||
454 | static int nxt2002_read_status(struct dvb_frontend* fe, fe_status_t* status) | ||
455 | { | ||
456 | struct nxt2002_state* state = (struct nxt2002_state*) fe->demodulator_priv; | ||
457 | u8 lock; | ||
458 | i2c_readbytes(state,0x31,&lock,1); | ||
459 | |||
460 | *status = 0; | ||
461 | if (lock & 0x20) { | ||
462 | *status |= FE_HAS_SIGNAL; | ||
463 | *status |= FE_HAS_CARRIER; | ||
464 | *status |= FE_HAS_VITERBI; | ||
465 | *status |= FE_HAS_SYNC; | ||
466 | *status |= FE_HAS_LOCK; | ||
467 | } | ||
468 | return 0; | ||
469 | } | ||
470 | |||
471 | static int nxt2002_read_ber(struct dvb_frontend* fe, u32* ber) | ||
472 | { | ||
473 | struct nxt2002_state* state = (struct nxt2002_state*) fe->demodulator_priv; | ||
474 | u8 b[3]; | ||
475 | |||
476 | nxt2002_readreg_multibyte(state,0xE6,b,3); | ||
477 | |||
478 | *ber = ((b[0] << 8) + b[1]) * 8; | ||
479 | |||
480 | return 0; | ||
481 | } | ||
482 | |||
483 | static int nxt2002_read_signal_strength(struct dvb_frontend* fe, u16* strength) | ||
484 | { | ||
485 | struct nxt2002_state* state = (struct nxt2002_state*) fe->demodulator_priv; | ||
486 | u8 b[2]; | ||
487 | u16 temp = 0; | ||
488 | |||
489 | /* setup to read cluster variance */ | ||
490 | b[0] = 0x00; | ||
491 | i2c_writebytes(state,0xA1,b,1); | ||
492 | |||
493 | /* get multreg val */ | ||
494 | nxt2002_readreg_multibyte(state,0xA6,b,2); | ||
495 | |||
496 | temp = (b[0] << 8) | b[1]; | ||
497 | *strength = ((0x7FFF - temp) & 0x0FFF) * 16; | ||
498 | |||
499 | return 0; | ||
500 | } | ||
501 | |||
502 | static int nxt2002_read_snr(struct dvb_frontend* fe, u16* snr) | ||
503 | { | ||
504 | |||
505 | struct nxt2002_state* state = (struct nxt2002_state*) fe->demodulator_priv; | ||
506 | u8 b[2]; | ||
507 | u16 temp = 0, temp2; | ||
508 | u32 snrdb = 0; | ||
509 | |||
510 | /* setup to read cluster variance */ | ||
511 | b[0] = 0x00; | ||
512 | i2c_writebytes(state,0xA1,b,1); | ||
513 | |||
514 | /* get multreg val from 0xA6 */ | ||
515 | nxt2002_readreg_multibyte(state,0xA6,b,2); | ||
516 | |||
517 | temp = (b[0] << 8) | b[1]; | ||
518 | temp2 = 0x7FFF - temp; | ||
519 | |||
520 | /* snr will be in db */ | ||
521 | if (temp2 > 0x7F00) | ||
522 | snrdb = 1000*24 + ( 1000*(30-24) * ( temp2 - 0x7F00 ) / ( 0x7FFF - 0x7F00 ) ); | ||
523 | else if (temp2 > 0x7EC0) | ||
524 | snrdb = 1000*18 + ( 1000*(24-18) * ( temp2 - 0x7EC0 ) / ( 0x7F00 - 0x7EC0 ) ); | ||
525 | else if (temp2 > 0x7C00) | ||
526 | snrdb = 1000*12 + ( 1000*(18-12) * ( temp2 - 0x7C00 ) / ( 0x7EC0 - 0x7C00 ) ); | ||
527 | else | ||
528 | snrdb = 1000*0 + ( 1000*(12-0) * ( temp2 - 0 ) / ( 0x7C00 - 0 ) ); | ||
529 | |||
530 | /* the value reported back from the frontend will be FFFF=32db 0000=0db */ | ||
531 | |||
532 | *snr = snrdb * (0xFFFF/32000); | ||
533 | |||
534 | return 0; | ||
535 | } | ||
536 | |||
537 | static int nxt2002_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks) | ||
538 | { | ||
539 | struct nxt2002_state* state = (struct nxt2002_state*) fe->demodulator_priv; | ||
540 | u8 b[3]; | ||
541 | |||
542 | nxt2002_readreg_multibyte(state,0xE6,b,3); | ||
543 | *ucblocks = b[2]; | ||
544 | |||
545 | return 0; | ||
546 | } | ||
547 | |||
548 | static int nxt2002_sleep(struct dvb_frontend* fe) | ||
549 | { | ||
550 | return 0; | ||
551 | } | ||
552 | |||
553 | static int nxt2002_init(struct dvb_frontend* fe) | ||
554 | { | ||
555 | struct nxt2002_state* state = (struct nxt2002_state*) fe->demodulator_priv; | ||
556 | const struct firmware *fw; | ||
557 | int ret; | ||
558 | u8 buf[2]; | ||
559 | |||
560 | if (!state->initialised) { | ||
561 | /* request the firmware, this will block until someone uploads it */ | ||
562 | printk("nxt2002: Waiting for firmware upload (%s)...\n", NXT2002_DEFAULT_FIRMWARE); | ||
563 | ret = state->config->request_firmware(fe, &fw, NXT2002_DEFAULT_FIRMWARE); | ||
564 | printk("nxt2002: Waiting for firmware upload(2)...\n"); | ||
565 | if (ret) { | ||
566 | printk("nxt2002: no firmware upload (timeout or file not found?)\n"); | ||
567 | return ret; | ||
568 | } | ||
569 | |||
570 | ret = nxt2002_load_firmware(fe, fw); | ||
571 | if (ret) { | ||
572 | printk("nxt2002: writing firmware to device failed\n"); | ||
573 | release_firmware(fw); | ||
574 | return ret; | ||
575 | } | ||
576 | printk("nxt2002: firmware upload complete\n"); | ||
577 | |||
578 | /* Put the micro into reset */ | ||
579 | nxt2002_microcontroller_stop(state); | ||
580 | |||
581 | /* ensure transfer is complete */ | ||
582 | buf[0]=0; | ||
583 | i2c_writebytes(state,0x2B,buf,1); | ||
584 | |||
585 | /* Put the micro into reset for real this time */ | ||
586 | nxt2002_microcontroller_stop(state); | ||
587 | |||
588 | /* soft reset everything (agc,frontend,eq,fec)*/ | ||
589 | buf[0] = 0x0F; | ||
590 | i2c_writebytes(state,0x08,buf,1); | ||
591 | buf[0] = 0x00; | ||
592 | i2c_writebytes(state,0x08,buf,1); | ||
593 | |||
594 | /* write agc sdm configure */ | ||
595 | buf[0] = 0xF1; | ||
596 | i2c_writebytes(state,0x57,buf,1); | ||
597 | |||
598 | /* write mod output format */ | ||
599 | buf[0] = 0x20; | ||
600 | i2c_writebytes(state,0x09,buf,1); | ||
601 | |||
602 | /* write fec mpeg mode */ | ||
603 | buf[0] = 0x7E; | ||
604 | buf[1] = 0x00; | ||
605 | i2c_writebytes(state,0xE9,buf,2); | ||
606 | |||
607 | /* write mux selection */ | ||
608 | buf[0] = 0x00; | ||
609 | i2c_writebytes(state,0xCC,buf,1); | ||
610 | |||
611 | state->initialised = 1; | ||
612 | } | ||
613 | |||
614 | return 0; | ||
615 | } | ||
616 | |||
617 | static int nxt2002_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings* fesettings) | ||
618 | { | ||
619 | fesettings->min_delay_ms = 500; | ||
620 | fesettings->step_size = 0; | ||
621 | fesettings->max_drift = 0; | ||
622 | return 0; | ||
623 | } | ||
624 | |||
625 | static void nxt2002_release(struct dvb_frontend* fe) | ||
626 | { | ||
627 | struct nxt2002_state* state = (struct nxt2002_state*) fe->demodulator_priv; | ||
628 | kfree(state); | ||
629 | } | ||
630 | |||
631 | static struct dvb_frontend_ops nxt2002_ops; | ||
632 | |||
633 | struct dvb_frontend* nxt2002_attach(const struct nxt2002_config* config, | ||
634 | struct i2c_adapter* i2c) | ||
635 | { | ||
636 | struct nxt2002_state* state = NULL; | ||
637 | u8 buf [] = {0,0,0,0,0}; | ||
638 | |||
639 | /* allocate memory for the internal state */ | ||
640 | state = (struct nxt2002_state*) kmalloc(sizeof(struct nxt2002_state), GFP_KERNEL); | ||
641 | if (state == NULL) goto error; | ||
642 | |||
643 | /* setup the state */ | ||
644 | state->config = config; | ||
645 | state->i2c = i2c; | ||
646 | memcpy(&state->ops, &nxt2002_ops, sizeof(struct dvb_frontend_ops)); | ||
647 | state->initialised = 0; | ||
648 | |||
649 | /* Check the first 5 registers to ensure this a revision we can handle */ | ||
650 | |||
651 | i2c_readbytes(state, 0x00, buf, 5); | ||
652 | if (buf[0] != 0x04) goto error; /* device id */ | ||
653 | if (buf[1] != 0x02) goto error; /* fab id */ | ||
654 | if (buf[2] != 0x11) goto error; /* month */ | ||
655 | if (buf[3] != 0x20) goto error; /* year msb */ | ||
656 | if (buf[4] != 0x00) goto error; /* year lsb */ | ||
657 | |||
658 | /* create dvb_frontend */ | ||
659 | state->frontend.ops = &state->ops; | ||
660 | state->frontend.demodulator_priv = state; | ||
661 | return &state->frontend; | ||
662 | |||
663 | error: | ||
664 | kfree(state); | ||
665 | return NULL; | ||
666 | } | ||
667 | |||
668 | static struct dvb_frontend_ops nxt2002_ops = { | ||
669 | |||
670 | .info = { | ||
671 | .name = "Nextwave nxt2002 VSB/QAM frontend", | ||
672 | .type = FE_ATSC, | ||
673 | .frequency_min = 54000000, | ||
674 | .frequency_max = 860000000, | ||
675 | /* stepsize is just a guess */ | ||
676 | .frequency_stepsize = 166666, | ||
677 | .caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | | ||
678 | FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO | | ||
679 | FE_CAN_8VSB | FE_CAN_QAM_64 | FE_CAN_QAM_256 | ||
680 | }, | ||
681 | |||
682 | .release = nxt2002_release, | ||
683 | |||
684 | .init = nxt2002_init, | ||
685 | .sleep = nxt2002_sleep, | ||
686 | |||
687 | .set_frontend = nxt2002_setup_frontend_parameters, | ||
688 | .get_tune_settings = nxt2002_get_tune_settings, | ||
689 | |||
690 | .read_status = nxt2002_read_status, | ||
691 | .read_ber = nxt2002_read_ber, | ||
692 | .read_signal_strength = nxt2002_read_signal_strength, | ||
693 | .read_snr = nxt2002_read_snr, | ||
694 | .read_ucblocks = nxt2002_read_ucblocks, | ||
695 | |||
696 | }; | ||
697 | |||
698 | module_param(debug, int, 0644); | ||
699 | MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off)."); | ||
700 | |||
701 | MODULE_DESCRIPTION("NXT2002 ATSC (8VSB & ITU J83 AnnexB FEC QAM64/256) demodulator driver"); | ||
702 | MODULE_AUTHOR("Taylor Jacob"); | ||
703 | MODULE_LICENSE("GPL"); | ||
704 | |||
705 | EXPORT_SYMBOL(nxt2002_attach); | ||
diff --git a/drivers/media/dvb/frontends/nxt2002.h b/drivers/media/dvb/frontends/nxt2002.h new file mode 100644 index 000000000000..462301f577ee --- /dev/null +++ b/drivers/media/dvb/frontends/nxt2002.h | |||
@@ -0,0 +1,23 @@ | |||
1 | /* | ||
2 | Driver for the Nxt2002 demodulator | ||
3 | */ | ||
4 | |||
5 | #ifndef NXT2002_H | ||
6 | #define NXT2002_H | ||
7 | |||
8 | #include <linux/dvb/frontend.h> | ||
9 | #include <linux/firmware.h> | ||
10 | |||
11 | struct nxt2002_config | ||
12 | { | ||
13 | /* the demodulator's i2c address */ | ||
14 | u8 demod_address; | ||
15 | |||
16 | /* request firmware for device */ | ||
17 | int (*request_firmware)(struct dvb_frontend* fe, const struct firmware **fw, char* name); | ||
18 | }; | ||
19 | |||
20 | extern struct dvb_frontend* nxt2002_attach(const struct nxt2002_config* config, | ||
21 | struct i2c_adapter* i2c); | ||
22 | |||
23 | #endif // NXT2002_H | ||
diff --git a/drivers/media/dvb/frontends/nxt6000.c b/drivers/media/dvb/frontends/nxt6000.c new file mode 100644 index 000000000000..a41f7da8b842 --- /dev/null +++ b/drivers/media/dvb/frontends/nxt6000.c | |||
@@ -0,0 +1,554 @@ | |||
1 | /* | ||
2 | NxtWave Communications - NXT6000 demodulator driver | ||
3 | |||
4 | Copyright (C) 2002-2003 Florian Schirmer <jolt@tuxbox.org> | ||
5 | Copyright (C) 2003 Paul Andreassen <paul@andreassen.com.au> | ||
6 | |||
7 | This program is free software; you can redistribute it and/or modify | ||
8 | it under the terms of the GNU General Public License as published by | ||
9 | the Free Software Foundation; either version 2 of the License, or | ||
10 | (at your option) any later version. | ||
11 | |||
12 | This program is distributed in the hope that it will be useful, | ||
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | GNU General Public License for more details. | ||
16 | |||
17 | You should have received a copy of the GNU General Public License | ||
18 | along with this program; if not, write to the Free Software | ||
19 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
20 | */ | ||
21 | |||
22 | #include <linux/init.h> | ||
23 | #include <linux/kernel.h> | ||
24 | #include <linux/module.h> | ||
25 | #include <linux/string.h> | ||
26 | #include <linux/slab.h> | ||
27 | |||
28 | #include "dvb_frontend.h" | ||
29 | #include "nxt6000_priv.h" | ||
30 | #include "nxt6000.h" | ||
31 | |||
32 | |||
33 | |||
34 | struct nxt6000_state { | ||
35 | struct i2c_adapter* i2c; | ||
36 | struct dvb_frontend_ops ops; | ||
37 | /* configuration settings */ | ||
38 | const struct nxt6000_config* config; | ||
39 | struct dvb_frontend frontend; | ||
40 | }; | ||
41 | |||
42 | static int debug = 0; | ||
43 | #define dprintk if (debug) printk | ||
44 | |||
45 | static int nxt6000_writereg(struct nxt6000_state* state, u8 reg, u8 data) | ||
46 | { | ||
47 | u8 buf[] = { reg, data }; | ||
48 | struct i2c_msg msg = {.addr = state->config->demod_address,.flags = 0,.buf = buf,.len = 2 }; | ||
49 | int ret; | ||
50 | |||
51 | if ((ret = i2c_transfer(state->i2c, &msg, 1)) != 1) | ||
52 | dprintk("nxt6000: nxt6000_write error (reg: 0x%02X, data: 0x%02X, ret: %d)\n", reg, data, ret); | ||
53 | |||
54 | return (ret != 1) ? -EFAULT : 0; | ||
55 | } | ||
56 | |||
57 | static u8 nxt6000_readreg(struct nxt6000_state* state, u8 reg) | ||
58 | { | ||
59 | int ret; | ||
60 | u8 b0[] = { reg }; | ||
61 | u8 b1[] = { 0 }; | ||
62 | struct i2c_msg msgs[] = { | ||
63 | {.addr = state->config->demod_address,.flags = 0,.buf = b0,.len = 1}, | ||
64 | {.addr = state->config->demod_address,.flags = I2C_M_RD,.buf = b1,.len = 1} | ||
65 | }; | ||
66 | |||
67 | ret = i2c_transfer(state->i2c, msgs, 2); | ||
68 | |||
69 | if (ret != 2) | ||
70 | dprintk("nxt6000: nxt6000_read error (reg: 0x%02X, ret: %d)\n", reg, ret); | ||
71 | |||
72 | return b1[0]; | ||
73 | } | ||
74 | |||
75 | static void nxt6000_reset(struct nxt6000_state* state) | ||
76 | { | ||
77 | u8 val; | ||
78 | |||
79 | val = nxt6000_readreg(state, OFDM_COR_CTL); | ||
80 | |||
81 | nxt6000_writereg(state, OFDM_COR_CTL, val & ~COREACT); | ||
82 | nxt6000_writereg(state, OFDM_COR_CTL, val | COREACT); | ||
83 | } | ||
84 | |||
85 | static int nxt6000_set_bandwidth(struct nxt6000_state* state, fe_bandwidth_t bandwidth) | ||
86 | { | ||
87 | u16 nominal_rate; | ||
88 | int result; | ||
89 | |||
90 | switch (bandwidth) { | ||
91 | |||
92 | case BANDWIDTH_6_MHZ: | ||
93 | nominal_rate = 0x55B7; | ||
94 | break; | ||
95 | |||
96 | case BANDWIDTH_7_MHZ: | ||
97 | nominal_rate = 0x6400; | ||
98 | break; | ||
99 | |||
100 | case BANDWIDTH_8_MHZ: | ||
101 | nominal_rate = 0x7249; | ||
102 | break; | ||
103 | |||
104 | default: | ||
105 | return -EINVAL; | ||
106 | } | ||
107 | |||
108 | if ((result = nxt6000_writereg(state, OFDM_TRL_NOMINALRATE_1, nominal_rate & 0xFF)) < 0) | ||
109 | return result; | ||
110 | |||
111 | return nxt6000_writereg(state, OFDM_TRL_NOMINALRATE_2, (nominal_rate >> 8) & 0xFF); | ||
112 | } | ||
113 | |||
114 | static int nxt6000_set_guard_interval(struct nxt6000_state* state, fe_guard_interval_t guard_interval) | ||
115 | { | ||
116 | switch (guard_interval) { | ||
117 | |||
118 | case GUARD_INTERVAL_1_32: | ||
119 | return nxt6000_writereg(state, OFDM_COR_MODEGUARD, 0x00 | (nxt6000_readreg(state, OFDM_COR_MODEGUARD) & ~0x03)); | ||
120 | |||
121 | case GUARD_INTERVAL_1_16: | ||
122 | return nxt6000_writereg(state, OFDM_COR_MODEGUARD, 0x01 | (nxt6000_readreg(state, OFDM_COR_MODEGUARD) & ~0x03)); | ||
123 | |||
124 | case GUARD_INTERVAL_AUTO: | ||
125 | case GUARD_INTERVAL_1_8: | ||
126 | return nxt6000_writereg(state, OFDM_COR_MODEGUARD, 0x02 | (nxt6000_readreg(state, OFDM_COR_MODEGUARD) & ~0x03)); | ||
127 | |||
128 | case GUARD_INTERVAL_1_4: | ||
129 | return nxt6000_writereg(state, OFDM_COR_MODEGUARD, 0x03 | (nxt6000_readreg(state, OFDM_COR_MODEGUARD) & ~0x03)); | ||
130 | |||
131 | default: | ||
132 | return -EINVAL; | ||
133 | } | ||
134 | } | ||
135 | |||
136 | static int nxt6000_set_inversion(struct nxt6000_state* state, fe_spectral_inversion_t inversion) | ||
137 | { | ||
138 | switch (inversion) { | ||
139 | |||
140 | case INVERSION_OFF: | ||
141 | return nxt6000_writereg(state, OFDM_ITB_CTL, 0x00); | ||
142 | |||
143 | case INVERSION_ON: | ||
144 | return nxt6000_writereg(state, OFDM_ITB_CTL, ITBINV); | ||
145 | |||
146 | default: | ||
147 | return -EINVAL; | ||
148 | |||
149 | } | ||
150 | } | ||
151 | |||
152 | static int nxt6000_set_transmission_mode(struct nxt6000_state* state, fe_transmit_mode_t transmission_mode) | ||
153 | { | ||
154 | int result; | ||
155 | |||
156 | switch (transmission_mode) { | ||
157 | |||
158 | case TRANSMISSION_MODE_2K: | ||
159 | if ((result = nxt6000_writereg(state, EN_DMD_RACQ, 0x00 | (nxt6000_readreg(state, EN_DMD_RACQ) & ~0x03))) < 0) | ||
160 | return result; | ||
161 | |||
162 | return nxt6000_writereg(state, OFDM_COR_MODEGUARD, (0x00 << 2) | (nxt6000_readreg(state, OFDM_COR_MODEGUARD) & ~0x04)); | ||
163 | |||
164 | case TRANSMISSION_MODE_8K: | ||
165 | case TRANSMISSION_MODE_AUTO: | ||
166 | if ((result = nxt6000_writereg(state, EN_DMD_RACQ, 0x02 | (nxt6000_readreg(state, EN_DMD_RACQ) & ~0x03))) < 0) | ||
167 | return result; | ||
168 | |||
169 | return nxt6000_writereg(state, OFDM_COR_MODEGUARD, (0x01 << 2) | (nxt6000_readreg(state, OFDM_COR_MODEGUARD) & ~0x04)); | ||
170 | |||
171 | default: | ||
172 | return -EINVAL; | ||
173 | |||
174 | } | ||
175 | } | ||
176 | |||
177 | static void nxt6000_setup(struct dvb_frontend* fe) | ||
178 | { | ||
179 | struct nxt6000_state* state = (struct nxt6000_state*) fe->demodulator_priv; | ||
180 | |||
181 | nxt6000_writereg(state, RS_COR_SYNC_PARAM, SYNC_PARAM); | ||
182 | nxt6000_writereg(state, BER_CTRL, /*(1 << 2) | */ (0x01 << 1) | 0x01); | ||
183 | nxt6000_writereg(state, VIT_COR_CTL, VIT_COR_RESYNC); | ||
184 | nxt6000_writereg(state, OFDM_COR_CTL, (0x01 << 5) | (nxt6000_readreg(state, OFDM_COR_CTL) & 0x0F)); | ||
185 | nxt6000_writereg(state, OFDM_COR_MODEGUARD, FORCEMODE8K | 0x02); | ||
186 | nxt6000_writereg(state, OFDM_AGC_CTL, AGCLAST | INITIAL_AGC_BW); | ||
187 | nxt6000_writereg(state, OFDM_ITB_FREQ_1, 0x06); | ||
188 | nxt6000_writereg(state, OFDM_ITB_FREQ_2, 0x31); | ||
189 | nxt6000_writereg(state, OFDM_CAS_CTL, (0x01 << 7) | (0x02 << 3) | 0x04); | ||
190 | nxt6000_writereg(state, CAS_FREQ, 0xBB); /* CHECKME */ | ||
191 | nxt6000_writereg(state, OFDM_SYR_CTL, 1 << 2); | ||
192 | nxt6000_writereg(state, OFDM_PPM_CTL_1, PPM256); | ||
193 | nxt6000_writereg(state, OFDM_TRL_NOMINALRATE_1, 0x49); | ||
194 | nxt6000_writereg(state, OFDM_TRL_NOMINALRATE_2, 0x72); | ||
195 | nxt6000_writereg(state, ANALOG_CONTROL_0, 1 << 5); | ||
196 | nxt6000_writereg(state, EN_DMD_RACQ, (1 << 7) | (3 << 4) | 2); | ||
197 | nxt6000_writereg(state, DIAG_CONFIG, TB_SET); | ||
198 | |||
199 | if (state->config->clock_inversion) | ||
200 | nxt6000_writereg(state, SUB_DIAG_MODE_SEL, CLKINVERSION); | ||
201 | else | ||
202 | nxt6000_writereg(state, SUB_DIAG_MODE_SEL, 0); | ||
203 | |||
204 | nxt6000_writereg(state, TS_FORMAT, 0); | ||
205 | |||
206 | if (state->config->pll_init) { | ||
207 | nxt6000_writereg(state, ENABLE_TUNER_IIC, 0x01); /* open i2c bus switch */ | ||
208 | state->config->pll_init(fe); | ||
209 | nxt6000_writereg(state, ENABLE_TUNER_IIC, 0x00); /* close i2c bus switch */ | ||
210 | } | ||
211 | } | ||
212 | |||
213 | static void nxt6000_dump_status(struct nxt6000_state *state) | ||
214 | { | ||
215 | u8 val; | ||
216 | |||
217 | /* | ||
218 | printk("RS_COR_STAT: 0x%02X\n", nxt6000_readreg(fe, RS_COR_STAT)); | ||
219 | printk("VIT_SYNC_STATUS: 0x%02X\n", nxt6000_readreg(fe, VIT_SYNC_STATUS)); | ||
220 | printk("OFDM_COR_STAT: 0x%02X\n", nxt6000_readreg(fe, OFDM_COR_STAT)); | ||
221 | printk("OFDM_SYR_STAT: 0x%02X\n", nxt6000_readreg(fe, OFDM_SYR_STAT)); | ||
222 | printk("OFDM_TPS_RCVD_1: 0x%02X\n", nxt6000_readreg(fe, OFDM_TPS_RCVD_1)); | ||
223 | printk("OFDM_TPS_RCVD_2: 0x%02X\n", nxt6000_readreg(fe, OFDM_TPS_RCVD_2)); | ||
224 | printk("OFDM_TPS_RCVD_3: 0x%02X\n", nxt6000_readreg(fe, OFDM_TPS_RCVD_3)); | ||
225 | printk("OFDM_TPS_RCVD_4: 0x%02X\n", nxt6000_readreg(fe, OFDM_TPS_RCVD_4)); | ||
226 | printk("OFDM_TPS_RESERVED_1: 0x%02X\n", nxt6000_readreg(fe, OFDM_TPS_RESERVED_1)); | ||
227 | printk("OFDM_TPS_RESERVED_2: 0x%02X\n", nxt6000_readreg(fe, OFDM_TPS_RESERVED_2)); | ||
228 | */ | ||
229 | printk("NXT6000 status:"); | ||
230 | |||
231 | val = nxt6000_readreg(state, RS_COR_STAT); | ||
232 | |||
233 | printk(" DATA DESCR LOCK: %d,", val & 0x01); | ||
234 | printk(" DATA SYNC LOCK: %d,", (val >> 1) & 0x01); | ||
235 | |||
236 | val = nxt6000_readreg(state, VIT_SYNC_STATUS); | ||
237 | |||
238 | printk(" VITERBI LOCK: %d,", (val >> 7) & 0x01); | ||
239 | |||
240 | switch ((val >> 4) & 0x07) { | ||
241 | |||
242 | case 0x00: | ||
243 | printk(" VITERBI CODERATE: 1/2,"); | ||
244 | break; | ||
245 | |||
246 | case 0x01: | ||
247 | printk(" VITERBI CODERATE: 2/3,"); | ||
248 | break; | ||
249 | |||
250 | case 0x02: | ||
251 | printk(" VITERBI CODERATE: 3/4,"); | ||
252 | break; | ||
253 | |||
254 | case 0x03: | ||
255 | printk(" VITERBI CODERATE: 5/6,"); | ||
256 | break; | ||
257 | |||
258 | case 0x04: | ||
259 | printk(" VITERBI CODERATE: 7/8,"); | ||
260 | break; | ||
261 | |||
262 | default: | ||
263 | printk(" VITERBI CODERATE: Reserved,"); | ||
264 | |||
265 | } | ||
266 | |||
267 | val = nxt6000_readreg(state, OFDM_COR_STAT); | ||
268 | |||
269 | printk(" CHCTrack: %d,", (val >> 7) & 0x01); | ||
270 | printk(" TPSLock: %d,", (val >> 6) & 0x01); | ||
271 | printk(" SYRLock: %d,", (val >> 5) & 0x01); | ||
272 | printk(" AGCLock: %d,", (val >> 4) & 0x01); | ||
273 | |||
274 | switch (val & 0x0F) { | ||
275 | |||
276 | case 0x00: | ||
277 | printk(" CoreState: IDLE,"); | ||
278 | break; | ||
279 | |||
280 | case 0x02: | ||
281 | printk(" CoreState: WAIT_AGC,"); | ||
282 | break; | ||
283 | |||
284 | case 0x03: | ||
285 | printk(" CoreState: WAIT_SYR,"); | ||
286 | break; | ||
287 | |||
288 | case 0x04: | ||
289 | printk(" CoreState: WAIT_PPM,"); | ||
290 | break; | ||
291 | |||
292 | case 0x01: | ||
293 | printk(" CoreState: WAIT_TRL,"); | ||
294 | break; | ||
295 | |||
296 | case 0x05: | ||
297 | printk(" CoreState: WAIT_TPS,"); | ||
298 | break; | ||
299 | |||
300 | case 0x06: | ||
301 | printk(" CoreState: MONITOR_TPS,"); | ||
302 | break; | ||
303 | |||
304 | default: | ||
305 | printk(" CoreState: Reserved,"); | ||
306 | |||
307 | } | ||
308 | |||
309 | val = nxt6000_readreg(state, OFDM_SYR_STAT); | ||
310 | |||
311 | printk(" SYRLock: %d,", (val >> 4) & 0x01); | ||
312 | printk(" SYRMode: %s,", (val >> 2) & 0x01 ? "8K" : "2K"); | ||
313 | |||
314 | switch ((val >> 4) & 0x03) { | ||
315 | |||
316 | case 0x00: | ||
317 | printk(" SYRGuard: 1/32,"); | ||
318 | break; | ||
319 | |||
320 | case 0x01: | ||
321 | printk(" SYRGuard: 1/16,"); | ||
322 | break; | ||
323 | |||
324 | case 0x02: | ||
325 | printk(" SYRGuard: 1/8,"); | ||
326 | break; | ||
327 | |||
328 | case 0x03: | ||
329 | printk(" SYRGuard: 1/4,"); | ||
330 | break; | ||
331 | } | ||
332 | |||
333 | val = nxt6000_readreg(state, OFDM_TPS_RCVD_3); | ||
334 | |||
335 | switch ((val >> 4) & 0x07) { | ||
336 | |||
337 | case 0x00: | ||
338 | printk(" TPSLP: 1/2,"); | ||
339 | break; | ||
340 | |||
341 | case 0x01: | ||
342 | printk(" TPSLP: 2/3,"); | ||
343 | break; | ||
344 | |||
345 | case 0x02: | ||
346 | printk(" TPSLP: 3/4,"); | ||
347 | break; | ||
348 | |||
349 | case 0x03: | ||
350 | printk(" TPSLP: 5/6,"); | ||
351 | break; | ||
352 | |||
353 | case 0x04: | ||
354 | printk(" TPSLP: 7/8,"); | ||
355 | break; | ||
356 | |||
357 | default: | ||
358 | printk(" TPSLP: Reserved,"); | ||
359 | |||
360 | } | ||
361 | |||
362 | switch (val & 0x07) { | ||
363 | |||
364 | case 0x00: | ||
365 | printk(" TPSHP: 1/2,"); | ||
366 | break; | ||
367 | |||
368 | case 0x01: | ||
369 | printk(" TPSHP: 2/3,"); | ||
370 | break; | ||
371 | |||
372 | case 0x02: | ||
373 | printk(" TPSHP: 3/4,"); | ||
374 | break; | ||
375 | |||
376 | case 0x03: | ||
377 | printk(" TPSHP: 5/6,"); | ||
378 | break; | ||
379 | |||
380 | case 0x04: | ||
381 | printk(" TPSHP: 7/8,"); | ||
382 | break; | ||
383 | |||
384 | default: | ||
385 | printk(" TPSHP: Reserved,"); | ||
386 | |||
387 | } | ||
388 | |||
389 | val = nxt6000_readreg(state, OFDM_TPS_RCVD_4); | ||
390 | |||
391 | printk(" TPSMode: %s,", val & 0x01 ? "8K" : "2K"); | ||
392 | |||
393 | switch ((val >> 4) & 0x03) { | ||
394 | |||
395 | case 0x00: | ||
396 | printk(" TPSGuard: 1/32,"); | ||
397 | break; | ||
398 | |||
399 | case 0x01: | ||
400 | printk(" TPSGuard: 1/16,"); | ||
401 | break; | ||
402 | |||
403 | case 0x02: | ||
404 | printk(" TPSGuard: 1/8,"); | ||
405 | break; | ||
406 | |||
407 | case 0x03: | ||
408 | printk(" TPSGuard: 1/4,"); | ||
409 | break; | ||
410 | |||
411 | } | ||
412 | |||
413 | /* Strange magic required to gain access to RF_AGC_STATUS */ | ||
414 | nxt6000_readreg(state, RF_AGC_VAL_1); | ||
415 | val = nxt6000_readreg(state, RF_AGC_STATUS); | ||
416 | val = nxt6000_readreg(state, RF_AGC_STATUS); | ||
417 | |||
418 | printk(" RF AGC LOCK: %d,", (val >> 4) & 0x01); | ||
419 | printk("\n"); | ||
420 | } | ||
421 | |||
422 | static int nxt6000_read_status(struct dvb_frontend* fe, fe_status_t* status) | ||
423 | { | ||
424 | u8 core_status; | ||
425 | struct nxt6000_state* state = (struct nxt6000_state*) fe->demodulator_priv; | ||
426 | |||
427 | *status = 0; | ||
428 | |||
429 | core_status = nxt6000_readreg(state, OFDM_COR_STAT); | ||
430 | |||
431 | if (core_status & AGCLOCKED) | ||
432 | *status |= FE_HAS_SIGNAL; | ||
433 | |||
434 | if (nxt6000_readreg(state, OFDM_SYR_STAT) & GI14_SYR_LOCK) | ||
435 | *status |= FE_HAS_CARRIER; | ||
436 | |||
437 | if (nxt6000_readreg(state, VIT_SYNC_STATUS) & VITINSYNC) | ||
438 | *status |= FE_HAS_VITERBI; | ||
439 | |||
440 | if (nxt6000_readreg(state, RS_COR_STAT) & RSCORESTATUS) | ||
441 | *status |= FE_HAS_SYNC; | ||
442 | |||
443 | if ((core_status & TPSLOCKED) && (*status == (FE_HAS_SIGNAL | FE_HAS_CARRIER | FE_HAS_VITERBI | FE_HAS_SYNC))) | ||
444 | *status |= FE_HAS_LOCK; | ||
445 | |||
446 | if (debug) | ||
447 | nxt6000_dump_status(state); | ||
448 | |||
449 | return 0; | ||
450 | } | ||
451 | |||
452 | static int nxt6000_init(struct dvb_frontend* fe) | ||
453 | { | ||
454 | struct nxt6000_state* state = (struct nxt6000_state*) fe->demodulator_priv; | ||
455 | |||
456 | nxt6000_reset(state); | ||
457 | nxt6000_setup(fe); | ||
458 | |||
459 | return 0; | ||
460 | } | ||
461 | |||
462 | static int nxt6000_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *param) | ||
463 | { | ||
464 | struct nxt6000_state* state = (struct nxt6000_state*) fe->demodulator_priv; | ||
465 | int result; | ||
466 | |||
467 | nxt6000_writereg(state, ENABLE_TUNER_IIC, 0x01); /* open i2c bus switch */ | ||
468 | state->config->pll_set(fe, param); | ||
469 | nxt6000_writereg(state, ENABLE_TUNER_IIC, 0x00); /* close i2c bus switch */ | ||
470 | |||
471 | if ((result = nxt6000_set_bandwidth(state, param->u.ofdm.bandwidth)) < 0) | ||
472 | return result; | ||
473 | if ((result = nxt6000_set_guard_interval(state, param->u.ofdm.guard_interval)) < 0) | ||
474 | return result; | ||
475 | if ((result = nxt6000_set_transmission_mode(state, param->u.ofdm.transmission_mode)) < 0) | ||
476 | return result; | ||
477 | if ((result = nxt6000_set_inversion(state, param->inversion)) < 0) | ||
478 | return result; | ||
479 | |||
480 | return 0; | ||
481 | } | ||
482 | |||
483 | static void nxt6000_release(struct dvb_frontend* fe) | ||
484 | { | ||
485 | struct nxt6000_state* state = (struct nxt6000_state*) fe->demodulator_priv; | ||
486 | kfree(state); | ||
487 | } | ||
488 | |||
489 | static struct dvb_frontend_ops nxt6000_ops; | ||
490 | |||
491 | struct dvb_frontend* nxt6000_attach(const struct nxt6000_config* config, | ||
492 | struct i2c_adapter* i2c) | ||
493 | { | ||
494 | struct nxt6000_state* state = NULL; | ||
495 | |||
496 | /* allocate memory for the internal state */ | ||
497 | state = (struct nxt6000_state*) kmalloc(sizeof(struct nxt6000_state), GFP_KERNEL); | ||
498 | if (state == NULL) goto error; | ||
499 | |||
500 | /* setup the state */ | ||
501 | state->config = config; | ||
502 | state->i2c = i2c; | ||
503 | memcpy(&state->ops, &nxt6000_ops, sizeof(struct dvb_frontend_ops)); | ||
504 | |||
505 | /* check if the demod is there */ | ||
506 | if (nxt6000_readreg(state, OFDM_MSC_REV) != NXT6000ASICDEVICE) goto error; | ||
507 | |||
508 | /* create dvb_frontend */ | ||
509 | state->frontend.ops = &state->ops; | ||
510 | state->frontend.demodulator_priv = state; | ||
511 | return &state->frontend; | ||
512 | |||
513 | error: | ||
514 | kfree(state); | ||
515 | return NULL; | ||
516 | } | ||
517 | |||
518 | static struct dvb_frontend_ops nxt6000_ops = { | ||
519 | |||
520 | .info = { | ||
521 | .name = "NxtWave NXT6000 DVB-T", | ||
522 | .type = FE_OFDM, | ||
523 | .frequency_min = 0, | ||
524 | .frequency_max = 863250000, | ||
525 | .frequency_stepsize = 62500, | ||
526 | /*.frequency_tolerance = *//* FIXME: 12% of SR */ | ||
527 | .symbol_rate_min = 0, /* FIXME */ | ||
528 | .symbol_rate_max = 9360000, /* FIXME */ | ||
529 | .symbol_rate_tolerance = 4000, | ||
530 | .caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | | ||
531 | FE_CAN_FEC_4_5 | FE_CAN_FEC_5_6 | FE_CAN_FEC_6_7 | | ||
532 | FE_CAN_FEC_7_8 | FE_CAN_FEC_8_9 | FE_CAN_FEC_AUTO | | ||
533 | FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO | | ||
534 | FE_CAN_TRANSMISSION_MODE_AUTO | FE_CAN_GUARD_INTERVAL_AUTO | | ||
535 | FE_CAN_HIERARCHY_AUTO, | ||
536 | }, | ||
537 | |||
538 | .release = nxt6000_release, | ||
539 | |||
540 | .init = nxt6000_init, | ||
541 | |||
542 | .set_frontend = nxt6000_set_frontend, | ||
543 | |||
544 | .read_status = nxt6000_read_status, | ||
545 | }; | ||
546 | |||
547 | module_param(debug, int, 0644); | ||
548 | MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off)."); | ||
549 | |||
550 | MODULE_DESCRIPTION("NxtWave NXT6000 DVB-T demodulator driver"); | ||
551 | MODULE_AUTHOR("Florian Schirmer"); | ||
552 | MODULE_LICENSE("GPL"); | ||
553 | |||
554 | EXPORT_SYMBOL(nxt6000_attach); | ||
diff --git a/drivers/media/dvb/frontends/nxt6000.h b/drivers/media/dvb/frontends/nxt6000.h new file mode 100644 index 000000000000..b7d9bead3002 --- /dev/null +++ b/drivers/media/dvb/frontends/nxt6000.h | |||
@@ -0,0 +1,43 @@ | |||
1 | /* | ||
2 | NxtWave Communications - NXT6000 demodulator driver | ||
3 | |||
4 | Copyright (C) 2002-2003 Florian Schirmer <jolt@tuxbox.org> | ||
5 | Copyright (C) 2003 Paul Andreassen <paul@andreassen.com.au> | ||
6 | |||
7 | This program is free software; you can redistribute it and/or modify | ||
8 | it under the terms of the GNU General Public License as published by | ||
9 | the Free Software Foundation; either version 2 of the License, or | ||
10 | (at your option) any later version. | ||
11 | |||
12 | This program is distributed in the hope that it will be useful, | ||
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | GNU General Public License for more details. | ||
16 | |||
17 | You should have received a copy of the GNU General Public License | ||
18 | along with this program; if not, write to the Free Software | ||
19 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
20 | */ | ||
21 | |||
22 | #ifndef NXT6000_H | ||
23 | #define NXT6000_H | ||
24 | |||
25 | #include <linux/dvb/frontend.h> | ||
26 | |||
27 | struct nxt6000_config | ||
28 | { | ||
29 | /* the demodulator's i2c address */ | ||
30 | u8 demod_address; | ||
31 | |||
32 | /* should clock inversion be used? */ | ||
33 | u8 clock_inversion:1; | ||
34 | |||
35 | /* PLL maintenance */ | ||
36 | int (*pll_init)(struct dvb_frontend* fe); | ||
37 | int (*pll_set)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params); | ||
38 | }; | ||
39 | |||
40 | extern struct dvb_frontend* nxt6000_attach(const struct nxt6000_config* config, | ||
41 | struct i2c_adapter* i2c); | ||
42 | |||
43 | #endif // NXT6000_H | ||
diff --git a/drivers/media/dvb/frontends/nxt6000_priv.h b/drivers/media/dvb/frontends/nxt6000_priv.h new file mode 100644 index 000000000000..64b1a89b2a22 --- /dev/null +++ b/drivers/media/dvb/frontends/nxt6000_priv.h | |||
@@ -0,0 +1,265 @@ | |||
1 | /* | ||
2 | * Public Include File for DRV6000 users | ||
3 | * (ie. NxtWave Communications - NXT6000 demodulator driver) | ||
4 | * | ||
5 | * Copyright (C) 2001 NxtWave Communications, Inc. | ||
6 | * | ||
7 | */ | ||
8 | |||
9 | /* Nxt6000 Register Addresses and Bit Masks */ | ||
10 | |||
11 | /* Maximum Register Number */ | ||
12 | #define MAXNXT6000REG (0x9A) | ||
13 | |||
14 | /* 0x1B A_VIT_BER_0 aka 0x3A */ | ||
15 | #define A_VIT_BER_0 (0x1B) | ||
16 | |||
17 | /* 0x1D A_VIT_BER_TIMER_0 aka 0x38 */ | ||
18 | #define A_VIT_BER_TIMER_0 (0x1D) | ||
19 | |||
20 | /* 0x21 RS_COR_STAT */ | ||
21 | #define RS_COR_STAT (0x21) | ||
22 | #define RSCORESTATUS (0x03) | ||
23 | |||
24 | /* 0x22 RS_COR_INTEN */ | ||
25 | #define RS_COR_INTEN (0x22) | ||
26 | |||
27 | /* 0x23 RS_COR_INSTAT */ | ||
28 | #define RS_COR_INSTAT (0x23) | ||
29 | #define INSTAT_ERROR (0x04) | ||
30 | #define LOCK_LOSS_BITS (0x03) | ||
31 | |||
32 | /* 0x24 RS_COR_SYNC_PARAM */ | ||
33 | #define RS_COR_SYNC_PARAM (0x24) | ||
34 | #define SYNC_PARAM (0x03) | ||
35 | |||
36 | /* 0x25 BER_CTRL */ | ||
37 | #define BER_CTRL (0x25) | ||
38 | #define BER_ENABLE (0x02) | ||
39 | #define BER_RESET (0x01) | ||
40 | |||
41 | /* 0x26 BER_PAY */ | ||
42 | #define BER_PAY (0x26) | ||
43 | |||
44 | /* 0x27 BER_PKT_L */ | ||
45 | #define BER_PKT_L (0x27) | ||
46 | #define BER_PKTOVERFLOW (0x80) | ||
47 | |||
48 | /* 0x30 VIT_COR_CTL */ | ||
49 | #define VIT_COR_CTL (0x30) | ||
50 | #define BER_CONTROL (0x02) | ||
51 | #define VIT_COR_MASK (0x82) | ||
52 | #define VIT_COR_RESYNC (0x80) | ||
53 | |||
54 | |||
55 | /* 0x32 VIT_SYNC_STATUS */ | ||
56 | #define VIT_SYNC_STATUS (0x32) | ||
57 | #define VITINSYNC (0x80) | ||
58 | |||
59 | /* 0x33 VIT_COR_INTEN */ | ||
60 | #define VIT_COR_INTEN (0x33) | ||
61 | #define GLOBAL_ENABLE (0x80) | ||
62 | |||
63 | /* 0x34 VIT_COR_INTSTAT */ | ||
64 | #define VIT_COR_INTSTAT (0x34) | ||
65 | #define BER_DONE (0x08) | ||
66 | #define BER_OVERFLOW (0x10) | ||
67 | |||
68 | /* 0x38 OFDM_BERTimer *//* Use the alias registers */ | ||
69 | #define A_VIT_BER_TIMER_0 (0x1D) | ||
70 | |||
71 | /* 0x3A VIT_BER_TIMER_0 *//* Use the alias registers */ | ||
72 | #define A_VIT_BER_0 (0x1B) | ||
73 | |||
74 | /* 0x40 OFDM_COR_CTL */ | ||
75 | #define OFDM_COR_CTL (0x40) | ||
76 | #define COREACT (0x20) | ||
77 | #define HOLDSM (0x10) | ||
78 | #define WAIT_AGC (0x02) | ||
79 | #define WAIT_SYR (0x03) | ||
80 | |||
81 | /* 0x41 OFDM_COR_STAT */ | ||
82 | #define OFDM_COR_STAT (0x41) | ||
83 | #define COR_STATUS (0x0F) | ||
84 | #define MONITOR_TPS (0x06) | ||
85 | #define TPSLOCKED (0x40) | ||
86 | #define AGCLOCKED (0x10) | ||
87 | |||
88 | /* 0x42 OFDM_COR_INTEN */ | ||
89 | #define OFDM_COR_INTEN (0x42) | ||
90 | #define TPSRCVBAD (0x04) | ||
91 | #define TPSRCVCHANGED (0x02) | ||
92 | #define TPSRCVUPDATE (0x01) | ||
93 | |||
94 | /* 0x43 OFDM_COR_INSTAT */ | ||
95 | #define OFDM_COR_INSTAT (0x43) | ||
96 | |||
97 | /* 0x44 OFDM_COR_MODEGUARD */ | ||
98 | #define OFDM_COR_MODEGUARD (0x44) | ||
99 | #define FORCEMODE (0x08) | ||
100 | #define FORCEMODE8K (0x04) | ||
101 | |||
102 | /* 0x45 OFDM_AGC_CTL */ | ||
103 | #define OFDM_AGC_CTL (0x45) | ||
104 | #define INITIAL_AGC_BW (0x08) | ||
105 | #define AGCNEG (0x02) | ||
106 | #define AGCLAST (0x10) | ||
107 | |||
108 | /* 0x48 OFDM_AGC_TARGET */ | ||
109 | #define OFDM_AGC_TARGET (0x48) | ||
110 | #define OFDM_AGC_TARGET_DEFAULT (0x28) | ||
111 | #define OFDM_AGC_TARGET_IMPULSE (0x38) | ||
112 | |||
113 | /* 0x49 OFDM_AGC_GAIN_1 */ | ||
114 | #define OFDM_AGC_GAIN_1 (0x49) | ||
115 | |||
116 | /* 0x4B OFDM_ITB_CTL */ | ||
117 | #define OFDM_ITB_CTL (0x4B) | ||
118 | #define ITBINV (0x01) | ||
119 | |||
120 | /* 0x4C OFDM_ITB_FREQ_1 */ | ||
121 | #define OFDM_ITB_FREQ_1 (0x4C) | ||
122 | |||
123 | /* 0x4D OFDM_ITB_FREQ_2 */ | ||
124 | #define OFDM_ITB_FREQ_2 (0x4D) | ||
125 | |||
126 | /* 0x4E OFDM_CAS_CTL */ | ||
127 | #define OFDM_CAS_CTL (0x4E) | ||
128 | #define ACSDIS (0x40) | ||
129 | #define CCSEN (0x80) | ||
130 | |||
131 | /* 0x4F CAS_FREQ */ | ||
132 | #define CAS_FREQ (0x4F) | ||
133 | |||
134 | /* 0x51 OFDM_SYR_CTL */ | ||
135 | #define OFDM_SYR_CTL (0x51) | ||
136 | #define SIXTH_ENABLE (0x80) | ||
137 | #define SYR_TRACKING_DISABLE (0x01) | ||
138 | |||
139 | /* 0x52 OFDM_SYR_STAT */ | ||
140 | #define OFDM_SYR_STAT (0x52) | ||
141 | #define GI14_2K_SYR_LOCK (0x13) | ||
142 | #define GI14_8K_SYR_LOCK (0x17) | ||
143 | #define GI14_SYR_LOCK (0x10) | ||
144 | |||
145 | /* 0x55 OFDM_SYR_OFFSET_1 */ | ||
146 | #define OFDM_SYR_OFFSET_1 (0x55) | ||
147 | |||
148 | /* 0x56 OFDM_SYR_OFFSET_2 */ | ||
149 | #define OFDM_SYR_OFFSET_2 (0x56) | ||
150 | |||
151 | /* 0x58 OFDM_SCR_CTL */ | ||
152 | #define OFDM_SCR_CTL (0x58) | ||
153 | #define SYR_ADJ_DECAY_MASK (0x70) | ||
154 | #define SYR_ADJ_DECAY (0x30) | ||
155 | |||
156 | /* 0x59 OFDM_PPM_CTL_1 */ | ||
157 | #define OFDM_PPM_CTL_1 (0x59) | ||
158 | #define PPMMAX_MASK (0x30) | ||
159 | #define PPM256 (0x30) | ||
160 | |||
161 | /* 0x5B OFDM_TRL_NOMINALRATE_1 */ | ||
162 | #define OFDM_TRL_NOMINALRATE_1 (0x5B) | ||
163 | |||
164 | /* 0x5C OFDM_TRL_NOMINALRATE_2 */ | ||
165 | #define OFDM_TRL_NOMINALRATE_2 (0x5C) | ||
166 | |||
167 | /* 0x5D OFDM_TRL_TIME_1 */ | ||
168 | #define OFDM_TRL_TIME_1 (0x5D) | ||
169 | |||
170 | /* 0x60 OFDM_CRL_FREQ_1 */ | ||
171 | #define OFDM_CRL_FREQ_1 (0x60) | ||
172 | |||
173 | /* 0x63 OFDM_CHC_CTL_1 */ | ||
174 | #define OFDM_CHC_CTL_1 (0x63) | ||
175 | #define MANMEAN1 (0xF0); | ||
176 | #define CHCFIR (0x01) | ||
177 | |||
178 | /* 0x64 OFDM_CHC_SNR */ | ||
179 | #define OFDM_CHC_SNR (0x64) | ||
180 | |||
181 | /* 0x65 OFDM_BDI_CTL */ | ||
182 | #define OFDM_BDI_CTL (0x65) | ||
183 | #define LP_SELECT (0x02) | ||
184 | |||
185 | /* 0x67 OFDM_TPS_RCVD_1 */ | ||
186 | #define OFDM_TPS_RCVD_1 (0x67) | ||
187 | #define TPSFRAME (0x03) | ||
188 | |||
189 | /* 0x68 OFDM_TPS_RCVD_2 */ | ||
190 | #define OFDM_TPS_RCVD_2 (0x68) | ||
191 | |||
192 | /* 0x69 OFDM_TPS_RCVD_3 */ | ||
193 | #define OFDM_TPS_RCVD_3 (0x69) | ||
194 | |||
195 | /* 0x6A OFDM_TPS_RCVD_4 */ | ||
196 | #define OFDM_TPS_RCVD_4 (0x6A) | ||
197 | |||
198 | /* 0x6B OFDM_TPS_RESERVED_1 */ | ||
199 | #define OFDM_TPS_RESERVED_1 (0x6B) | ||
200 | |||
201 | /* 0x6C OFDM_TPS_RESERVED_2 */ | ||
202 | #define OFDM_TPS_RESERVED_2 (0x6C) | ||
203 | |||
204 | /* 0x73 OFDM_MSC_REV */ | ||
205 | #define OFDM_MSC_REV (0x73) | ||
206 | |||
207 | /* 0x76 OFDM_SNR_CARRIER_2 */ | ||
208 | #define OFDM_SNR_CARRIER_2 (0x76) | ||
209 | #define MEAN_MASK (0x80) | ||
210 | #define MEANBIT (0x80) | ||
211 | |||
212 | /* 0x80 ANALOG_CONTROL_0 */ | ||
213 | #define ANALOG_CONTROL_0 (0x80) | ||
214 | #define POWER_DOWN_ADC (0x40) | ||
215 | |||
216 | /* 0x81 ENABLE_TUNER_IIC */ | ||
217 | #define ENABLE_TUNER_IIC (0x81) | ||
218 | #define ENABLE_TUNER_BIT (0x01) | ||
219 | |||
220 | /* 0x82 EN_DMD_RACQ */ | ||
221 | #define EN_DMD_RACQ (0x82) | ||
222 | #define EN_DMD_RACQ_REG_VAL (0x81) | ||
223 | #define EN_DMD_RACQ_REG_VAL_14 (0x01) | ||
224 | |||
225 | /* 0x84 SNR_COMMAND */ | ||
226 | #define SNR_COMMAND (0x84) | ||
227 | #define SNRStat (0x80) | ||
228 | |||
229 | /* 0x85 SNRCARRIERNUMBER_LSB */ | ||
230 | #define SNRCARRIERNUMBER_LSB (0x85) | ||
231 | |||
232 | /* 0x87 SNRMINTHRESHOLD_LSB */ | ||
233 | #define SNRMINTHRESHOLD_LSB (0x87) | ||
234 | |||
235 | /* 0x89 SNR_PER_CARRIER_LSB */ | ||
236 | #define SNR_PER_CARRIER_LSB (0x89) | ||
237 | |||
238 | /* 0x8B SNRBELOWTHRESHOLD_LSB */ | ||
239 | #define SNRBELOWTHRESHOLD_LSB (0x8B) | ||
240 | |||
241 | /* 0x91 RF_AGC_VAL_1 */ | ||
242 | #define RF_AGC_VAL_1 (0x91) | ||
243 | |||
244 | /* 0x92 RF_AGC_STATUS */ | ||
245 | #define RF_AGC_STATUS (0x92) | ||
246 | |||
247 | /* 0x98 DIAG_CONFIG */ | ||
248 | #define DIAG_CONFIG (0x98) | ||
249 | #define DIAG_MASK (0x70) | ||
250 | #define TB_SET (0x10) | ||
251 | #define TRAN_SELECT (0x07) | ||
252 | #define SERIAL_SELECT (0x01) | ||
253 | |||
254 | /* 0x99 SUB_DIAG_MODE_SEL */ | ||
255 | #define SUB_DIAG_MODE_SEL (0x99) | ||
256 | #define CLKINVERSION (0x01) | ||
257 | |||
258 | /* 0x9A TS_FORMAT */ | ||
259 | #define TS_FORMAT (0x9A) | ||
260 | #define ERROR_SENSE (0x08) | ||
261 | #define VALID_SENSE (0x04) | ||
262 | #define SYNC_SENSE (0x02) | ||
263 | #define GATED_CLOCK (0x01) | ||
264 | |||
265 | #define NXT6000ASICDEVICE (0x0b) | ||
diff --git a/drivers/media/dvb/frontends/or51132.c b/drivers/media/dvb/frontends/or51132.c new file mode 100644 index 000000000000..df5dee7760a3 --- /dev/null +++ b/drivers/media/dvb/frontends/or51132.c | |||
@@ -0,0 +1,628 @@ | |||
1 | /* | ||
2 | * Support for OR51132 (pcHDTV HD-3000) - VSB/QAM | ||
3 | * | ||
4 | * Copyright (C) 2005 Kirk Lapray <kirk_lapray@bigfoot.com> | ||
5 | * | ||
6 | * Based on code from Jack Kelliher (kelliher@xmission.com) | ||
7 | * Copyright (C) 2002 & pcHDTV, inc. | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or modify | ||
10 | * it under the terms of the GNU General Public License as published by | ||
11 | * the Free Software Foundation; either version 2 of the License, or | ||
12 | * (at your option) any later version. | ||
13 | * | ||
14 | * This program is distributed in the hope that it will be useful, | ||
15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
17 | * GNU General Public License for more details. | ||
18 | * | ||
19 | * You should have received a copy of the GNU General Public License | ||
20 | * along with this program; if not, write to the Free Software | ||
21 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
22 | * | ||
23 | */ | ||
24 | |||
25 | /* | ||
26 | * This driver needs two external firmware files. Please copy | ||
27 | * "dvb-fe-or51132-vsb.fw" and "dvb-fe-or51132-qam.fw" to | ||
28 | * /usr/lib/hotplug/firmware/ or /lib/firmware/ | ||
29 | * (depending on configuration of firmware hotplug). | ||
30 | */ | ||
31 | #define OR51132_VSB_FIRMWARE "dvb-fe-or51132-vsb.fw" | ||
32 | #define OR51132_QAM_FIRMWARE "dvb-fe-or51132-qam.fw" | ||
33 | |||
34 | #include <linux/kernel.h> | ||
35 | #include <linux/module.h> | ||
36 | #include <linux/moduleparam.h> | ||
37 | #include <linux/init.h> | ||
38 | #include <linux/delay.h> | ||
39 | #include <asm/byteorder.h> | ||
40 | |||
41 | #include "dvb_frontend.h" | ||
42 | #include "dvb-pll.h" | ||
43 | #include "or51132.h" | ||
44 | |||
45 | static int debug; | ||
46 | #define dprintk(args...) \ | ||
47 | do { \ | ||
48 | if (debug) printk(KERN_DEBUG "or51132: " args); \ | ||
49 | } while (0) | ||
50 | |||
51 | |||
52 | struct or51132_state | ||
53 | { | ||
54 | struct i2c_adapter* i2c; | ||
55 | struct dvb_frontend_ops ops; | ||
56 | |||
57 | /* Configuration settings */ | ||
58 | const struct or51132_config* config; | ||
59 | |||
60 | struct dvb_frontend frontend; | ||
61 | |||
62 | /* Demodulator private data */ | ||
63 | fe_modulation_t current_modulation; | ||
64 | |||
65 | /* Tuner private data */ | ||
66 | u32 current_frequency; | ||
67 | }; | ||
68 | |||
69 | static int i2c_writebytes (struct or51132_state* state, u8 reg, u8 *buf, int len) | ||
70 | { | ||
71 | int err; | ||
72 | struct i2c_msg msg; | ||
73 | msg.addr = reg; | ||
74 | msg.flags = 0; | ||
75 | msg.len = len; | ||
76 | msg.buf = buf; | ||
77 | |||
78 | if ((err = i2c_transfer(state->i2c, &msg, 1)) != 1) { | ||
79 | printk(KERN_WARNING "or51132: i2c_writebytes error (addr %02x, err == %i)\n", reg, err); | ||
80 | return -EREMOTEIO; | ||
81 | } | ||
82 | |||
83 | return 0; | ||
84 | } | ||
85 | |||
86 | static u8 i2c_readbytes (struct or51132_state* state, u8 reg, u8* buf, int len) | ||
87 | { | ||
88 | int err; | ||
89 | struct i2c_msg msg; | ||
90 | msg.addr = reg; | ||
91 | msg.flags = I2C_M_RD; | ||
92 | msg.len = len; | ||
93 | msg.buf = buf; | ||
94 | |||
95 | if ((err = i2c_transfer(state->i2c, &msg, 1)) != 1) { | ||
96 | printk(KERN_WARNING "or51132: i2c_readbytes error (addr %02x, err == %i)\n", reg, err); | ||
97 | return -EREMOTEIO; | ||
98 | } | ||
99 | |||
100 | return 0; | ||
101 | } | ||
102 | |||
103 | static int or51132_load_firmware (struct dvb_frontend* fe, const struct firmware *fw) | ||
104 | { | ||
105 | struct or51132_state* state = (struct or51132_state*) fe->demodulator_priv; | ||
106 | static u8 run_buf[] = {0x7F,0x01}; | ||
107 | static u8 get_ver_buf[] = {0x04,0x00,0x30,0x00,0x00}; | ||
108 | u8 rec_buf[14]; | ||
109 | u8 cmd_buf[14]; | ||
110 | u32 firmwareAsize, firmwareBsize; | ||
111 | int i,ret; | ||
112 | |||
113 | dprintk("Firmware is %Zd bytes\n",fw->size); | ||
114 | |||
115 | /* Get size of firmware A and B */ | ||
116 | firmwareAsize = le32_to_cpu(*((u32*)fw->data)); | ||
117 | dprintk("FirmwareA is %i bytes\n",firmwareAsize); | ||
118 | firmwareBsize = le32_to_cpu(*((u32*)(fw->data+4))); | ||
119 | dprintk("FirmwareB is %i bytes\n",firmwareBsize); | ||
120 | |||
121 | /* Upload firmware */ | ||
122 | if ((ret = i2c_writebytes(state,state->config->demod_address, | ||
123 | &fw->data[8],firmwareAsize))) { | ||
124 | printk(KERN_WARNING "or51132: load_firmware error 1\n"); | ||
125 | return ret; | ||
126 | } | ||
127 | msleep(1); /* 1ms */ | ||
128 | if ((ret = i2c_writebytes(state,state->config->demod_address, | ||
129 | &fw->data[8+firmwareAsize],firmwareBsize))) { | ||
130 | printk(KERN_WARNING "or51132: load_firmware error 2\n"); | ||
131 | return ret; | ||
132 | } | ||
133 | msleep(1); /* 1ms */ | ||
134 | |||
135 | if ((ret = i2c_writebytes(state,state->config->demod_address, | ||
136 | run_buf,2))) { | ||
137 | printk(KERN_WARNING "or51132: load_firmware error 3\n"); | ||
138 | return ret; | ||
139 | } | ||
140 | |||
141 | /* Wait at least 5 msec */ | ||
142 | msleep(20); /* 10ms */ | ||
143 | |||
144 | if ((ret = i2c_writebytes(state,state->config->demod_address, | ||
145 | run_buf,2))) { | ||
146 | printk(KERN_WARNING "or51132: load_firmware error 4\n"); | ||
147 | return ret; | ||
148 | } | ||
149 | |||
150 | /* 50ms for operation to begin */ | ||
151 | msleep(50); | ||
152 | |||
153 | /* Read back ucode version to besure we loaded correctly and are really up and running */ | ||
154 | /* Get uCode version */ | ||
155 | cmd_buf[0] = 0x10; | ||
156 | cmd_buf[1] = 0x10; | ||
157 | cmd_buf[2] = 0x00; | ||
158 | cmd_buf[3] = 0x00; | ||
159 | msleep(20); /* 20ms */ | ||
160 | if ((ret = i2c_writebytes(state,state->config->demod_address, | ||
161 | cmd_buf,3))) { | ||
162 | printk(KERN_WARNING "or51132: load_firmware error a\n"); | ||
163 | return ret; | ||
164 | } | ||
165 | |||
166 | cmd_buf[0] = 0x04; | ||
167 | cmd_buf[1] = 0x17; | ||
168 | cmd_buf[2] = 0x00; | ||
169 | cmd_buf[3] = 0x00; | ||
170 | msleep(20); /* 20ms */ | ||
171 | if ((ret = i2c_writebytes(state,state->config->demod_address, | ||
172 | cmd_buf,2))) { | ||
173 | printk(KERN_WARNING "or51132: load_firmware error b\n"); | ||
174 | return ret; | ||
175 | } | ||
176 | |||
177 | cmd_buf[0] = 0x00; | ||
178 | cmd_buf[1] = 0x00; | ||
179 | cmd_buf[2] = 0x00; | ||
180 | cmd_buf[3] = 0x00; | ||
181 | msleep(20); /* 20ms */ | ||
182 | if ((ret = i2c_writebytes(state,state->config->demod_address, | ||
183 | cmd_buf,2))) { | ||
184 | printk(KERN_WARNING "or51132: load_firmware error c\n"); | ||
185 | return ret; | ||
186 | } | ||
187 | |||
188 | for(i=0;i<4;i++) { | ||
189 | msleep(20); /* 20ms */ | ||
190 | get_ver_buf[4] = i+1; | ||
191 | if ((ret = i2c_readbytes(state,state->config->demod_address, | ||
192 | &rec_buf[i*2],2))) { | ||
193 | printk(KERN_WARNING | ||
194 | "or51132: load_firmware error d - %d\n",i); | ||
195 | return ret; | ||
196 | } | ||
197 | } | ||
198 | |||
199 | printk(KERN_WARNING | ||
200 | "or51132: Version: %02X%02X%02X%02X-%02X%02X%02X%02X (%02X%01X-%01X-%02X%01X-%01X)\n", | ||
201 | rec_buf[1],rec_buf[0],rec_buf[3],rec_buf[2], | ||
202 | rec_buf[5],rec_buf[4],rec_buf[7],rec_buf[6], | ||
203 | rec_buf[3],rec_buf[2]>>4,rec_buf[2]&0x0f, | ||
204 | rec_buf[5],rec_buf[4]>>4,rec_buf[4]&0x0f); | ||
205 | |||
206 | cmd_buf[0] = 0x10; | ||
207 | cmd_buf[1] = 0x00; | ||
208 | cmd_buf[2] = 0x00; | ||
209 | cmd_buf[3] = 0x00; | ||
210 | msleep(20); /* 20ms */ | ||
211 | if ((ret = i2c_writebytes(state,state->config->demod_address, | ||
212 | cmd_buf,3))) { | ||
213 | printk(KERN_WARNING "or51132: load_firmware error e\n"); | ||
214 | return ret; | ||
215 | } | ||
216 | return 0; | ||
217 | }; | ||
218 | |||
219 | static int or51132_init(struct dvb_frontend* fe) | ||
220 | { | ||
221 | return 0; | ||
222 | } | ||
223 | |||
224 | static int or51132_read_ber(struct dvb_frontend* fe, u32* ber) | ||
225 | { | ||
226 | *ber = 0; | ||
227 | return 0; | ||
228 | } | ||
229 | |||
230 | static int or51132_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks) | ||
231 | { | ||
232 | *ucblocks = 0; | ||
233 | return 0; | ||
234 | } | ||
235 | |||
236 | static int or51132_sleep(struct dvb_frontend* fe) | ||
237 | { | ||
238 | return 0; | ||
239 | } | ||
240 | |||
241 | static int or51132_setmode(struct dvb_frontend* fe) | ||
242 | { | ||
243 | struct or51132_state* state = (struct or51132_state*) fe->demodulator_priv; | ||
244 | unsigned char cmd_buf[4]; | ||
245 | |||
246 | dprintk("setmode %d\n",(int)state->current_modulation); | ||
247 | /* set operation mode in Receiver 1 register; */ | ||
248 | cmd_buf[0] = 0x04; | ||
249 | cmd_buf[1] = 0x01; | ||
250 | switch (state->current_modulation) { | ||
251 | case QAM_256: | ||
252 | case QAM_64: | ||
253 | case QAM_AUTO: | ||
254 | /* Auto-deinterleave; MPEG ser, MPEG2tr, phase noise-high*/ | ||
255 | cmd_buf[2] = 0x5F; | ||
256 | break; | ||
257 | case VSB_8: | ||
258 | /* Auto CH, Auto NTSC rej, MPEGser, MPEG2tr, phase noise-high*/ | ||
259 | cmd_buf[2] = 0x50; | ||
260 | break; | ||
261 | default: | ||
262 | printk("setmode:Modulation set to unsupported value\n"); | ||
263 | }; | ||
264 | cmd_buf[3] = 0x00; | ||
265 | if (i2c_writebytes(state,state->config->demod_address, | ||
266 | cmd_buf,3)) { | ||
267 | printk(KERN_WARNING "or51132: set_mode error 1\n"); | ||
268 | return -1; | ||
269 | } | ||
270 | dprintk("or51132: set #1 to %02x\n", cmd_buf[2]); | ||
271 | |||
272 | /* Set operation mode in Receiver 6 register */ | ||
273 | cmd_buf[0] = 0x1C; | ||
274 | switch (state->current_modulation) { | ||
275 | case QAM_AUTO: | ||
276 | /* REC MODE Normal Carrier Lock */ | ||
277 | cmd_buf[1] = 0x00; | ||
278 | /* Channel MODE Auto QAM64/256 */ | ||
279 | cmd_buf[2] = 0x4f; | ||
280 | break; | ||
281 | case QAM_256: | ||
282 | /* REC MODE Normal Carrier Lock */ | ||
283 | cmd_buf[1] = 0x00; | ||
284 | /* Channel MODE QAM256 */ | ||
285 | cmd_buf[2] = 0x45; | ||
286 | break; | ||
287 | case QAM_64: | ||
288 | /* REC MODE Normal Carrier Lock */ | ||
289 | cmd_buf[1] = 0x00; | ||
290 | /* Channel MODE QAM64 */ | ||
291 | cmd_buf[2] = 0x43; | ||
292 | break; | ||
293 | case VSB_8: | ||
294 | /* REC MODE inv IF spectrum, Normal */ | ||
295 | cmd_buf[1] = 0x03; | ||
296 | /* Channel MODE ATSC/VSB8 */ | ||
297 | cmd_buf[2] = 0x06; | ||
298 | break; | ||
299 | default: | ||
300 | printk("setmode: Modulation set to unsupported value\n"); | ||
301 | }; | ||
302 | cmd_buf[3] = 0x00; | ||
303 | msleep(20); /* 20ms */ | ||
304 | if (i2c_writebytes(state,state->config->demod_address, | ||
305 | cmd_buf,3)) { | ||
306 | printk(KERN_WARNING "or51132: set_mode error 2\n"); | ||
307 | return -1; | ||
308 | } | ||
309 | dprintk("or51132: set #6 to 0x%02x%02x\n", cmd_buf[1], cmd_buf[2]); | ||
310 | |||
311 | return 0; | ||
312 | } | ||
313 | |||
314 | static int or51132_set_parameters(struct dvb_frontend* fe, | ||
315 | struct dvb_frontend_parameters *param) | ||
316 | { | ||
317 | int ret; | ||
318 | u8 buf[4]; | ||
319 | struct or51132_state* state = (struct or51132_state*) fe->demodulator_priv; | ||
320 | const struct firmware *fw; | ||
321 | |||
322 | /* Change only if we are actually changing the modulation */ | ||
323 | if (state->current_modulation != param->u.vsb.modulation) { | ||
324 | switch(param->u.vsb.modulation) { | ||
325 | case VSB_8: | ||
326 | dprintk("set_parameters VSB MODE\n"); | ||
327 | printk("or51132: Waiting for firmware upload(%s)...\n", | ||
328 | OR51132_VSB_FIRMWARE); | ||
329 | ret = request_firmware(&fw, OR51132_VSB_FIRMWARE, | ||
330 | &state->i2c->dev); | ||
331 | if (ret){ | ||
332 | printk(KERN_WARNING "or51132: No firmware up" | ||
333 | "loaded(timeout or file not found?)\n"); | ||
334 | return ret; | ||
335 | } | ||
336 | /* Set non-punctured clock for VSB */ | ||
337 | state->config->set_ts_params(fe, 0); | ||
338 | break; | ||
339 | case QAM_AUTO: | ||
340 | case QAM_64: | ||
341 | case QAM_256: | ||
342 | dprintk("set_parameters QAM MODE\n"); | ||
343 | printk("or51132: Waiting for firmware upload(%s)...\n", | ||
344 | OR51132_QAM_FIRMWARE); | ||
345 | ret = request_firmware(&fw, OR51132_QAM_FIRMWARE, | ||
346 | &state->i2c->dev); | ||
347 | if (ret){ | ||
348 | printk(KERN_WARNING "or51132: No firmware up" | ||
349 | "loaded(timeout or file not found?)\n"); | ||
350 | return ret; | ||
351 | } | ||
352 | /* Set punctured clock for QAM */ | ||
353 | state->config->set_ts_params(fe, 1); | ||
354 | break; | ||
355 | default: | ||
356 | printk("or51132:Modulation type(%d) UNSUPPORTED\n", | ||
357 | param->u.vsb.modulation); | ||
358 | return -1; | ||
359 | }; | ||
360 | ret = or51132_load_firmware(fe, fw); | ||
361 | release_firmware(fw); | ||
362 | if (ret) { | ||
363 | printk(KERN_WARNING "or51132: Writing firmware to " | ||
364 | "device failed!\n"); | ||
365 | return ret; | ||
366 | } | ||
367 | printk("or51132: Firmware upload complete.\n"); | ||
368 | |||
369 | state->current_modulation = param->u.vsb.modulation; | ||
370 | or51132_setmode(fe); | ||
371 | } | ||
372 | |||
373 | /* Change only if we are actually changing the channel */ | ||
374 | if (state->current_frequency != param->frequency) { | ||
375 | dvb_pll_configure(state->config->pll_desc, buf, | ||
376 | param->frequency, 0); | ||
377 | dprintk("set_parameters tuner bytes: 0x%02x 0x%02x " | ||
378 | "0x%02x 0x%02x\n",buf[0],buf[1],buf[2],buf[3]); | ||
379 | if (i2c_writebytes(state, state->config->pll_address ,buf, 4)) | ||
380 | printk(KERN_WARNING "or51132: set_parameters error " | ||
381 | "writing to tuner\n"); | ||
382 | |||
383 | /* Set to current mode */ | ||
384 | or51132_setmode(fe); | ||
385 | |||
386 | /* Update current frequency */ | ||
387 | state->current_frequency = param->frequency; | ||
388 | } | ||
389 | return 0; | ||
390 | } | ||
391 | |||
392 | static int or51132_read_status(struct dvb_frontend* fe, fe_status_t* status) | ||
393 | { | ||
394 | struct or51132_state* state = (struct or51132_state*) fe->demodulator_priv; | ||
395 | unsigned char rec_buf[2]; | ||
396 | unsigned char snd_buf[2]; | ||
397 | *status = 0; | ||
398 | |||
399 | /* Receiver Status */ | ||
400 | snd_buf[0]=0x04; | ||
401 | snd_buf[1]=0x00; | ||
402 | msleep(30); /* 30ms */ | ||
403 | if (i2c_writebytes(state,state->config->demod_address,snd_buf,2)) { | ||
404 | printk(KERN_WARNING "or51132: read_status write error\n"); | ||
405 | return -1; | ||
406 | } | ||
407 | msleep(30); /* 30ms */ | ||
408 | if (i2c_readbytes(state,state->config->demod_address,rec_buf,2)) { | ||
409 | printk(KERN_WARNING "or51132: read_status read error\n"); | ||
410 | return -1; | ||
411 | } | ||
412 | dprintk("read_status %x %x\n",rec_buf[0],rec_buf[1]); | ||
413 | |||
414 | if (rec_buf[1] & 0x01) { /* Receiver Lock */ | ||
415 | *status |= FE_HAS_SIGNAL; | ||
416 | *status |= FE_HAS_CARRIER; | ||
417 | *status |= FE_HAS_VITERBI; | ||
418 | *status |= FE_HAS_SYNC; | ||
419 | *status |= FE_HAS_LOCK; | ||
420 | } | ||
421 | return 0; | ||
422 | } | ||
423 | |||
424 | /* log10-1 table at .5 increments from 1 to 100.5 */ | ||
425 | static unsigned int i100x20log10[] = { | ||
426 | 0, 352, 602, 795, 954, 1088, 1204, 1306, 1397, 1480, | ||
427 | 1556, 1625, 1690, 1750, 1806, 1858, 1908, 1955, 2000, 2042, | ||
428 | 2082, 2121, 2158, 2193, 2227, 2260, 2292, 2322, 2352, 2380, | ||
429 | 2408, 2434, 2460, 2486, 2510, 2534, 2557, 2580, 2602, 2623, | ||
430 | 2644, 2664, 2684, 2704, 2723, 2742, 2760, 2778, 2795, 2813, | ||
431 | 2829, 2846, 2862, 2878, 2894, 2909, 2924, 2939, 2954, 2968, | ||
432 | 2982, 2996, 3010, 3023, 3037, 3050, 3062, 3075, 3088, 3100, | ||
433 | 3112, 3124, 3136, 3148, 3159, 3170, 3182, 3193, 3204, 3214, | ||
434 | 3225, 3236, 3246, 3256, 3266, 3276, 3286, 3296, 3306, 3316, | ||
435 | 3325, 3334, 3344, 3353, 3362, 3371, 3380, 3389, 3397, 3406, | ||
436 | 3415, 3423, 3432, 3440, 3448, 3456, 3464, 3472, 3480, 3488, | ||
437 | 3496, 3504, 3511, 3519, 3526, 3534, 3541, 3549, 3556, 3563, | ||
438 | 3570, 3577, 3584, 3591, 3598, 3605, 3612, 3619, 3625, 3632, | ||
439 | 3639, 3645, 3652, 3658, 3665, 3671, 3677, 3683, 3690, 3696, | ||
440 | 3702, 3708, 3714, 3720, 3726, 3732, 3738, 3744, 3750, 3755, | ||
441 | 3761, 3767, 3772, 3778, 3784, 3789, 3795, 3800, 3806, 3811, | ||
442 | 3816, 3822, 3827, 3832, 3838, 3843, 3848, 3853, 3858, 3863, | ||
443 | 3868, 3874, 3879, 3884, 3888, 3893, 3898, 3903, 3908, 3913, | ||
444 | 3918, 3922, 3927, 3932, 3936, 3941, 3946, 3950, 3955, 3960, | ||
445 | 3964, 3969, 3973, 3978, 3982, 3986, 3991, 3995, 4000, 4004, | ||
446 | }; | ||
447 | |||
448 | static unsigned int denom[] = {1,1,100,1000,10000,100000,1000000,10000000,100000000}; | ||
449 | |||
450 | static unsigned int i20Log10(unsigned short val) | ||
451 | { | ||
452 | unsigned int rntval = 100; | ||
453 | unsigned int tmp = val; | ||
454 | unsigned int exp = 1; | ||
455 | |||
456 | while(tmp > 100) {tmp /= 100; exp++;} | ||
457 | |||
458 | val = (2 * val)/denom[exp]; | ||
459 | if (exp > 1) rntval = 2000*exp; | ||
460 | |||
461 | rntval += i100x20log10[val]; | ||
462 | return rntval; | ||
463 | } | ||
464 | |||
465 | static int or51132_read_signal_strength(struct dvb_frontend* fe, u16* strength) | ||
466 | { | ||
467 | struct or51132_state* state = (struct or51132_state*) fe->demodulator_priv; | ||
468 | unsigned char rec_buf[2]; | ||
469 | unsigned char snd_buf[2]; | ||
470 | u8 rcvr_stat; | ||
471 | u16 snr_equ; | ||
472 | int usK; | ||
473 | |||
474 | snd_buf[0]=0x04; | ||
475 | snd_buf[1]=0x02; /* SNR after Equalizer */ | ||
476 | msleep(30); /* 30ms */ | ||
477 | if (i2c_writebytes(state,state->config->demod_address,snd_buf,2)) { | ||
478 | printk(KERN_WARNING "or51132: read_status write error\n"); | ||
479 | return -1; | ||
480 | } | ||
481 | msleep(30); /* 30ms */ | ||
482 | if (i2c_readbytes(state,state->config->demod_address,rec_buf,2)) { | ||
483 | printk(KERN_WARNING "or51132: read_status read error\n"); | ||
484 | return -1; | ||
485 | } | ||
486 | snr_equ = rec_buf[0] | (rec_buf[1] << 8); | ||
487 | dprintk("read_signal_strength snr_equ %x %x (%i)\n",rec_buf[0],rec_buf[1],snr_equ); | ||
488 | |||
489 | /* Receiver Status */ | ||
490 | snd_buf[0]=0x04; | ||
491 | snd_buf[1]=0x00; | ||
492 | msleep(30); /* 30ms */ | ||
493 | if (i2c_writebytes(state,state->config->demod_address,snd_buf,2)) { | ||
494 | printk(KERN_WARNING "or51132: read_signal_strength read_status write error\n"); | ||
495 | return -1; | ||
496 | } | ||
497 | msleep(30); /* 30ms */ | ||
498 | if (i2c_readbytes(state,state->config->demod_address,rec_buf,2)) { | ||
499 | printk(KERN_WARNING "or51132: read_signal_strength read_status read error\n"); | ||
500 | return -1; | ||
501 | } | ||
502 | dprintk("read_signal_strength read_status %x %x\n",rec_buf[0],rec_buf[1]); | ||
503 | rcvr_stat = rec_buf[1]; | ||
504 | usK = (rcvr_stat & 0x10) ? 3 : 0; | ||
505 | |||
506 | /* The value reported back from the frontend will be FFFF=100% 0000=0% */ | ||
507 | *strength = (((8952 - i20Log10(snr_equ) - usK*100)/3+5)*65535)/1000; | ||
508 | dprintk("read_signal_strength %i\n",*strength); | ||
509 | |||
510 | return 0; | ||
511 | } | ||
512 | |||
513 | static int or51132_read_snr(struct dvb_frontend* fe, u16* snr) | ||
514 | { | ||
515 | struct or51132_state* state = (struct or51132_state*) fe->demodulator_priv; | ||
516 | unsigned char rec_buf[2]; | ||
517 | unsigned char snd_buf[2]; | ||
518 | u16 snr_equ; | ||
519 | |||
520 | snd_buf[0]=0x04; | ||
521 | snd_buf[1]=0x02; /* SNR after Equalizer */ | ||
522 | msleep(30); /* 30ms */ | ||
523 | if (i2c_writebytes(state,state->config->demod_address,snd_buf,2)) { | ||
524 | printk(KERN_WARNING "or51132: read_snr write error\n"); | ||
525 | return -1; | ||
526 | } | ||
527 | msleep(30); /* 30ms */ | ||
528 | if (i2c_readbytes(state,state->config->demod_address,rec_buf,2)) { | ||
529 | printk(KERN_WARNING "or51132: read_snr dvr read error\n"); | ||
530 | return -1; | ||
531 | } | ||
532 | snr_equ = rec_buf[0] | (rec_buf[1] << 8); | ||
533 | dprintk("read_snr snr_equ %x %x (%i)\n",rec_buf[0],rec_buf[1],snr_equ); | ||
534 | |||
535 | *snr = 0xFFFF - snr_equ; | ||
536 | dprintk("read_snr %i\n",*snr); | ||
537 | |||
538 | return 0; | ||
539 | } | ||
540 | |||
541 | static int or51132_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings* fe_tune_settings) | ||
542 | { | ||
543 | fe_tune_settings->min_delay_ms = 500; | ||
544 | fe_tune_settings->step_size = 0; | ||
545 | fe_tune_settings->max_drift = 0; | ||
546 | |||
547 | return 0; | ||
548 | } | ||
549 | |||
550 | static void or51132_release(struct dvb_frontend* fe) | ||
551 | { | ||
552 | struct or51132_state* state = (struct or51132_state*) fe->demodulator_priv; | ||
553 | kfree(state); | ||
554 | } | ||
555 | |||
556 | static struct dvb_frontend_ops or51132_ops; | ||
557 | |||
558 | struct dvb_frontend* or51132_attach(const struct or51132_config* config, | ||
559 | struct i2c_adapter* i2c) | ||
560 | { | ||
561 | struct or51132_state* state = NULL; | ||
562 | |||
563 | /* Allocate memory for the internal state */ | ||
564 | state = kmalloc(sizeof(struct or51132_state), GFP_KERNEL); | ||
565 | if (state == NULL) | ||
566 | goto error; | ||
567 | |||
568 | /* Setup the state */ | ||
569 | state->config = config; | ||
570 | state->i2c = i2c; | ||
571 | memcpy(&state->ops, &or51132_ops, sizeof(struct dvb_frontend_ops)); | ||
572 | state->current_frequency = -1; | ||
573 | state->current_modulation = -1; | ||
574 | |||
575 | /* Create dvb_frontend */ | ||
576 | state->frontend.ops = &state->ops; | ||
577 | state->frontend.demodulator_priv = state; | ||
578 | return &state->frontend; | ||
579 | |||
580 | error: | ||
581 | if (state) | ||
582 | kfree(state); | ||
583 | return NULL; | ||
584 | } | ||
585 | |||
586 | static struct dvb_frontend_ops or51132_ops = { | ||
587 | |||
588 | .info = { | ||
589 | .name = "Oren OR51132 VSB/QAM Frontend", | ||
590 | .type = FE_ATSC, | ||
591 | .frequency_min = 44000000, | ||
592 | .frequency_max = 958000000, | ||
593 | .frequency_stepsize = 166666, | ||
594 | .caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | | ||
595 | FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO | | ||
596 | FE_CAN_QAM_64 | FE_CAN_QAM_256 | FE_CAN_QAM_AUTO | | ||
597 | FE_CAN_8VSB | ||
598 | }, | ||
599 | |||
600 | .release = or51132_release, | ||
601 | |||
602 | .init = or51132_init, | ||
603 | .sleep = or51132_sleep, | ||
604 | |||
605 | .set_frontend = or51132_set_parameters, | ||
606 | .get_tune_settings = or51132_get_tune_settings, | ||
607 | |||
608 | .read_status = or51132_read_status, | ||
609 | .read_ber = or51132_read_ber, | ||
610 | .read_signal_strength = or51132_read_signal_strength, | ||
611 | .read_snr = or51132_read_snr, | ||
612 | .read_ucblocks = or51132_read_ucblocks, | ||
613 | }; | ||
614 | |||
615 | module_param(debug, int, 0644); | ||
616 | MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off)."); | ||
617 | |||
618 | MODULE_DESCRIPTION("OR51132 ATSC [pcHDTV HD-3000] (8VSB & ITU J83 AnnexB FEC QAM64/256) Demodulator Driver"); | ||
619 | MODULE_AUTHOR("Kirk Lapray"); | ||
620 | MODULE_LICENSE("GPL"); | ||
621 | |||
622 | EXPORT_SYMBOL(or51132_attach); | ||
623 | |||
624 | /* | ||
625 | * Local variables: | ||
626 | * c-basic-offset: 8 | ||
627 | * End: | ||
628 | */ | ||
diff --git a/drivers/media/dvb/frontends/or51132.h b/drivers/media/dvb/frontends/or51132.h new file mode 100644 index 000000000000..622cdd18381b --- /dev/null +++ b/drivers/media/dvb/frontends/or51132.h | |||
@@ -0,0 +1,48 @@ | |||
1 | /* | ||
2 | * Support for OR51132 (pcHDTV HD-3000) - VSB/QAM | ||
3 | * | ||
4 | * Copyright (C) 2005 Kirk Lapray <kirk_lapray@bigfoot.com> | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License as published by | ||
8 | * the Free Software Foundation; either version 2 of the License, or | ||
9 | * (at your option) any later version. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU General Public License for more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License | ||
17 | * along with this program; if not, write to the Free Software | ||
18 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
19 | * | ||
20 | */ | ||
21 | |||
22 | #ifndef OR51132_H | ||
23 | #define OR51132_H | ||
24 | |||
25 | #include <linux/firmware.h> | ||
26 | #include <linux/dvb/frontend.h> | ||
27 | |||
28 | struct or51132_config | ||
29 | { | ||
30 | /* The demodulator's i2c address */ | ||
31 | u8 demod_address; | ||
32 | u8 pll_address; | ||
33 | struct dvb_pll_desc *pll_desc; | ||
34 | |||
35 | /* Need to set device param for start_dma */ | ||
36 | int (*set_ts_params)(struct dvb_frontend* fe, int is_punctured); | ||
37 | }; | ||
38 | |||
39 | extern struct dvb_frontend* or51132_attach(const struct or51132_config* config, | ||
40 | struct i2c_adapter* i2c); | ||
41 | |||
42 | #endif // OR51132_H | ||
43 | |||
44 | /* | ||
45 | * Local variables: | ||
46 | * c-basic-offset: 8 | ||
47 | * End: | ||
48 | */ | ||
diff --git a/drivers/media/dvb/frontends/or51211.c b/drivers/media/dvb/frontends/or51211.c new file mode 100644 index 000000000000..ad56a9958404 --- /dev/null +++ b/drivers/media/dvb/frontends/or51211.c | |||
@@ -0,0 +1,631 @@ | |||
1 | /* | ||
2 | * Support for OR51211 (pcHDTV HD-2000) - VSB | ||
3 | * | ||
4 | * Copyright (C) 2005 Kirk Lapray <kirk_lapray@bigfoot.com> | ||
5 | * | ||
6 | * Based on code from Jack Kelliher (kelliher@xmission.com) | ||
7 | * Copyright (C) 2002 & pcHDTV, inc. | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or modify | ||
10 | * it under the terms of the GNU General Public License as published by | ||
11 | * the Free Software Foundation; either version 2 of the License, or | ||
12 | * (at your option) any later version. | ||
13 | * | ||
14 | * This program is distributed in the hope that it will be useful, | ||
15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
17 | * GNU General Public License for more details. | ||
18 | * | ||
19 | * You should have received a copy of the GNU General Public License | ||
20 | * along with this program; if not, write to the Free Software | ||
21 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
22 | * | ||
23 | */ | ||
24 | |||
25 | /* | ||
26 | * This driver needs external firmware. Please use the command | ||
27 | * "<kerneldir>/Documentation/dvb/get_dvb_firmware or51211" to | ||
28 | * download/extract it, and then copy it to /usr/lib/hotplug/firmware. | ||
29 | */ | ||
30 | #define OR51211_DEFAULT_FIRMWARE "dvb-fe-or51211.fw" | ||
31 | |||
32 | #include <linux/kernel.h> | ||
33 | #include <linux/module.h> | ||
34 | #include <linux/moduleparam.h> | ||
35 | #include <linux/device.h> | ||
36 | #include <linux/firmware.h> | ||
37 | #include <asm/byteorder.h> | ||
38 | |||
39 | #include "dvb_frontend.h" | ||
40 | #include "or51211.h" | ||
41 | |||
42 | static int debug; | ||
43 | #define dprintk(args...) \ | ||
44 | do { \ | ||
45 | if (debug) printk(KERN_DEBUG "or51211: " args); \ | ||
46 | } while (0) | ||
47 | |||
48 | static u8 run_buf[] = {0x7f,0x01}; | ||
49 | static u8 cmd_buf[] = {0x04,0x01,0x50,0x80,0x06}; // ATSC | ||
50 | |||
51 | struct or51211_state { | ||
52 | |||
53 | struct i2c_adapter* i2c; | ||
54 | struct dvb_frontend_ops ops; | ||
55 | |||
56 | /* Configuration settings */ | ||
57 | const struct or51211_config* config; | ||
58 | |||
59 | struct dvb_frontend frontend; | ||
60 | struct bt878* bt; | ||
61 | |||
62 | /* Demodulator private data */ | ||
63 | u8 initialized:1; | ||
64 | |||
65 | /* Tuner private data */ | ||
66 | u32 current_frequency; | ||
67 | }; | ||
68 | |||
69 | static int i2c_writebytes (struct or51211_state* state, u8 reg, u8 *buf, | ||
70 | int len) | ||
71 | { | ||
72 | int err; | ||
73 | struct i2c_msg msg; | ||
74 | msg.addr = reg; | ||
75 | msg.flags = 0; | ||
76 | msg.len = len; | ||
77 | msg.buf = buf; | ||
78 | |||
79 | if ((err = i2c_transfer (state->i2c, &msg, 1)) != 1) { | ||
80 | printk(KERN_WARNING "or51211: i2c_writebytes error " | ||
81 | "(addr %02x, err == %i)\n", reg, err); | ||
82 | return -EREMOTEIO; | ||
83 | } | ||
84 | |||
85 | return 0; | ||
86 | } | ||
87 | |||
88 | static u8 i2c_readbytes (struct or51211_state* state, u8 reg, u8* buf, int len) | ||
89 | { | ||
90 | int err; | ||
91 | struct i2c_msg msg; | ||
92 | msg.addr = reg; | ||
93 | msg.flags = I2C_M_RD; | ||
94 | msg.len = len; | ||
95 | msg.buf = buf; | ||
96 | |||
97 | if ((err = i2c_transfer (state->i2c, &msg, 1)) != 1) { | ||
98 | printk(KERN_WARNING "or51211: i2c_readbytes error " | ||
99 | "(addr %02x, err == %i)\n", reg, err); | ||
100 | return -EREMOTEIO; | ||
101 | } | ||
102 | |||
103 | return 0; | ||
104 | } | ||
105 | |||
106 | static int or51211_load_firmware (struct dvb_frontend* fe, | ||
107 | const struct firmware *fw) | ||
108 | { | ||
109 | struct or51211_state* state = fe->demodulator_priv; | ||
110 | u8 tudata[585]; | ||
111 | int i; | ||
112 | |||
113 | dprintk("Firmware is %d bytes\n",fw->size); | ||
114 | |||
115 | /* Get eprom data */ | ||
116 | tudata[0] = 17; | ||
117 | if (i2c_writebytes(state,0x50,tudata,1)) { | ||
118 | printk(KERN_WARNING "or51211:load_firmware error eprom addr\n"); | ||
119 | return -1; | ||
120 | } | ||
121 | if (i2c_readbytes(state,0x50,&tudata[145],192)) { | ||
122 | printk(KERN_WARNING "or51211: load_firmware error eprom\n"); | ||
123 | return -1; | ||
124 | } | ||
125 | |||
126 | /* Create firmware buffer */ | ||
127 | for (i = 0; i < 145; i++) | ||
128 | tudata[i] = fw->data[i]; | ||
129 | |||
130 | for (i = 0; i < 248; i++) | ||
131 | tudata[i+337] = fw->data[145+i]; | ||
132 | |||
133 | state->config->reset(fe); | ||
134 | |||
135 | if (i2c_writebytes(state,state->config->demod_address,tudata,585)) { | ||
136 | printk(KERN_WARNING "or51211: load_firmware error 1\n"); | ||
137 | return -1; | ||
138 | } | ||
139 | msleep(1); | ||
140 | |||
141 | if (i2c_writebytes(state,state->config->demod_address, | ||
142 | &fw->data[393],8125)) { | ||
143 | printk(KERN_WARNING "or51211: load_firmware error 2\n"); | ||
144 | return -1; | ||
145 | } | ||
146 | msleep(1); | ||
147 | |||
148 | if (i2c_writebytes(state,state->config->demod_address,run_buf,2)) { | ||
149 | printk(KERN_WARNING "or51211: load_firmware error 3\n"); | ||
150 | return -1; | ||
151 | } | ||
152 | |||
153 | /* Wait at least 5 msec */ | ||
154 | msleep(10); | ||
155 | if (i2c_writebytes(state,state->config->demod_address,run_buf,2)) { | ||
156 | printk(KERN_WARNING "or51211: load_firmware error 4\n"); | ||
157 | return -1; | ||
158 | } | ||
159 | msleep(10); | ||
160 | |||
161 | printk("or51211: Done.\n"); | ||
162 | return 0; | ||
163 | }; | ||
164 | |||
165 | static int or51211_setmode(struct dvb_frontend* fe, int mode) | ||
166 | { | ||
167 | struct or51211_state* state = fe->demodulator_priv; | ||
168 | u8 rec_buf[14]; | ||
169 | |||
170 | state->config->setmode(fe, mode); | ||
171 | |||
172 | if (i2c_writebytes(state,state->config->demod_address,run_buf,2)) { | ||
173 | printk(KERN_WARNING "or51211: setmode error 1\n"); | ||
174 | return -1; | ||
175 | } | ||
176 | |||
177 | /* Wait at least 5 msec */ | ||
178 | msleep(10); | ||
179 | if (i2c_writebytes(state,state->config->demod_address,run_buf,2)) { | ||
180 | printk(KERN_WARNING "or51211: setmode error 2\n"); | ||
181 | return -1; | ||
182 | } | ||
183 | |||
184 | msleep(10); | ||
185 | |||
186 | /* Set operation mode in Receiver 1 register; | ||
187 | * type 1: | ||
188 | * data 0x50h Automatic sets receiver channel conditions | ||
189 | * Automatic NTSC rejection filter | ||
190 | * Enable MPEG serial data output | ||
191 | * MPEG2tr | ||
192 | * High tuner phase noise | ||
193 | * normal +/-150kHz Carrier acquisition range | ||
194 | */ | ||
195 | if (i2c_writebytes(state,state->config->demod_address,cmd_buf,3)) { | ||
196 | printk(KERN_WARNING "or51211: setmode error 3\n"); | ||
197 | return -1; | ||
198 | } | ||
199 | |||
200 | rec_buf[0] = 0x04; | ||
201 | rec_buf[1] = 0x00; | ||
202 | rec_buf[2] = 0x03; | ||
203 | rec_buf[3] = 0x00; | ||
204 | msleep(20); | ||
205 | if (i2c_writebytes(state,state->config->demod_address,rec_buf,3)) { | ||
206 | printk(KERN_WARNING "or51211: setmode error 5\n"); | ||
207 | } | ||
208 | msleep(3); | ||
209 | if (i2c_readbytes(state,state->config->demod_address,&rec_buf[10],2)) { | ||
210 | printk(KERN_WARNING "or51211: setmode error 6"); | ||
211 | return -1; | ||
212 | } | ||
213 | dprintk("setmode rec status %02x %02x\n",rec_buf[10],rec_buf[11]); | ||
214 | |||
215 | return 0; | ||
216 | } | ||
217 | |||
218 | static int or51211_set_parameters(struct dvb_frontend* fe, | ||
219 | struct dvb_frontend_parameters *param) | ||
220 | { | ||
221 | struct or51211_state* state = fe->demodulator_priv; | ||
222 | u32 freq = 0; | ||
223 | u16 tunerfreq = 0; | ||
224 | u8 buf[4]; | ||
225 | |||
226 | /* Change only if we are actually changing the channel */ | ||
227 | if (state->current_frequency != param->frequency) { | ||
228 | freq = 44000 + (param->frequency/1000); | ||
229 | tunerfreq = freq * 16/1000; | ||
230 | |||
231 | dprintk("set_parameters frequency = %d (tunerfreq = %d)\n", | ||
232 | param->frequency,tunerfreq); | ||
233 | |||
234 | buf[0] = (tunerfreq >> 8) & 0x7F; | ||
235 | buf[1] = (tunerfreq & 0xFF); | ||
236 | buf[2] = 0x8E; | ||
237 | |||
238 | if (param->frequency < 157250000) { | ||
239 | buf[3] = 0xA0; | ||
240 | dprintk("set_parameters VHF low range\n"); | ||
241 | } else if (param->frequency < 454000000) { | ||
242 | buf[3] = 0x90; | ||
243 | dprintk("set_parameters VHF high range\n"); | ||
244 | } else { | ||
245 | buf[3] = 0x30; | ||
246 | dprintk("set_parameters UHF range\n"); | ||
247 | } | ||
248 | dprintk("set_parameters tuner bytes: 0x%02x 0x%02x " | ||
249 | "0x%02x 0x%02x\n",buf[0],buf[1],buf[2],buf[3]); | ||
250 | |||
251 | if (i2c_writebytes(state,0xC2>>1,buf,4)) | ||
252 | printk(KERN_WARNING "or51211:set_parameters error " | ||
253 | "writing to tuner\n"); | ||
254 | |||
255 | /* Set to ATSC mode */ | ||
256 | or51211_setmode(fe,0); | ||
257 | |||
258 | /* Update current frequency */ | ||
259 | state->current_frequency = param->frequency; | ||
260 | } | ||
261 | return 0; | ||
262 | } | ||
263 | |||
264 | static int or51211_read_status(struct dvb_frontend* fe, fe_status_t* status) | ||
265 | { | ||
266 | struct or51211_state* state = fe->demodulator_priv; | ||
267 | unsigned char rec_buf[2]; | ||
268 | unsigned char snd_buf[] = {0x04,0x00,0x03,0x00}; | ||
269 | *status = 0; | ||
270 | |||
271 | /* Receiver Status */ | ||
272 | if (i2c_writebytes(state,state->config->demod_address,snd_buf,3)) { | ||
273 | printk(KERN_WARNING "or51132: read_status write error\n"); | ||
274 | return -1; | ||
275 | } | ||
276 | msleep(3); | ||
277 | if (i2c_readbytes(state,state->config->demod_address,rec_buf,2)) { | ||
278 | printk(KERN_WARNING "or51132: read_status read error\n"); | ||
279 | return -1; | ||
280 | } | ||
281 | dprintk("read_status %x %x\n",rec_buf[0],rec_buf[1]); | ||
282 | |||
283 | if (rec_buf[0] & 0x01) { /* Receiver Lock */ | ||
284 | *status |= FE_HAS_SIGNAL; | ||
285 | *status |= FE_HAS_CARRIER; | ||
286 | *status |= FE_HAS_VITERBI; | ||
287 | *status |= FE_HAS_SYNC; | ||
288 | *status |= FE_HAS_LOCK; | ||
289 | } | ||
290 | return 0; | ||
291 | } | ||
292 | |||
293 | /* log10-1 table at .5 increments from 1 to 100.5 */ | ||
294 | static unsigned int i100x20log10[] = { | ||
295 | 0, 352, 602, 795, 954, 1088, 1204, 1306, 1397, 1480, | ||
296 | 1556, 1625, 1690, 1750, 1806, 1858, 1908, 1955, 2000, 2042, | ||
297 | 2082, 2121, 2158, 2193, 2227, 2260, 2292, 2322, 2352, 2380, | ||
298 | 2408, 2434, 2460, 2486, 2510, 2534, 2557, 2580, 2602, 2623, | ||
299 | 2644, 2664, 2684, 2704, 2723, 2742, 2760, 2778, 2795, 2813, | ||
300 | 2829, 2846, 2862, 2878, 2894, 2909, 2924, 2939, 2954, 2968, | ||
301 | 2982, 2996, 3010, 3023, 3037, 3050, 3062, 3075, 3088, 3100, | ||
302 | 3112, 3124, 3136, 3148, 3159, 3170, 3182, 3193, 3204, 3214, | ||
303 | 3225, 3236, 3246, 3256, 3266, 3276, 3286, 3296, 3306, 3316, | ||
304 | 3325, 3334, 3344, 3353, 3362, 3371, 3380, 3389, 3397, 3406, | ||
305 | 3415, 3423, 3432, 3440, 3448, 3456, 3464, 3472, 3480, 3488, | ||
306 | 3496, 3504, 3511, 3519, 3526, 3534, 3541, 3549, 3556, 3563, | ||
307 | 3570, 3577, 3584, 3591, 3598, 3605, 3612, 3619, 3625, 3632, | ||
308 | 3639, 3645, 3652, 3658, 3665, 3671, 3677, 3683, 3690, 3696, | ||
309 | 3702, 3708, 3714, 3720, 3726, 3732, 3738, 3744, 3750, 3755, | ||
310 | 3761, 3767, 3772, 3778, 3784, 3789, 3795, 3800, 3806, 3811, | ||
311 | 3816, 3822, 3827, 3832, 3838, 3843, 3848, 3853, 3858, 3863, | ||
312 | 3868, 3874, 3879, 3884, 3888, 3893, 3898, 3903, 3908, 3913, | ||
313 | 3918, 3922, 3927, 3932, 3936, 3941, 3946, 3950, 3955, 3960, | ||
314 | 3964, 3969, 3973, 3978, 3982, 3986, 3991, 3995, 4000, 4004, | ||
315 | }; | ||
316 | |||
317 | static unsigned int denom[] = {1,1,100,1000,10000,100000,1000000,10000000,100000000}; | ||
318 | |||
319 | static unsigned int i20Log10(unsigned short val) | ||
320 | { | ||
321 | unsigned int rntval = 100; | ||
322 | unsigned int tmp = val; | ||
323 | unsigned int exp = 1; | ||
324 | |||
325 | while(tmp > 100) {tmp /= 100; exp++;} | ||
326 | |||
327 | val = (2 * val)/denom[exp]; | ||
328 | if (exp > 1) rntval = 2000*exp; | ||
329 | |||
330 | rntval += i100x20log10[val]; | ||
331 | return rntval; | ||
332 | } | ||
333 | |||
334 | static int or51211_read_signal_strength(struct dvb_frontend* fe, u16* strength) | ||
335 | { | ||
336 | struct or51211_state* state = fe->demodulator_priv; | ||
337 | u8 rec_buf[2]; | ||
338 | u8 snd_buf[4]; | ||
339 | u8 snr_equ; | ||
340 | |||
341 | /* SNR after Equalizer */ | ||
342 | snd_buf[0] = 0x04; | ||
343 | snd_buf[1] = 0x00; | ||
344 | snd_buf[2] = 0x04; | ||
345 | snd_buf[3] = 0x00; | ||
346 | |||
347 | if (i2c_writebytes(state,state->config->demod_address,snd_buf,3)) { | ||
348 | printk(KERN_WARNING "or51211: read_status write error\n"); | ||
349 | return -1; | ||
350 | } | ||
351 | msleep(3); | ||
352 | if (i2c_readbytes(state,state->config->demod_address,rec_buf,2)) { | ||
353 | printk(KERN_WARNING "or51211: read_status read error\n"); | ||
354 | return -1; | ||
355 | } | ||
356 | snr_equ = rec_buf[0] & 0xff; | ||
357 | |||
358 | /* The value reported back from the frontend will be FFFF=100% 0000=0% */ | ||
359 | *strength = (((5334 - i20Log10(snr_equ))/3+5)*65535)/1000; | ||
360 | |||
361 | dprintk("read_signal_strength %i\n",*strength); | ||
362 | |||
363 | return 0; | ||
364 | } | ||
365 | |||
366 | static int or51211_read_snr(struct dvb_frontend* fe, u16* snr) | ||
367 | { | ||
368 | struct or51211_state* state = fe->demodulator_priv; | ||
369 | u8 rec_buf[2]; | ||
370 | u8 snd_buf[4]; | ||
371 | |||
372 | /* SNR after Equalizer */ | ||
373 | snd_buf[0] = 0x04; | ||
374 | snd_buf[1] = 0x00; | ||
375 | snd_buf[2] = 0x04; | ||
376 | snd_buf[3] = 0x00; | ||
377 | |||
378 | if (i2c_writebytes(state,state->config->demod_address,snd_buf,3)) { | ||
379 | printk(KERN_WARNING "or51211: read_status write error\n"); | ||
380 | return -1; | ||
381 | } | ||
382 | msleep(3); | ||
383 | if (i2c_readbytes(state,state->config->demod_address,rec_buf,2)) { | ||
384 | printk(KERN_WARNING "or51211: read_status read error\n"); | ||
385 | return -1; | ||
386 | } | ||
387 | *snr = rec_buf[0] & 0xff; | ||
388 | |||
389 | dprintk("read_snr %i\n",*snr); | ||
390 | |||
391 | return 0; | ||
392 | } | ||
393 | |||
394 | static int or51211_read_ber(struct dvb_frontend* fe, u32* ber) | ||
395 | { | ||
396 | *ber = -ENOSYS; | ||
397 | return 0; | ||
398 | } | ||
399 | |||
400 | static int or51211_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks) | ||
401 | { | ||
402 | *ucblocks = -ENOSYS; | ||
403 | return 0; | ||
404 | } | ||
405 | |||
406 | static int or51211_sleep(struct dvb_frontend* fe) | ||
407 | { | ||
408 | return 0; | ||
409 | } | ||
410 | |||
411 | static int or51211_init(struct dvb_frontend* fe) | ||
412 | { | ||
413 | struct or51211_state* state = fe->demodulator_priv; | ||
414 | const struct or51211_config* config = state->config; | ||
415 | const struct firmware* fw; | ||
416 | unsigned char get_ver_buf[] = {0x04,0x00,0x30,0x00,0x00}; | ||
417 | unsigned char rec_buf[14]; | ||
418 | int ret,i; | ||
419 | |||
420 | if (!state->initialized) { | ||
421 | /* Request the firmware, this will block until it uploads */ | ||
422 | printk(KERN_INFO "or51211: Waiting for firmware upload " | ||
423 | "(%s)...\n", OR51211_DEFAULT_FIRMWARE); | ||
424 | ret = config->request_firmware(fe, &fw, | ||
425 | OR51211_DEFAULT_FIRMWARE); | ||
426 | printk(KERN_INFO "or51211:Got Hotplug firmware\n"); | ||
427 | if (ret) { | ||
428 | printk(KERN_WARNING "or51211: No firmware uploaded " | ||
429 | "(timeout or file not found?)\n"); | ||
430 | return ret; | ||
431 | } | ||
432 | |||
433 | ret = or51211_load_firmware(fe, fw); | ||
434 | if (ret) { | ||
435 | printk(KERN_WARNING "or51211: Writing firmware to " | ||
436 | "device failed!\n"); | ||
437 | release_firmware(fw); | ||
438 | return ret; | ||
439 | } | ||
440 | printk(KERN_INFO "or51211: Firmware upload complete.\n"); | ||
441 | |||
442 | /* Set operation mode in Receiver 1 register; | ||
443 | * type 1: | ||
444 | * data 0x50h Automatic sets receiver channel conditions | ||
445 | * Automatic NTSC rejection filter | ||
446 | * Enable MPEG serial data output | ||
447 | * MPEG2tr | ||
448 | * High tuner phase noise | ||
449 | * normal +/-150kHz Carrier acquisition range | ||
450 | */ | ||
451 | if (i2c_writebytes(state,state->config->demod_address, | ||
452 | cmd_buf,3)) { | ||
453 | printk(KERN_WARNING "or51211: Load DVR Error 5\n"); | ||
454 | return -1; | ||
455 | } | ||
456 | |||
457 | /* Read back ucode version to besure we loaded correctly */ | ||
458 | /* and are really up and running */ | ||
459 | rec_buf[0] = 0x04; | ||
460 | rec_buf[1] = 0x00; | ||
461 | rec_buf[2] = 0x03; | ||
462 | rec_buf[3] = 0x00; | ||
463 | msleep(30); | ||
464 | if (i2c_writebytes(state,state->config->demod_address, | ||
465 | rec_buf,3)) { | ||
466 | printk(KERN_WARNING "or51211: Load DVR Error A\n"); | ||
467 | return -1; | ||
468 | } | ||
469 | msleep(3); | ||
470 | if (i2c_readbytes(state,state->config->demod_address, | ||
471 | &rec_buf[10],2)) { | ||
472 | printk(KERN_WARNING "or51211: Load DVR Error B\n"); | ||
473 | return -1; | ||
474 | } | ||
475 | |||
476 | rec_buf[0] = 0x04; | ||
477 | rec_buf[1] = 0x00; | ||
478 | rec_buf[2] = 0x01; | ||
479 | rec_buf[3] = 0x00; | ||
480 | msleep(20); | ||
481 | if (i2c_writebytes(state,state->config->demod_address, | ||
482 | rec_buf,3)) { | ||
483 | printk(KERN_WARNING "or51211: Load DVR Error C\n"); | ||
484 | return -1; | ||
485 | } | ||
486 | msleep(3); | ||
487 | if (i2c_readbytes(state,state->config->demod_address, | ||
488 | &rec_buf[12],2)) { | ||
489 | printk(KERN_WARNING "or51211: Load DVR Error D\n"); | ||
490 | return -1; | ||
491 | } | ||
492 | |||
493 | for (i = 0; i < 8; i++) | ||
494 | rec_buf[i]=0xed; | ||
495 | |||
496 | for (i = 0; i < 5; i++) { | ||
497 | msleep(30); | ||
498 | get_ver_buf[4] = i+1; | ||
499 | if (i2c_writebytes(state,state->config->demod_address, | ||
500 | get_ver_buf,5)) { | ||
501 | printk(KERN_WARNING "or51211:Load DVR Error 6" | ||
502 | " - %d\n",i); | ||
503 | return -1; | ||
504 | } | ||
505 | msleep(3); | ||
506 | |||
507 | if (i2c_readbytes(state,state->config->demod_address, | ||
508 | &rec_buf[i*2],2)) { | ||
509 | printk(KERN_WARNING "or51211:Load DVR Error 7" | ||
510 | " - %d\n",i); | ||
511 | return -1; | ||
512 | } | ||
513 | /* If we didn't receive the right index, try again */ | ||
514 | if ((int)rec_buf[i*2+1]!=i+1){ | ||
515 | i--; | ||
516 | } | ||
517 | } | ||
518 | dprintk("read_fwbits %x %x %x %x %x %x %x %x %x %x\n", | ||
519 | rec_buf[0], rec_buf[1], rec_buf[2], rec_buf[3], | ||
520 | rec_buf[4], rec_buf[5], rec_buf[6], rec_buf[7], | ||
521 | rec_buf[8], rec_buf[9]); | ||
522 | |||
523 | printk(KERN_INFO "or51211: ver TU%02x%02x%02x VSB mode %02x" | ||
524 | " Status %02x\n", | ||
525 | rec_buf[2], rec_buf[4],rec_buf[6], | ||
526 | rec_buf[12],rec_buf[10]); | ||
527 | |||
528 | rec_buf[0] = 0x04; | ||
529 | rec_buf[1] = 0x00; | ||
530 | rec_buf[2] = 0x03; | ||
531 | rec_buf[3] = 0x00; | ||
532 | msleep(20); | ||
533 | if (i2c_writebytes(state,state->config->demod_address, | ||
534 | rec_buf,3)) { | ||
535 | printk(KERN_WARNING "or51211: Load DVR Error 8\n"); | ||
536 | return -1; | ||
537 | } | ||
538 | msleep(20); | ||
539 | if (i2c_readbytes(state,state->config->demod_address, | ||
540 | &rec_buf[8],2)) { | ||
541 | printk(KERN_WARNING "or51211: Load DVR Error 9\n"); | ||
542 | return -1; | ||
543 | } | ||
544 | state->initialized = 1; | ||
545 | } | ||
546 | |||
547 | return 0; | ||
548 | } | ||
549 | |||
550 | static int or51211_get_tune_settings(struct dvb_frontend* fe, | ||
551 | struct dvb_frontend_tune_settings* fesettings) | ||
552 | { | ||
553 | fesettings->min_delay_ms = 500; | ||
554 | fesettings->step_size = 0; | ||
555 | fesettings->max_drift = 0; | ||
556 | return 0; | ||
557 | } | ||
558 | |||
559 | static void or51211_release(struct dvb_frontend* fe) | ||
560 | { | ||
561 | struct or51211_state* state = fe->demodulator_priv; | ||
562 | state->config->sleep(fe); | ||
563 | kfree(state); | ||
564 | } | ||
565 | |||
566 | static struct dvb_frontend_ops or51211_ops; | ||
567 | |||
568 | struct dvb_frontend* or51211_attach(const struct or51211_config* config, | ||
569 | struct i2c_adapter* i2c) | ||
570 | { | ||
571 | struct or51211_state* state = NULL; | ||
572 | |||
573 | /* Allocate memory for the internal state */ | ||
574 | state = kmalloc(sizeof(struct or51211_state), GFP_KERNEL); | ||
575 | if (state == NULL) | ||
576 | goto error; | ||
577 | |||
578 | /* Setup the state */ | ||
579 | state->config = config; | ||
580 | state->i2c = i2c; | ||
581 | memcpy(&state->ops, &or51211_ops, sizeof(struct dvb_frontend_ops)); | ||
582 | state->initialized = 0; | ||
583 | state->current_frequency = 0; | ||
584 | |||
585 | /* Create dvb_frontend */ | ||
586 | state->frontend.ops = &state->ops; | ||
587 | state->frontend.demodulator_priv = state; | ||
588 | return &state->frontend; | ||
589 | |||
590 | error: | ||
591 | kfree(state); | ||
592 | return NULL; | ||
593 | } | ||
594 | |||
595 | static struct dvb_frontend_ops or51211_ops = { | ||
596 | |||
597 | .info = { | ||
598 | .name = "Oren OR51211 VSB Frontend", | ||
599 | .type = FE_ATSC, | ||
600 | .frequency_min = 44000000, | ||
601 | .frequency_max = 958000000, | ||
602 | .frequency_stepsize = 166666, | ||
603 | .caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | | ||
604 | FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO | | ||
605 | FE_CAN_8VSB | ||
606 | }, | ||
607 | |||
608 | .release = or51211_release, | ||
609 | |||
610 | .init = or51211_init, | ||
611 | .sleep = or51211_sleep, | ||
612 | |||
613 | .set_frontend = or51211_set_parameters, | ||
614 | .get_tune_settings = or51211_get_tune_settings, | ||
615 | |||
616 | .read_status = or51211_read_status, | ||
617 | .read_ber = or51211_read_ber, | ||
618 | .read_signal_strength = or51211_read_signal_strength, | ||
619 | .read_snr = or51211_read_snr, | ||
620 | .read_ucblocks = or51211_read_ucblocks, | ||
621 | }; | ||
622 | |||
623 | module_param(debug, int, 0644); | ||
624 | MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off)."); | ||
625 | |||
626 | MODULE_DESCRIPTION("Oren OR51211 VSB [pcHDTV HD-2000] Demodulator Driver"); | ||
627 | MODULE_AUTHOR("Kirk Lapray"); | ||
628 | MODULE_LICENSE("GPL"); | ||
629 | |||
630 | EXPORT_SYMBOL(or51211_attach); | ||
631 | |||
diff --git a/drivers/media/dvb/frontends/or51211.h b/drivers/media/dvb/frontends/or51211.h new file mode 100644 index 000000000000..13a5a3afbf8b --- /dev/null +++ b/drivers/media/dvb/frontends/or51211.h | |||
@@ -0,0 +1,44 @@ | |||
1 | /* | ||
2 | * Support for OR51211 (pcHDTV HD-2000) - VSB | ||
3 | * | ||
4 | * Copyright (C) 2005 Kirk Lapray <kirk_lapray@bigfoot.com> | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License as published by | ||
8 | * the Free Software Foundation; either version 2 of the License, or | ||
9 | * (at your option) any later version. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU General Public License for more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License | ||
17 | * along with this program; if not, write to the Free Software | ||
18 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
19 | * | ||
20 | */ | ||
21 | |||
22 | #ifndef OR51211_H | ||
23 | #define OR51211_H | ||
24 | |||
25 | #include <linux/dvb/frontend.h> | ||
26 | #include <linux/firmware.h> | ||
27 | |||
28 | struct or51211_config | ||
29 | { | ||
30 | /* The demodulator's i2c address */ | ||
31 | u8 demod_address; | ||
32 | |||
33 | /* Request firmware for device */ | ||
34 | int (*request_firmware)(struct dvb_frontend* fe, const struct firmware **fw, char* name); | ||
35 | void (*setmode)(struct dvb_frontend * fe, int mode); | ||
36 | void (*reset)(struct dvb_frontend * fe); | ||
37 | void (*sleep)(struct dvb_frontend * fe); | ||
38 | }; | ||
39 | |||
40 | extern struct dvb_frontend* or51211_attach(const struct or51211_config* config, | ||
41 | struct i2c_adapter* i2c); | ||
42 | |||
43 | #endif // OR51211_H | ||
44 | |||
diff --git a/drivers/media/dvb/frontends/sp8870.c b/drivers/media/dvb/frontends/sp8870.c new file mode 100644 index 000000000000..58ad34ef0a00 --- /dev/null +++ b/drivers/media/dvb/frontends/sp8870.c | |||
@@ -0,0 +1,614 @@ | |||
1 | /* | ||
2 | Driver for Spase SP8870 demodulator | ||
3 | |||
4 | Copyright (C) 1999 Juergen Peitz | ||
5 | |||
6 | This program is free software; you can redistribute it and/or modify | ||
7 | it under the terms of the GNU General Public License as published by | ||
8 | the Free Software Foundation; either version 2 of the License, or | ||
9 | (at your option) any later version. | ||
10 | |||
11 | This program is distributed in the hope that it will be useful, | ||
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | |||
15 | GNU General Public License for more details. | ||
16 | |||
17 | You should have received a copy of the GNU General Public License | ||
18 | along with this program; if not, write to the Free Software | ||
19 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
20 | |||
21 | */ | ||
22 | /* | ||
23 | * This driver needs external firmware. Please use the command | ||
24 | * "<kerneldir>/Documentation/dvb/get_dvb_firmware alps_tdlb7" to | ||
25 | * download/extract it, and then copy it to /usr/lib/hotplug/firmware. | ||
26 | */ | ||
27 | #define SP8870_DEFAULT_FIRMWARE "dvb-fe-sp8870.fw" | ||
28 | |||
29 | #include <linux/init.h> | ||
30 | #include <linux/module.h> | ||
31 | #include <linux/moduleparam.h> | ||
32 | #include <linux/device.h> | ||
33 | #include <linux/firmware.h> | ||
34 | #include <linux/delay.h> | ||
35 | |||
36 | #include "dvb_frontend.h" | ||
37 | #include "sp8870.h" | ||
38 | |||
39 | |||
40 | struct sp8870_state { | ||
41 | |||
42 | struct i2c_adapter* i2c; | ||
43 | |||
44 | struct dvb_frontend_ops ops; | ||
45 | |||
46 | const struct sp8870_config* config; | ||
47 | |||
48 | struct dvb_frontend frontend; | ||
49 | |||
50 | /* demodulator private data */ | ||
51 | u8 initialised:1; | ||
52 | }; | ||
53 | |||
54 | static int debug; | ||
55 | #define dprintk(args...) \ | ||
56 | do { \ | ||
57 | if (debug) printk(KERN_DEBUG "sp8870: " args); \ | ||
58 | } while (0) | ||
59 | |||
60 | /* firmware size for sp8870 */ | ||
61 | #define SP8870_FIRMWARE_SIZE 16382 | ||
62 | |||
63 | /* starting point for firmware in file 'Sc_main.mc' */ | ||
64 | #define SP8870_FIRMWARE_OFFSET 0x0A | ||
65 | |||
66 | static int sp8870_writereg (struct sp8870_state* state, u16 reg, u16 data) | ||
67 | { | ||
68 | u8 buf [] = { reg >> 8, reg & 0xff, data >> 8, data & 0xff }; | ||
69 | struct i2c_msg msg = { .addr = state->config->demod_address, .flags = 0, .buf = buf, .len = 4 }; | ||
70 | int err; | ||
71 | |||
72 | if ((err = i2c_transfer (state->i2c, &msg, 1)) != 1) { | ||
73 | dprintk ("%s: writereg error (err == %i, reg == 0x%02x, data == 0x%02x)\n", __FUNCTION__, err, reg, data); | ||
74 | return -EREMOTEIO; | ||
75 | } | ||
76 | |||
77 | return 0; | ||
78 | } | ||
79 | |||
80 | static int sp8870_readreg (struct sp8870_state* state, u16 reg) | ||
81 | { | ||
82 | int ret; | ||
83 | u8 b0 [] = { reg >> 8 , reg & 0xff }; | ||
84 | u8 b1 [] = { 0, 0 }; | ||
85 | struct i2c_msg msg [] = { { .addr = state->config->demod_address, .flags = 0, .buf = b0, .len = 2 }, | ||
86 | { .addr = state->config->demod_address, .flags = I2C_M_RD, .buf = b1, .len = 2 } }; | ||
87 | |||
88 | ret = i2c_transfer (state->i2c, msg, 2); | ||
89 | |||
90 | if (ret != 2) { | ||
91 | dprintk("%s: readreg error (ret == %i)\n", __FUNCTION__, ret); | ||
92 | return -1; | ||
93 | } | ||
94 | |||
95 | return (b1[0] << 8 | b1[1]); | ||
96 | } | ||
97 | |||
98 | static int sp8870_firmware_upload (struct sp8870_state* state, const struct firmware *fw) | ||
99 | { | ||
100 | struct i2c_msg msg; | ||
101 | char *fw_buf = fw->data; | ||
102 | int fw_pos; | ||
103 | u8 tx_buf[255]; | ||
104 | int tx_len; | ||
105 | int err = 0; | ||
106 | |||
107 | dprintk ("%s: ...\n", __FUNCTION__); | ||
108 | |||
109 | if (fw->size < SP8870_FIRMWARE_SIZE + SP8870_FIRMWARE_OFFSET) | ||
110 | return -EINVAL; | ||
111 | |||
112 | // system controller stop | ||
113 | sp8870_writereg(state, 0x0F00, 0x0000); | ||
114 | |||
115 | // instruction RAM register hiword | ||
116 | sp8870_writereg(state, 0x8F08, ((SP8870_FIRMWARE_SIZE / 2) & 0xFFFF)); | ||
117 | |||
118 | // instruction RAM MWR | ||
119 | sp8870_writereg(state, 0x8F0A, ((SP8870_FIRMWARE_SIZE / 2) >> 16)); | ||
120 | |||
121 | // do firmware upload | ||
122 | fw_pos = SP8870_FIRMWARE_OFFSET; | ||
123 | while (fw_pos < SP8870_FIRMWARE_SIZE + SP8870_FIRMWARE_OFFSET){ | ||
124 | tx_len = (fw_pos <= SP8870_FIRMWARE_SIZE + SP8870_FIRMWARE_OFFSET - 252) ? 252 : SP8870_FIRMWARE_SIZE + SP8870_FIRMWARE_OFFSET - fw_pos; | ||
125 | // write register 0xCF0A | ||
126 | tx_buf[0] = 0xCF; | ||
127 | tx_buf[1] = 0x0A; | ||
128 | memcpy(&tx_buf[2], fw_buf + fw_pos, tx_len); | ||
129 | msg.addr = state->config->demod_address; | ||
130 | msg.flags = 0; | ||
131 | msg.buf = tx_buf; | ||
132 | msg.len = tx_len + 2; | ||
133 | if ((err = i2c_transfer (state->i2c, &msg, 1)) != 1) { | ||
134 | printk("%s: firmware upload failed!\n", __FUNCTION__); | ||
135 | printk ("%s: i2c error (err == %i)\n", __FUNCTION__, err); | ||
136 | return err; | ||
137 | } | ||
138 | fw_pos += tx_len; | ||
139 | } | ||
140 | |||
141 | dprintk ("%s: done!\n", __FUNCTION__); | ||
142 | return 0; | ||
143 | }; | ||
144 | |||
145 | static void sp8870_microcontroller_stop (struct sp8870_state* state) | ||
146 | { | ||
147 | sp8870_writereg(state, 0x0F08, 0x000); | ||
148 | sp8870_writereg(state, 0x0F09, 0x000); | ||
149 | |||
150 | // microcontroller STOP | ||
151 | sp8870_writereg(state, 0x0F00, 0x000); | ||
152 | } | ||
153 | |||
154 | static void sp8870_microcontroller_start (struct sp8870_state* state) | ||
155 | { | ||
156 | sp8870_writereg(state, 0x0F08, 0x000); | ||
157 | sp8870_writereg(state, 0x0F09, 0x000); | ||
158 | |||
159 | // microcontroller START | ||
160 | sp8870_writereg(state, 0x0F00, 0x001); | ||
161 | // not documented but if we don't read 0x0D01 out here | ||
162 | // we don't get a correct data valid signal | ||
163 | sp8870_readreg(state, 0x0D01); | ||
164 | } | ||
165 | |||
166 | static int sp8870_read_data_valid_signal(struct sp8870_state* state) | ||
167 | { | ||
168 | return (sp8870_readreg(state, 0x0D02) > 0); | ||
169 | } | ||
170 | |||
171 | static int configure_reg0xc05 (struct dvb_frontend_parameters *p, u16 *reg0xc05) | ||
172 | { | ||
173 | int known_parameters = 1; | ||
174 | |||
175 | *reg0xc05 = 0x000; | ||
176 | |||
177 | switch (p->u.ofdm.constellation) { | ||
178 | case QPSK: | ||
179 | break; | ||
180 | case QAM_16: | ||
181 | *reg0xc05 |= (1 << 10); | ||
182 | break; | ||
183 | case QAM_64: | ||
184 | *reg0xc05 |= (2 << 10); | ||
185 | break; | ||
186 | case QAM_AUTO: | ||
187 | known_parameters = 0; | ||
188 | break; | ||
189 | default: | ||
190 | return -EINVAL; | ||
191 | }; | ||
192 | |||
193 | switch (p->u.ofdm.hierarchy_information) { | ||
194 | case HIERARCHY_NONE: | ||
195 | break; | ||
196 | case HIERARCHY_1: | ||
197 | *reg0xc05 |= (1 << 7); | ||
198 | break; | ||
199 | case HIERARCHY_2: | ||
200 | *reg0xc05 |= (2 << 7); | ||
201 | break; | ||
202 | case HIERARCHY_4: | ||
203 | *reg0xc05 |= (3 << 7); | ||
204 | break; | ||
205 | case HIERARCHY_AUTO: | ||
206 | known_parameters = 0; | ||
207 | break; | ||
208 | default: | ||
209 | return -EINVAL; | ||
210 | }; | ||
211 | |||
212 | switch (p->u.ofdm.code_rate_HP) { | ||
213 | case FEC_1_2: | ||
214 | break; | ||
215 | case FEC_2_3: | ||
216 | *reg0xc05 |= (1 << 3); | ||
217 | break; | ||
218 | case FEC_3_4: | ||
219 | *reg0xc05 |= (2 << 3); | ||
220 | break; | ||
221 | case FEC_5_6: | ||
222 | *reg0xc05 |= (3 << 3); | ||
223 | break; | ||
224 | case FEC_7_8: | ||
225 | *reg0xc05 |= (4 << 3); | ||
226 | break; | ||
227 | case FEC_AUTO: | ||
228 | known_parameters = 0; | ||
229 | break; | ||
230 | default: | ||
231 | return -EINVAL; | ||
232 | }; | ||
233 | |||
234 | if (known_parameters) | ||
235 | *reg0xc05 |= (2 << 1); /* use specified parameters */ | ||
236 | else | ||
237 | *reg0xc05 |= (1 << 1); /* enable autoprobing */ | ||
238 | |||
239 | return 0; | ||
240 | } | ||
241 | |||
242 | static int sp8870_wake_up(struct sp8870_state* state) | ||
243 | { | ||
244 | // enable TS output and interface pins | ||
245 | return sp8870_writereg(state, 0xC18, 0x00D); | ||
246 | } | ||
247 | |||
248 | static int sp8870_set_frontend_parameters (struct dvb_frontend* fe, | ||
249 | struct dvb_frontend_parameters *p) | ||
250 | { | ||
251 | struct sp8870_state* state = (struct sp8870_state*) fe->demodulator_priv; | ||
252 | int err; | ||
253 | u16 reg0xc05; | ||
254 | |||
255 | if ((err = configure_reg0xc05(p, ®0xc05))) | ||
256 | return err; | ||
257 | |||
258 | // system controller stop | ||
259 | sp8870_microcontroller_stop(state); | ||
260 | |||
261 | // set tuner parameters | ||
262 | sp8870_writereg(state, 0x206, 0x001); | ||
263 | state->config->pll_set(fe, p); | ||
264 | sp8870_writereg(state, 0x206, 0x000); | ||
265 | |||
266 | // sample rate correction bit [23..17] | ||
267 | sp8870_writereg(state, 0x0319, 0x000A); | ||
268 | |||
269 | // sample rate correction bit [16..0] | ||
270 | sp8870_writereg(state, 0x031A, 0x0AAB); | ||
271 | |||
272 | // integer carrier offset | ||
273 | sp8870_writereg(state, 0x0309, 0x0400); | ||
274 | |||
275 | // fractional carrier offset | ||
276 | sp8870_writereg(state, 0x030A, 0x0000); | ||
277 | |||
278 | // filter for 6/7/8 Mhz channel | ||
279 | if (p->u.ofdm.bandwidth == BANDWIDTH_6_MHZ) | ||
280 | sp8870_writereg(state, 0x0311, 0x0002); | ||
281 | else if (p->u.ofdm.bandwidth == BANDWIDTH_7_MHZ) | ||
282 | sp8870_writereg(state, 0x0311, 0x0001); | ||
283 | else | ||
284 | sp8870_writereg(state, 0x0311, 0x0000); | ||
285 | |||
286 | // scan order: 2k first = 0x0000, 8k first = 0x0001 | ||
287 | if (p->u.ofdm.transmission_mode == TRANSMISSION_MODE_2K) | ||
288 | sp8870_writereg(state, 0x0338, 0x0000); | ||
289 | else | ||
290 | sp8870_writereg(state, 0x0338, 0x0001); | ||
291 | |||
292 | sp8870_writereg(state, 0xc05, reg0xc05); | ||
293 | |||
294 | // read status reg in order to clear pending irqs | ||
295 | sp8870_readreg(state, 0x200); | ||
296 | |||
297 | // system controller start | ||
298 | sp8870_microcontroller_start(state); | ||
299 | |||
300 | return 0; | ||
301 | } | ||
302 | |||
303 | static int sp8870_init (struct dvb_frontend* fe) | ||
304 | { | ||
305 | struct sp8870_state* state = (struct sp8870_state*) fe->demodulator_priv; | ||
306 | const struct firmware *fw = NULL; | ||
307 | |||
308 | sp8870_wake_up(state); | ||
309 | if (state->initialised) return 0; | ||
310 | state->initialised = 1; | ||
311 | |||
312 | dprintk ("%s\n", __FUNCTION__); | ||
313 | |||
314 | |||
315 | /* request the firmware, this will block until someone uploads it */ | ||
316 | printk("sp8870: waiting for firmware upload (%s)...\n", SP8870_DEFAULT_FIRMWARE); | ||
317 | if (state->config->request_firmware(fe, &fw, SP8870_DEFAULT_FIRMWARE)) { | ||
318 | printk("sp8870: no firmware upload (timeout or file not found?)\n"); | ||
319 | release_firmware(fw); | ||
320 | return -EIO; | ||
321 | } | ||
322 | |||
323 | if (sp8870_firmware_upload(state, fw)) { | ||
324 | printk("sp8870: writing firmware to device failed\n"); | ||
325 | release_firmware(fw); | ||
326 | return -EIO; | ||
327 | } | ||
328 | printk("sp8870: firmware upload complete\n"); | ||
329 | |||
330 | /* enable TS output and interface pins */ | ||
331 | sp8870_writereg(state, 0xc18, 0x00d); | ||
332 | |||
333 | // system controller stop | ||
334 | sp8870_microcontroller_stop(state); | ||
335 | |||
336 | // ADC mode | ||
337 | sp8870_writereg(state, 0x0301, 0x0003); | ||
338 | |||
339 | // Reed Solomon parity bytes passed to output | ||
340 | sp8870_writereg(state, 0x0C13, 0x0001); | ||
341 | |||
342 | // MPEG clock is suppressed if no valid data | ||
343 | sp8870_writereg(state, 0x0C14, 0x0001); | ||
344 | |||
345 | /* bit 0x010: enable data valid signal */ | ||
346 | sp8870_writereg(state, 0x0D00, 0x010); | ||
347 | sp8870_writereg(state, 0x0D01, 0x000); | ||
348 | |||
349 | /* setup PLL */ | ||
350 | if (state->config->pll_init) { | ||
351 | sp8870_writereg(state, 0x206, 0x001); | ||
352 | state->config->pll_init(fe); | ||
353 | sp8870_writereg(state, 0x206, 0x000); | ||
354 | } | ||
355 | |||
356 | return 0; | ||
357 | } | ||
358 | |||
359 | static int sp8870_read_status (struct dvb_frontend* fe, fe_status_t * fe_status) | ||
360 | { | ||
361 | struct sp8870_state* state = (struct sp8870_state*) fe->demodulator_priv; | ||
362 | int status; | ||
363 | int signal; | ||
364 | |||
365 | *fe_status = 0; | ||
366 | |||
367 | status = sp8870_readreg (state, 0x0200); | ||
368 | if (status < 0) | ||
369 | return -EIO; | ||
370 | |||
371 | signal = sp8870_readreg (state, 0x0303); | ||
372 | if (signal < 0) | ||
373 | return -EIO; | ||
374 | |||
375 | if (signal > 0x0F) | ||
376 | *fe_status |= FE_HAS_SIGNAL; | ||
377 | if (status & 0x08) | ||
378 | *fe_status |= FE_HAS_SYNC; | ||
379 | if (status & 0x04) | ||
380 | *fe_status |= FE_HAS_LOCK | FE_HAS_CARRIER | FE_HAS_VITERBI; | ||
381 | |||
382 | return 0; | ||
383 | } | ||
384 | |||
385 | static int sp8870_read_ber (struct dvb_frontend* fe, u32 * ber) | ||
386 | { | ||
387 | struct sp8870_state* state = (struct sp8870_state*) fe->demodulator_priv; | ||
388 | int ret; | ||
389 | u32 tmp; | ||
390 | |||
391 | *ber = 0; | ||
392 | |||
393 | ret = sp8870_readreg(state, 0xC08); | ||
394 | if (ret < 0) | ||
395 | return -EIO; | ||
396 | |||
397 | tmp = ret & 0x3F; | ||
398 | |||
399 | ret = sp8870_readreg(state, 0xC07); | ||
400 | if (ret < 0) | ||
401 | return -EIO; | ||
402 | |||
403 | tmp = ret << 6; | ||
404 | |||
405 | if (tmp >= 0x3FFF0) | ||
406 | tmp = ~0; | ||
407 | |||
408 | *ber = tmp; | ||
409 | |||
410 | return 0; | ||
411 | } | ||
412 | |||
413 | static int sp8870_read_signal_strength(struct dvb_frontend* fe, u16 * signal) | ||
414 | { | ||
415 | struct sp8870_state* state = (struct sp8870_state*) fe->demodulator_priv; | ||
416 | int ret; | ||
417 | u16 tmp; | ||
418 | |||
419 | *signal = 0; | ||
420 | |||
421 | ret = sp8870_readreg (state, 0x306); | ||
422 | if (ret < 0) | ||
423 | return -EIO; | ||
424 | |||
425 | tmp = ret << 8; | ||
426 | |||
427 | ret = sp8870_readreg (state, 0x303); | ||
428 | if (ret < 0) | ||
429 | return -EIO; | ||
430 | |||
431 | tmp |= ret; | ||
432 | |||
433 | if (tmp) | ||
434 | *signal = 0xFFFF - tmp; | ||
435 | |||
436 | return 0; | ||
437 | } | ||
438 | |||
439 | static int sp8870_read_uncorrected_blocks (struct dvb_frontend* fe, u32* ublocks) | ||
440 | { | ||
441 | struct sp8870_state* state = (struct sp8870_state*) fe->demodulator_priv; | ||
442 | int ret; | ||
443 | |||
444 | *ublocks = 0; | ||
445 | |||
446 | ret = sp8870_readreg(state, 0xC0C); | ||
447 | if (ret < 0) | ||
448 | return -EIO; | ||
449 | |||
450 | if (ret == 0xFFFF) | ||
451 | ret = ~0; | ||
452 | |||
453 | *ublocks = ret; | ||
454 | |||
455 | return 0; | ||
456 | } | ||
457 | |||
458 | // number of trials to recover from lockup | ||
459 | #define MAXTRIALS 5 | ||
460 | // maximum checks for data valid signal | ||
461 | #define MAXCHECKS 100 | ||
462 | |||
463 | // only for debugging: counter for detected lockups | ||
464 | static int lockups = 0; | ||
465 | // only for debugging: counter for channel switches | ||
466 | static int switches = 0; | ||
467 | |||
468 | static int sp8870_set_frontend (struct dvb_frontend* fe, struct dvb_frontend_parameters *p) | ||
469 | { | ||
470 | struct sp8870_state* state = (struct sp8870_state*) fe->demodulator_priv; | ||
471 | |||
472 | /* | ||
473 | The firmware of the sp8870 sometimes locks up after setting frontend parameters. | ||
474 | We try to detect this by checking the data valid signal. | ||
475 | If it is not set after MAXCHECKS we try to recover the lockup by setting | ||
476 | the frontend parameters again. | ||
477 | */ | ||
478 | |||
479 | int err = 0; | ||
480 | int valid = 0; | ||
481 | int trials = 0; | ||
482 | int check_count = 0; | ||
483 | |||
484 | dprintk("%s: frequency = %i\n", __FUNCTION__, p->frequency); | ||
485 | |||
486 | for (trials = 1; trials <= MAXTRIALS; trials++) { | ||
487 | |||
488 | if ((err = sp8870_set_frontend_parameters(fe, p))) | ||
489 | return err; | ||
490 | |||
491 | for (check_count = 0; check_count < MAXCHECKS; check_count++) { | ||
492 | // valid = ((sp8870_readreg(i2c, 0x0200) & 4) == 0); | ||
493 | valid = sp8870_read_data_valid_signal(state); | ||
494 | if (valid) { | ||
495 | dprintk("%s: delay = %i usec\n", | ||
496 | __FUNCTION__, check_count * 10); | ||
497 | break; | ||
498 | } | ||
499 | udelay(10); | ||
500 | } | ||
501 | if (valid) | ||
502 | break; | ||
503 | } | ||
504 | |||
505 | if (!valid) { | ||
506 | printk("%s: firmware crash!!!!!!\n", __FUNCTION__); | ||
507 | return -EIO; | ||
508 | } | ||
509 | |||
510 | if (debug) { | ||
511 | if (valid) { | ||
512 | if (trials > 1) { | ||
513 | printk("%s: firmware lockup!!!\n", __FUNCTION__); | ||
514 | printk("%s: recovered after %i trial(s))\n", __FUNCTION__, trials - 1); | ||
515 | lockups++; | ||
516 | } | ||
517 | } | ||
518 | switches++; | ||
519 | printk("%s: switches = %i lockups = %i\n", __FUNCTION__, switches, lockups); | ||
520 | } | ||
521 | |||
522 | return 0; | ||
523 | } | ||
524 | |||
525 | static int sp8870_sleep(struct dvb_frontend* fe) | ||
526 | { | ||
527 | struct sp8870_state* state = (struct sp8870_state*) fe->demodulator_priv; | ||
528 | |||
529 | // tristate TS output and disable interface pins | ||
530 | return sp8870_writereg(state, 0xC18, 0x000); | ||
531 | } | ||
532 | |||
533 | static int sp8870_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings* fesettings) | ||
534 | { | ||
535 | fesettings->min_delay_ms = 350; | ||
536 | fesettings->step_size = 0; | ||
537 | fesettings->max_drift = 0; | ||
538 | return 0; | ||
539 | } | ||
540 | |||
541 | static void sp8870_release(struct dvb_frontend* fe) | ||
542 | { | ||
543 | struct sp8870_state* state = (struct sp8870_state*) fe->demodulator_priv; | ||
544 | kfree(state); | ||
545 | } | ||
546 | |||
547 | static struct dvb_frontend_ops sp8870_ops; | ||
548 | |||
549 | struct dvb_frontend* sp8870_attach(const struct sp8870_config* config, | ||
550 | struct i2c_adapter* i2c) | ||
551 | { | ||
552 | struct sp8870_state* state = NULL; | ||
553 | |||
554 | /* allocate memory for the internal state */ | ||
555 | state = (struct sp8870_state*) kmalloc(sizeof(struct sp8870_state), GFP_KERNEL); | ||
556 | if (state == NULL) goto error; | ||
557 | |||
558 | /* setup the state */ | ||
559 | state->config = config; | ||
560 | state->i2c = i2c; | ||
561 | memcpy(&state->ops, &sp8870_ops, sizeof(struct dvb_frontend_ops)); | ||
562 | state->initialised = 0; | ||
563 | |||
564 | /* check if the demod is there */ | ||
565 | if (sp8870_readreg(state, 0x0200) < 0) goto error; | ||
566 | |||
567 | /* create dvb_frontend */ | ||
568 | state->frontend.ops = &state->ops; | ||
569 | state->frontend.demodulator_priv = state; | ||
570 | return &state->frontend; | ||
571 | |||
572 | error: | ||
573 | kfree(state); | ||
574 | return NULL; | ||
575 | } | ||
576 | |||
577 | static struct dvb_frontend_ops sp8870_ops = { | ||
578 | |||
579 | .info = { | ||
580 | .name = "Spase SP8870 DVB-T", | ||
581 | .type = FE_OFDM, | ||
582 | .frequency_min = 470000000, | ||
583 | .frequency_max = 860000000, | ||
584 | .frequency_stepsize = 166666, | ||
585 | .caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | | ||
586 | FE_CAN_FEC_3_4 | FE_CAN_FEC_5_6 | | ||
587 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO | | ||
588 | FE_CAN_QPSK | FE_CAN_QAM_16 | | ||
589 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO | | ||
590 | FE_CAN_HIERARCHY_AUTO | FE_CAN_RECOVER | ||
591 | }, | ||
592 | |||
593 | .release = sp8870_release, | ||
594 | |||
595 | .init = sp8870_init, | ||
596 | .sleep = sp8870_sleep, | ||
597 | |||
598 | .set_frontend = sp8870_set_frontend, | ||
599 | .get_tune_settings = sp8870_get_tune_settings, | ||
600 | |||
601 | .read_status = sp8870_read_status, | ||
602 | .read_ber = sp8870_read_ber, | ||
603 | .read_signal_strength = sp8870_read_signal_strength, | ||
604 | .read_ucblocks = sp8870_read_uncorrected_blocks, | ||
605 | }; | ||
606 | |||
607 | module_param(debug, int, 0644); | ||
608 | MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off)."); | ||
609 | |||
610 | MODULE_DESCRIPTION("Spase SP8870 DVB-T Demodulator driver"); | ||
611 | MODULE_AUTHOR("Juergen Peitz"); | ||
612 | MODULE_LICENSE("GPL"); | ||
613 | |||
614 | EXPORT_SYMBOL(sp8870_attach); | ||
diff --git a/drivers/media/dvb/frontends/sp8870.h b/drivers/media/dvb/frontends/sp8870.h new file mode 100644 index 000000000000..f3b555dbc960 --- /dev/null +++ b/drivers/media/dvb/frontends/sp8870.h | |||
@@ -0,0 +1,45 @@ | |||
1 | /* | ||
2 | Driver for Spase SP8870 demodulator | ||
3 | |||
4 | Copyright (C) 1999 Juergen Peitz | ||
5 | |||
6 | This program is free software; you can redistribute it and/or modify | ||
7 | it under the terms of the GNU General Public License as published by | ||
8 | the Free Software Foundation; either version 2 of the License, or | ||
9 | (at your option) any later version. | ||
10 | |||
11 | This program is distributed in the hope that it will be useful, | ||
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | |||
15 | GNU General Public License for more details. | ||
16 | |||
17 | You should have received a copy of the GNU General Public License | ||
18 | along with this program; if not, write to the Free Software | ||
19 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
20 | |||
21 | */ | ||
22 | |||
23 | #ifndef SP8870_H | ||
24 | #define SP8870_H | ||
25 | |||
26 | #include <linux/dvb/frontend.h> | ||
27 | #include <linux/firmware.h> | ||
28 | |||
29 | struct sp8870_config | ||
30 | { | ||
31 | /* the demodulator's i2c address */ | ||
32 | u8 demod_address; | ||
33 | |||
34 | /* PLL maintenance */ | ||
35 | int (*pll_init)(struct dvb_frontend* fe); | ||
36 | int (*pll_set)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params); | ||
37 | |||
38 | /* request firmware for device */ | ||
39 | int (*request_firmware)(struct dvb_frontend* fe, const struct firmware **fw, char* name); | ||
40 | }; | ||
41 | |||
42 | extern struct dvb_frontend* sp8870_attach(const struct sp8870_config* config, | ||
43 | struct i2c_adapter* i2c); | ||
44 | |||
45 | #endif // SP8870_H | ||
diff --git a/drivers/media/dvb/frontends/sp887x.c b/drivers/media/dvb/frontends/sp887x.c new file mode 100644 index 000000000000..7eae833ece49 --- /dev/null +++ b/drivers/media/dvb/frontends/sp887x.c | |||
@@ -0,0 +1,606 @@ | |||
1 | /* | ||
2 | Driver for the Spase sp887x demodulator | ||
3 | */ | ||
4 | |||
5 | /* | ||
6 | * This driver needs external firmware. Please use the command | ||
7 | * "<kerneldir>/Documentation/dvb/get_dvb_firmware sp887x" to | ||
8 | * download/extract it, and then copy it to /usr/lib/hotplug/firmware. | ||
9 | */ | ||
10 | #define SP887X_DEFAULT_FIRMWARE "dvb-fe-sp887x.fw" | ||
11 | |||
12 | #include <linux/init.h> | ||
13 | #include <linux/module.h> | ||
14 | #include <linux/moduleparam.h> | ||
15 | #include <linux/device.h> | ||
16 | #include <linux/firmware.h> | ||
17 | |||
18 | #include "dvb_frontend.h" | ||
19 | #include "sp887x.h" | ||
20 | |||
21 | |||
22 | struct sp887x_state { | ||
23 | struct i2c_adapter* i2c; | ||
24 | struct dvb_frontend_ops ops; | ||
25 | const struct sp887x_config* config; | ||
26 | struct dvb_frontend frontend; | ||
27 | |||
28 | /* demodulator private data */ | ||
29 | u8 initialised:1; | ||
30 | }; | ||
31 | |||
32 | static int debug; | ||
33 | #define dprintk(args...) \ | ||
34 | do { \ | ||
35 | if (debug) printk(KERN_DEBUG "sp887x: " args); \ | ||
36 | } while (0) | ||
37 | |||
38 | static int i2c_writebytes (struct sp887x_state* state, u8 *buf, u8 len) | ||
39 | { | ||
40 | struct i2c_msg msg = { .addr = state->config->demod_address, .flags = 0, .buf = buf, .len = len }; | ||
41 | int err; | ||
42 | |||
43 | if ((err = i2c_transfer (state->i2c, &msg, 1)) != 1) { | ||
44 | printk ("%s: i2c write error (addr %02x, err == %i)\n", | ||
45 | __FUNCTION__, state->config->demod_address, err); | ||
46 | return -EREMOTEIO; | ||
47 | } | ||
48 | |||
49 | return 0; | ||
50 | } | ||
51 | |||
52 | static int sp887x_writereg (struct sp887x_state* state, u16 reg, u16 data) | ||
53 | { | ||
54 | u8 b0 [] = { reg >> 8 , reg & 0xff, data >> 8, data & 0xff }; | ||
55 | struct i2c_msg msg = { .addr = state->config->demod_address, .flags = 0, .buf = b0, .len = 4 }; | ||
56 | int ret; | ||
57 | |||
58 | if ((ret = i2c_transfer(state->i2c, &msg, 1)) != 1) { | ||
59 | /** | ||
60 | * in case of soft reset we ignore ACK errors... | ||
61 | */ | ||
62 | if (!(reg == 0xf1a && data == 0x000 && | ||
63 | (ret == -EREMOTEIO || ret == -EFAULT))) | ||
64 | { | ||
65 | printk("%s: writereg error " | ||
66 | "(reg %03x, data %03x, ret == %i)\n", | ||
67 | __FUNCTION__, reg & 0xffff, data & 0xffff, ret); | ||
68 | return ret; | ||
69 | } | ||
70 | } | ||
71 | |||
72 | return 0; | ||
73 | } | ||
74 | |||
75 | static int sp887x_readreg (struct sp887x_state* state, u16 reg) | ||
76 | { | ||
77 | u8 b0 [] = { reg >> 8 , reg & 0xff }; | ||
78 | u8 b1 [2]; | ||
79 | int ret; | ||
80 | struct i2c_msg msg[] = {{ .addr = state->config->demod_address, .flags = 0, .buf = b0, .len = 2 }, | ||
81 | { .addr = state->config->demod_address, .flags = I2C_M_RD, .buf = b1, .len = 2 }}; | ||
82 | |||
83 | if ((ret = i2c_transfer(state->i2c, msg, 2)) != 2) { | ||
84 | printk("%s: readreg error (ret == %i)\n", __FUNCTION__, ret); | ||
85 | return -1; | ||
86 | } | ||
87 | |||
88 | return (((b1[0] << 8) | b1[1]) & 0xfff); | ||
89 | } | ||
90 | |||
91 | static void sp887x_microcontroller_stop (struct sp887x_state* state) | ||
92 | { | ||
93 | dprintk("%s\n", __FUNCTION__); | ||
94 | sp887x_writereg(state, 0xf08, 0x000); | ||
95 | sp887x_writereg(state, 0xf09, 0x000); | ||
96 | |||
97 | /* microcontroller STOP */ | ||
98 | sp887x_writereg(state, 0xf00, 0x000); | ||
99 | } | ||
100 | |||
101 | static void sp887x_microcontroller_start (struct sp887x_state* state) | ||
102 | { | ||
103 | dprintk("%s\n", __FUNCTION__); | ||
104 | sp887x_writereg(state, 0xf08, 0x000); | ||
105 | sp887x_writereg(state, 0xf09, 0x000); | ||
106 | |||
107 | /* microcontroller START */ | ||
108 | sp887x_writereg(state, 0xf00, 0x001); | ||
109 | } | ||
110 | |||
111 | static void sp887x_setup_agc (struct sp887x_state* state) | ||
112 | { | ||
113 | /* setup AGC parameters */ | ||
114 | dprintk("%s\n", __FUNCTION__); | ||
115 | sp887x_writereg(state, 0x33c, 0x054); | ||
116 | sp887x_writereg(state, 0x33b, 0x04c); | ||
117 | sp887x_writereg(state, 0x328, 0x000); | ||
118 | sp887x_writereg(state, 0x327, 0x005); | ||
119 | sp887x_writereg(state, 0x326, 0x001); | ||
120 | sp887x_writereg(state, 0x325, 0x001); | ||
121 | sp887x_writereg(state, 0x324, 0x001); | ||
122 | sp887x_writereg(state, 0x318, 0x050); | ||
123 | sp887x_writereg(state, 0x317, 0x3fe); | ||
124 | sp887x_writereg(state, 0x316, 0x001); | ||
125 | sp887x_writereg(state, 0x313, 0x005); | ||
126 | sp887x_writereg(state, 0x312, 0x002); | ||
127 | sp887x_writereg(state, 0x306, 0x000); | ||
128 | sp887x_writereg(state, 0x303, 0x000); | ||
129 | } | ||
130 | |||
131 | #define BLOCKSIZE 30 | ||
132 | #define FW_SIZE 0x4000 | ||
133 | /** | ||
134 | * load firmware and setup MPEG interface... | ||
135 | */ | ||
136 | static int sp887x_initial_setup (struct dvb_frontend* fe, const struct firmware *fw) | ||
137 | { | ||
138 | struct sp887x_state* state = (struct sp887x_state*) fe->demodulator_priv; | ||
139 | u8 buf [BLOCKSIZE+2]; | ||
140 | int i; | ||
141 | int fw_size = fw->size; | ||
142 | unsigned char *mem = fw->data; | ||
143 | |||
144 | dprintk("%s\n", __FUNCTION__); | ||
145 | |||
146 | /* ignore the first 10 bytes, then we expect 0x4000 bytes of firmware */ | ||
147 | if (fw_size < FW_SIZE+10) | ||
148 | return -ENODEV; | ||
149 | |||
150 | mem = fw->data + 10; | ||
151 | |||
152 | /* soft reset */ | ||
153 | sp887x_writereg(state, 0xf1a, 0x000); | ||
154 | |||
155 | sp887x_microcontroller_stop (state); | ||
156 | |||
157 | printk ("%s: firmware upload... ", __FUNCTION__); | ||
158 | |||
159 | /* setup write pointer to -1 (end of memory) */ | ||
160 | /* bit 0x8000 in address is set to enable 13bit mode */ | ||
161 | sp887x_writereg(state, 0x8f08, 0x1fff); | ||
162 | |||
163 | /* dummy write (wrap around to start of memory) */ | ||
164 | sp887x_writereg(state, 0x8f0a, 0x0000); | ||
165 | |||
166 | for (i = 0; i < FW_SIZE; i += BLOCKSIZE) { | ||
167 | int c = BLOCKSIZE; | ||
168 | int err; | ||
169 | |||
170 | if (i+c > FW_SIZE) | ||
171 | c = FW_SIZE - i; | ||
172 | |||
173 | /* bit 0x8000 in address is set to enable 13bit mode */ | ||
174 | /* bit 0x4000 enables multibyte read/write transfers */ | ||
175 | /* write register is 0xf0a */ | ||
176 | buf[0] = 0xcf; | ||
177 | buf[1] = 0x0a; | ||
178 | |||
179 | memcpy(&buf[2], mem + i, c); | ||
180 | |||
181 | if ((err = i2c_writebytes (state, buf, c+2)) < 0) { | ||
182 | printk ("failed.\n"); | ||
183 | printk ("%s: i2c error (err == %i)\n", __FUNCTION__, err); | ||
184 | return err; | ||
185 | } | ||
186 | } | ||
187 | |||
188 | /* don't write RS bytes between packets */ | ||
189 | sp887x_writereg(state, 0xc13, 0x001); | ||
190 | |||
191 | /* suppress clock if (!data_valid) */ | ||
192 | sp887x_writereg(state, 0xc14, 0x000); | ||
193 | |||
194 | /* setup MPEG interface... */ | ||
195 | sp887x_writereg(state, 0xc1a, 0x872); | ||
196 | sp887x_writereg(state, 0xc1b, 0x001); | ||
197 | sp887x_writereg(state, 0xc1c, 0x000); /* parallel mode (serial mode == 1) */ | ||
198 | sp887x_writereg(state, 0xc1a, 0x871); | ||
199 | |||
200 | /* ADC mode, 2 for MT8872, 3 for SP8870/SP8871 */ | ||
201 | sp887x_writereg(state, 0x301, 0x002); | ||
202 | |||
203 | sp887x_setup_agc(state); | ||
204 | |||
205 | /* bit 0x010: enable data valid signal */ | ||
206 | sp887x_writereg(state, 0xd00, 0x010); | ||
207 | sp887x_writereg(state, 0x0d1, 0x000); | ||
208 | |||
209 | /* setup the PLL */ | ||
210 | if (state->config->pll_init) { | ||
211 | sp887x_writereg(state, 0x206, 0x001); | ||
212 | state->config->pll_init(fe); | ||
213 | sp887x_writereg(state, 0x206, 0x000); | ||
214 | } | ||
215 | |||
216 | printk ("done.\n"); | ||
217 | return 0; | ||
218 | }; | ||
219 | |||
220 | static int configure_reg0xc05 (struct dvb_frontend_parameters *p, u16 *reg0xc05) | ||
221 | { | ||
222 | int known_parameters = 1; | ||
223 | |||
224 | *reg0xc05 = 0x000; | ||
225 | |||
226 | switch (p->u.ofdm.constellation) { | ||
227 | case QPSK: | ||
228 | break; | ||
229 | case QAM_16: | ||
230 | *reg0xc05 |= (1 << 10); | ||
231 | break; | ||
232 | case QAM_64: | ||
233 | *reg0xc05 |= (2 << 10); | ||
234 | break; | ||
235 | case QAM_AUTO: | ||
236 | known_parameters = 0; | ||
237 | break; | ||
238 | default: | ||
239 | return -EINVAL; | ||
240 | }; | ||
241 | |||
242 | switch (p->u.ofdm.hierarchy_information) { | ||
243 | case HIERARCHY_NONE: | ||
244 | break; | ||
245 | case HIERARCHY_1: | ||
246 | *reg0xc05 |= (1 << 7); | ||
247 | break; | ||
248 | case HIERARCHY_2: | ||
249 | *reg0xc05 |= (2 << 7); | ||
250 | break; | ||
251 | case HIERARCHY_4: | ||
252 | *reg0xc05 |= (3 << 7); | ||
253 | break; | ||
254 | case HIERARCHY_AUTO: | ||
255 | known_parameters = 0; | ||
256 | break; | ||
257 | default: | ||
258 | return -EINVAL; | ||
259 | }; | ||
260 | |||
261 | switch (p->u.ofdm.code_rate_HP) { | ||
262 | case FEC_1_2: | ||
263 | break; | ||
264 | case FEC_2_3: | ||
265 | *reg0xc05 |= (1 << 3); | ||
266 | break; | ||
267 | case FEC_3_4: | ||
268 | *reg0xc05 |= (2 << 3); | ||
269 | break; | ||
270 | case FEC_5_6: | ||
271 | *reg0xc05 |= (3 << 3); | ||
272 | break; | ||
273 | case FEC_7_8: | ||
274 | *reg0xc05 |= (4 << 3); | ||
275 | break; | ||
276 | case FEC_AUTO: | ||
277 | known_parameters = 0; | ||
278 | break; | ||
279 | default: | ||
280 | return -EINVAL; | ||
281 | }; | ||
282 | |||
283 | if (known_parameters) | ||
284 | *reg0xc05 |= (2 << 1); /* use specified parameters */ | ||
285 | else | ||
286 | *reg0xc05 |= (1 << 1); /* enable autoprobing */ | ||
287 | |||
288 | return 0; | ||
289 | } | ||
290 | |||
291 | /** | ||
292 | * estimates division of two 24bit numbers, | ||
293 | * derived from the ves1820/stv0299 driver code | ||
294 | */ | ||
295 | static void divide (int n, int d, int *quotient_i, int *quotient_f) | ||
296 | { | ||
297 | unsigned int q, r; | ||
298 | |||
299 | r = (n % d) << 8; | ||
300 | q = (r / d); | ||
301 | |||
302 | if (quotient_i) | ||
303 | *quotient_i = q; | ||
304 | |||
305 | if (quotient_f) { | ||
306 | r = (r % d) << 8; | ||
307 | q = (q << 8) | (r / d); | ||
308 | r = (r % d) << 8; | ||
309 | *quotient_f = (q << 8) | (r / d); | ||
310 | } | ||
311 | } | ||
312 | |||
313 | static void sp887x_correct_offsets (struct sp887x_state* state, | ||
314 | struct dvb_frontend_parameters *p, | ||
315 | int actual_freq) | ||
316 | { | ||
317 | static const u32 srate_correction [] = { 1879617, 4544878, 8098561 }; | ||
318 | int bw_index = p->u.ofdm.bandwidth - BANDWIDTH_8_MHZ; | ||
319 | int freq_offset = actual_freq - p->frequency; | ||
320 | int sysclock = 61003; //[kHz] | ||
321 | int ifreq = 36000000; | ||
322 | int freq; | ||
323 | int frequency_shift; | ||
324 | |||
325 | if (p->inversion == INVERSION_ON) | ||
326 | freq = ifreq - freq_offset; | ||
327 | else | ||
328 | freq = ifreq + freq_offset; | ||
329 | |||
330 | divide(freq / 333, sysclock, NULL, &frequency_shift); | ||
331 | |||
332 | if (p->inversion == INVERSION_ON) | ||
333 | frequency_shift = -frequency_shift; | ||
334 | |||
335 | /* sample rate correction */ | ||
336 | sp887x_writereg(state, 0x319, srate_correction[bw_index] >> 12); | ||
337 | sp887x_writereg(state, 0x31a, srate_correction[bw_index] & 0xfff); | ||
338 | |||
339 | /* carrier offset correction */ | ||
340 | sp887x_writereg(state, 0x309, frequency_shift >> 12); | ||
341 | sp887x_writereg(state, 0x30a, frequency_shift & 0xfff); | ||
342 | } | ||
343 | |||
344 | static int sp887x_setup_frontend_parameters (struct dvb_frontend* fe, | ||
345 | struct dvb_frontend_parameters *p) | ||
346 | { | ||
347 | struct sp887x_state* state = (struct sp887x_state*) fe->demodulator_priv; | ||
348 | int actual_freq, err; | ||
349 | u16 val, reg0xc05; | ||
350 | |||
351 | if (p->u.ofdm.bandwidth != BANDWIDTH_8_MHZ && | ||
352 | p->u.ofdm.bandwidth != BANDWIDTH_7_MHZ && | ||
353 | p->u.ofdm.bandwidth != BANDWIDTH_6_MHZ) | ||
354 | return -EINVAL; | ||
355 | |||
356 | if ((err = configure_reg0xc05(p, ®0xc05))) | ||
357 | return err; | ||
358 | |||
359 | sp887x_microcontroller_stop(state); | ||
360 | |||
361 | /* setup the PLL */ | ||
362 | sp887x_writereg(state, 0x206, 0x001); | ||
363 | actual_freq = state->config->pll_set(fe, p); | ||
364 | sp887x_writereg(state, 0x206, 0x000); | ||
365 | |||
366 | /* read status reg in order to clear <pending irqs */ | ||
367 | sp887x_readreg(state, 0x200); | ||
368 | |||
369 | sp887x_correct_offsets(state, p, actual_freq); | ||
370 | |||
371 | /* filter for 6/7/8 Mhz channel */ | ||
372 | if (p->u.ofdm.bandwidth == BANDWIDTH_6_MHZ) | ||
373 | val = 2; | ||
374 | else if (p->u.ofdm.bandwidth == BANDWIDTH_7_MHZ) | ||
375 | val = 1; | ||
376 | else | ||
377 | val = 0; | ||
378 | |||
379 | sp887x_writereg(state, 0x311, val); | ||
380 | |||
381 | /* scan order: 2k first = 0, 8k first = 1 */ | ||
382 | if (p->u.ofdm.transmission_mode == TRANSMISSION_MODE_2K) | ||
383 | sp887x_writereg(state, 0x338, 0x000); | ||
384 | else | ||
385 | sp887x_writereg(state, 0x338, 0x001); | ||
386 | |||
387 | sp887x_writereg(state, 0xc05, reg0xc05); | ||
388 | |||
389 | if (p->u.ofdm.bandwidth == BANDWIDTH_6_MHZ) | ||
390 | val = 2 << 3; | ||
391 | else if (p->u.ofdm.bandwidth == BANDWIDTH_7_MHZ) | ||
392 | val = 3 << 3; | ||
393 | else | ||
394 | val = 0 << 3; | ||
395 | |||
396 | /* enable OFDM and SAW bits as lock indicators in sync register 0xf17, | ||
397 | * optimize algorithm for given bandwidth... | ||
398 | */ | ||
399 | sp887x_writereg(state, 0xf14, 0x160 | val); | ||
400 | sp887x_writereg(state, 0xf15, 0x000); | ||
401 | |||
402 | sp887x_microcontroller_start(state); | ||
403 | return 0; | ||
404 | } | ||
405 | |||
406 | static int sp887x_read_status(struct dvb_frontend* fe, fe_status_t* status) | ||
407 | { | ||
408 | struct sp887x_state* state = (struct sp887x_state*) fe->demodulator_priv; | ||
409 | u16 snr12 = sp887x_readreg(state, 0xf16); | ||
410 | u16 sync0x200 = sp887x_readreg(state, 0x200); | ||
411 | u16 sync0xf17 = sp887x_readreg(state, 0xf17); | ||
412 | |||
413 | *status = 0; | ||
414 | |||
415 | if (snr12 > 0x00f) | ||
416 | *status |= FE_HAS_SIGNAL; | ||
417 | |||
418 | //if (sync0x200 & 0x004) | ||
419 | // *status |= FE_HAS_SYNC | FE_HAS_CARRIER; | ||
420 | |||
421 | //if (sync0x200 & 0x008) | ||
422 | // *status |= FE_HAS_VITERBI; | ||
423 | |||
424 | if ((sync0xf17 & 0x00f) == 0x002) { | ||
425 | *status |= FE_HAS_LOCK; | ||
426 | *status |= FE_HAS_VITERBI | FE_HAS_SYNC | FE_HAS_CARRIER; | ||
427 | } | ||
428 | |||
429 | if (sync0x200 & 0x001) { /* tuner adjustment requested...*/ | ||
430 | int steps = (sync0x200 >> 4) & 0x00f; | ||
431 | if (steps & 0x008) | ||
432 | steps = -steps; | ||
433 | dprintk("sp887x: implement tuner adjustment (%+i steps)!!\n", | ||
434 | steps); | ||
435 | } | ||
436 | |||
437 | return 0; | ||
438 | } | ||
439 | |||
440 | static int sp887x_read_ber(struct dvb_frontend* fe, u32* ber) | ||
441 | { | ||
442 | struct sp887x_state* state = (struct sp887x_state*) fe->demodulator_priv; | ||
443 | |||
444 | *ber = (sp887x_readreg(state, 0xc08) & 0x3f) | | ||
445 | (sp887x_readreg(state, 0xc07) << 6); | ||
446 | sp887x_writereg(state, 0xc08, 0x000); | ||
447 | sp887x_writereg(state, 0xc07, 0x000); | ||
448 | if (*ber >= 0x3fff0) | ||
449 | *ber = ~0; | ||
450 | |||
451 | return 0; | ||
452 | } | ||
453 | |||
454 | static int sp887x_read_signal_strength(struct dvb_frontend* fe, u16* strength) | ||
455 | { | ||
456 | struct sp887x_state* state = (struct sp887x_state*) fe->demodulator_priv; | ||
457 | |||
458 | u16 snr12 = sp887x_readreg(state, 0xf16); | ||
459 | u32 signal = 3 * (snr12 << 4); | ||
460 | *strength = (signal < 0xffff) ? signal : 0xffff; | ||
461 | |||
462 | return 0; | ||
463 | } | ||
464 | |||
465 | static int sp887x_read_snr(struct dvb_frontend* fe, u16* snr) | ||
466 | { | ||
467 | struct sp887x_state* state = (struct sp887x_state*) fe->demodulator_priv; | ||
468 | |||
469 | u16 snr12 = sp887x_readreg(state, 0xf16); | ||
470 | *snr = (snr12 << 4) | (snr12 >> 8); | ||
471 | |||
472 | return 0; | ||
473 | } | ||
474 | |||
475 | static int sp887x_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks) | ||
476 | { | ||
477 | struct sp887x_state* state = (struct sp887x_state*) fe->demodulator_priv; | ||
478 | |||
479 | *ucblocks = sp887x_readreg(state, 0xc0c); | ||
480 | if (*ucblocks == 0xfff) | ||
481 | *ucblocks = ~0; | ||
482 | |||
483 | return 0; | ||
484 | } | ||
485 | |||
486 | static int sp887x_sleep(struct dvb_frontend* fe) | ||
487 | { | ||
488 | struct sp887x_state* state = (struct sp887x_state*) fe->demodulator_priv; | ||
489 | |||
490 | /* tristate TS output and disable interface pins */ | ||
491 | sp887x_writereg(state, 0xc18, 0x000); | ||
492 | |||
493 | return 0; | ||
494 | } | ||
495 | |||
496 | static int sp887x_init(struct dvb_frontend* fe) | ||
497 | { | ||
498 | struct sp887x_state* state = (struct sp887x_state*) fe->demodulator_priv; | ||
499 | const struct firmware *fw = NULL; | ||
500 | int ret; | ||
501 | |||
502 | if (!state->initialised) { | ||
503 | /* request the firmware, this will block until someone uploads it */ | ||
504 | printk("sp887x: waiting for firmware upload (%s)...\n", SP887X_DEFAULT_FIRMWARE); | ||
505 | ret = state->config->request_firmware(fe, &fw, SP887X_DEFAULT_FIRMWARE); | ||
506 | if (ret) { | ||
507 | printk("sp887x: no firmware upload (timeout or file not found?)\n"); | ||
508 | return ret; | ||
509 | } | ||
510 | |||
511 | ret = sp887x_initial_setup(fe, fw); | ||
512 | if (ret) { | ||
513 | printk("sp887x: writing firmware to device failed\n"); | ||
514 | release_firmware(fw); | ||
515 | return ret; | ||
516 | } | ||
517 | printk("sp887x: firmware upload complete\n"); | ||
518 | state->initialised = 1; | ||
519 | } | ||
520 | |||
521 | /* enable TS output and interface pins */ | ||
522 | sp887x_writereg(state, 0xc18, 0x00d); | ||
523 | |||
524 | return 0; | ||
525 | } | ||
526 | |||
527 | static int sp887x_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings* fesettings) | ||
528 | { | ||
529 | fesettings->min_delay_ms = 350; | ||
530 | fesettings->step_size = 166666*2; | ||
531 | fesettings->max_drift = (166666*2)+1; | ||
532 | return 0; | ||
533 | } | ||
534 | |||
535 | static void sp887x_release(struct dvb_frontend* fe) | ||
536 | { | ||
537 | struct sp887x_state* state = (struct sp887x_state*) fe->demodulator_priv; | ||
538 | kfree(state); | ||
539 | } | ||
540 | |||
541 | static struct dvb_frontend_ops sp887x_ops; | ||
542 | |||
543 | struct dvb_frontend* sp887x_attach(const struct sp887x_config* config, | ||
544 | struct i2c_adapter* i2c) | ||
545 | { | ||
546 | struct sp887x_state* state = NULL; | ||
547 | |||
548 | /* allocate memory for the internal state */ | ||
549 | state = (struct sp887x_state*) kmalloc(sizeof(struct sp887x_state), GFP_KERNEL); | ||
550 | if (state == NULL) goto error; | ||
551 | |||
552 | /* setup the state */ | ||
553 | state->config = config; | ||
554 | state->i2c = i2c; | ||
555 | memcpy(&state->ops, &sp887x_ops, sizeof(struct dvb_frontend_ops)); | ||
556 | state->initialised = 0; | ||
557 | |||
558 | /* check if the demod is there */ | ||
559 | if (sp887x_readreg(state, 0x0200) < 0) goto error; | ||
560 | |||
561 | /* create dvb_frontend */ | ||
562 | state->frontend.ops = &state->ops; | ||
563 | state->frontend.demodulator_priv = state; | ||
564 | return &state->frontend; | ||
565 | |||
566 | error: | ||
567 | kfree(state); | ||
568 | return NULL; | ||
569 | } | ||
570 | |||
571 | static struct dvb_frontend_ops sp887x_ops = { | ||
572 | |||
573 | .info = { | ||
574 | .name = "Spase SP887x DVB-T", | ||
575 | .type = FE_OFDM, | ||
576 | .frequency_min = 50500000, | ||
577 | .frequency_max = 858000000, | ||
578 | .frequency_stepsize = 166666, | ||
579 | .caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | | ||
580 | FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO | | ||
581 | FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | | ||
582 | FE_CAN_RECOVER | ||
583 | }, | ||
584 | |||
585 | .release = sp887x_release, | ||
586 | |||
587 | .init = sp887x_init, | ||
588 | .sleep = sp887x_sleep, | ||
589 | |||
590 | .set_frontend = sp887x_setup_frontend_parameters, | ||
591 | .get_tune_settings = sp887x_get_tune_settings, | ||
592 | |||
593 | .read_status = sp887x_read_status, | ||
594 | .read_ber = sp887x_read_ber, | ||
595 | .read_signal_strength = sp887x_read_signal_strength, | ||
596 | .read_snr = sp887x_read_snr, | ||
597 | .read_ucblocks = sp887x_read_ucblocks, | ||
598 | }; | ||
599 | |||
600 | module_param(debug, int, 0644); | ||
601 | MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off)."); | ||
602 | |||
603 | MODULE_DESCRIPTION("Spase sp887x DVB-T demodulator driver"); | ||
604 | MODULE_LICENSE("GPL"); | ||
605 | |||
606 | EXPORT_SYMBOL(sp887x_attach); | ||
diff --git a/drivers/media/dvb/frontends/sp887x.h b/drivers/media/dvb/frontends/sp887x.h new file mode 100644 index 000000000000..6a05d8f8e8cc --- /dev/null +++ b/drivers/media/dvb/frontends/sp887x.h | |||
@@ -0,0 +1,29 @@ | |||
1 | /* | ||
2 | Driver for the Spase sp887x demodulator | ||
3 | */ | ||
4 | |||
5 | #ifndef SP887X_H | ||
6 | #define SP887X_H | ||
7 | |||
8 | #include <linux/dvb/frontend.h> | ||
9 | #include <linux/firmware.h> | ||
10 | |||
11 | struct sp887x_config | ||
12 | { | ||
13 | /* the demodulator's i2c address */ | ||
14 | u8 demod_address; | ||
15 | |||
16 | /* PLL maintenance */ | ||
17 | int (*pll_init)(struct dvb_frontend* fe); | ||
18 | |||
19 | /* this should return the actual frequency tuned to */ | ||
20 | int (*pll_set)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params); | ||
21 | |||
22 | /* request firmware for device */ | ||
23 | int (*request_firmware)(struct dvb_frontend* fe, const struct firmware **fw, char* name); | ||
24 | }; | ||
25 | |||
26 | extern struct dvb_frontend* sp887x_attach(const struct sp887x_config* config, | ||
27 | struct i2c_adapter* i2c); | ||
28 | |||
29 | #endif // SP887X_H | ||
diff --git a/drivers/media/dvb/frontends/stv0297.c b/drivers/media/dvb/frontends/stv0297.c new file mode 100644 index 000000000000..502c6403dfc6 --- /dev/null +++ b/drivers/media/dvb/frontends/stv0297.c | |||
@@ -0,0 +1,798 @@ | |||
1 | /* | ||
2 | Driver for STV0297 demodulator | ||
3 | |||
4 | Copyright (C) 2004 Andrew de Quincey <adq_dvb@lidskialf.net> | ||
5 | Copyright (C) 2003-2004 Dennis Noermann <dennis.noermann@noernet.de> | ||
6 | |||
7 | This program is free software; you can redistribute it and/or modify | ||
8 | it under the terms of the GNU General Public License as published by | ||
9 | the Free Software Foundation; either version 2 of the License, or | ||
10 | (at your option) any later version. | ||
11 | |||
12 | This program is distributed in the hope that it will be useful, | ||
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | GNU General Public License for more details. | ||
16 | |||
17 | You should have received a copy of the GNU General Public License | ||
18 | along with this program; if not, write to the Free Software | ||
19 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
20 | */ | ||
21 | |||
22 | #include <linux/init.h> | ||
23 | #include <linux/kernel.h> | ||
24 | #include <linux/module.h> | ||
25 | #include <linux/string.h> | ||
26 | #include <linux/delay.h> | ||
27 | |||
28 | #include "dvb_frontend.h" | ||
29 | #include "stv0297.h" | ||
30 | |||
31 | struct stv0297_state { | ||
32 | struct i2c_adapter *i2c; | ||
33 | struct dvb_frontend_ops ops; | ||
34 | const struct stv0297_config *config; | ||
35 | struct dvb_frontend frontend; | ||
36 | |||
37 | unsigned long base_freq; | ||
38 | u8 pwm; | ||
39 | }; | ||
40 | |||
41 | #if 1 | ||
42 | #define dprintk(x...) printk(x) | ||
43 | #else | ||
44 | #define dprintk(x...) | ||
45 | #endif | ||
46 | |||
47 | #define STV0297_CLOCK_KHZ 28900 | ||
48 | |||
49 | static u8 init_tab[] = { | ||
50 | 0x00, 0x09, | ||
51 | 0x01, 0x69, | ||
52 | 0x03, 0x00, | ||
53 | 0x04, 0x00, | ||
54 | 0x07, 0x00, | ||
55 | 0x08, 0x00, | ||
56 | 0x20, 0x00, | ||
57 | 0x21, 0x40, | ||
58 | 0x22, 0x00, | ||
59 | 0x23, 0x00, | ||
60 | 0x24, 0x40, | ||
61 | 0x25, 0x88, | ||
62 | 0x30, 0xff, | ||
63 | 0x31, 0x00, | ||
64 | 0x32, 0xff, | ||
65 | 0x33, 0x00, | ||
66 | 0x34, 0x50, | ||
67 | 0x35, 0x7f, | ||
68 | 0x36, 0x00, | ||
69 | 0x37, 0x20, | ||
70 | 0x38, 0x00, | ||
71 | 0x40, 0x1c, | ||
72 | 0x41, 0xff, | ||
73 | 0x42, 0x29, | ||
74 | 0x43, 0x00, | ||
75 | 0x44, 0xff, | ||
76 | 0x45, 0x00, | ||
77 | 0x46, 0x00, | ||
78 | 0x49, 0x04, | ||
79 | 0x4a, 0xff, | ||
80 | 0x4b, 0x7f, | ||
81 | 0x52, 0x30, | ||
82 | 0x55, 0xae, | ||
83 | 0x56, 0x47, | ||
84 | 0x57, 0xe1, | ||
85 | 0x58, 0x3a, | ||
86 | 0x5a, 0x1e, | ||
87 | 0x5b, 0x34, | ||
88 | 0x60, 0x00, | ||
89 | 0x63, 0x00, | ||
90 | 0x64, 0x00, | ||
91 | 0x65, 0x00, | ||
92 | 0x66, 0x00, | ||
93 | 0x67, 0x00, | ||
94 | 0x68, 0x00, | ||
95 | 0x69, 0x00, | ||
96 | 0x6a, 0x02, | ||
97 | 0x6b, 0x00, | ||
98 | 0x70, 0xff, | ||
99 | 0x71, 0x00, | ||
100 | 0x72, 0x00, | ||
101 | 0x73, 0x00, | ||
102 | 0x74, 0x0c, | ||
103 | 0x80, 0x00, | ||
104 | 0x81, 0x00, | ||
105 | 0x82, 0x00, | ||
106 | 0x83, 0x00, | ||
107 | 0x84, 0x04, | ||
108 | 0x85, 0x80, | ||
109 | 0x86, 0x24, | ||
110 | 0x87, 0x78, | ||
111 | 0x88, 0x00, | ||
112 | 0x89, 0x00, | ||
113 | 0x90, 0x01, | ||
114 | 0x91, 0x01, | ||
115 | 0xa0, 0x00, | ||
116 | 0xa1, 0x00, | ||
117 | 0xa2, 0x00, | ||
118 | 0xb0, 0x91, | ||
119 | 0xb1, 0x0b, | ||
120 | 0xc0, 0x53, | ||
121 | 0xc1, 0x70, | ||
122 | 0xc2, 0x12, | ||
123 | 0xd0, 0x00, | ||
124 | 0xd1, 0x00, | ||
125 | 0xd2, 0x00, | ||
126 | 0xd3, 0x00, | ||
127 | 0xd4, 0x00, | ||
128 | 0xd5, 0x00, | ||
129 | 0xde, 0x00, | ||
130 | 0xdf, 0x00, | ||
131 | 0x61, 0x49, | ||
132 | 0x62, 0x0b, | ||
133 | 0x53, 0x08, | ||
134 | 0x59, 0x08, | ||
135 | }; | ||
136 | |||
137 | |||
138 | static int stv0297_writereg(struct stv0297_state *state, u8 reg, u8 data) | ||
139 | { | ||
140 | int ret; | ||
141 | u8 buf[] = { reg, data }; | ||
142 | struct i2c_msg msg = {.addr = state->config->demod_address,.flags = 0,.buf = buf,.len = 2 }; | ||
143 | |||
144 | ret = i2c_transfer(state->i2c, &msg, 1); | ||
145 | |||
146 | if (ret != 1) | ||
147 | dprintk("%s: writereg error (reg == 0x%02x, val == 0x%02x, " | ||
148 | "ret == %i)\n", __FUNCTION__, reg, data, ret); | ||
149 | |||
150 | return (ret != 1) ? -1 : 0; | ||
151 | } | ||
152 | |||
153 | static int stv0297_readreg(struct stv0297_state *state, u8 reg) | ||
154 | { | ||
155 | int ret; | ||
156 | u8 b0[] = { reg }; | ||
157 | u8 b1[] = { 0 }; | ||
158 | struct i2c_msg msg[] = { {.addr = state->config->demod_address,.flags = 0,.buf = b0,.len = | ||
159 | 1}, | ||
160 | {.addr = state->config->demod_address,.flags = I2C_M_RD,.buf = b1,.len = 1} | ||
161 | }; | ||
162 | |||
163 | // this device needs a STOP between the register and data | ||
164 | if ((ret = i2c_transfer(state->i2c, &msg[0], 1)) != 1) { | ||
165 | dprintk("%s: readreg error (reg == 0x%02x, ret == %i)\n", __FUNCTION__, reg, ret); | ||
166 | return -1; | ||
167 | } | ||
168 | if ((ret = i2c_transfer(state->i2c, &msg[1], 1)) != 1) { | ||
169 | dprintk("%s: readreg error (reg == 0x%02x, ret == %i)\n", __FUNCTION__, reg, ret); | ||
170 | return -1; | ||
171 | } | ||
172 | |||
173 | return b1[0]; | ||
174 | } | ||
175 | |||
176 | static int stv0297_writereg_mask(struct stv0297_state *state, u8 reg, u8 mask, u8 data) | ||
177 | { | ||
178 | int val; | ||
179 | |||
180 | val = stv0297_readreg(state, reg); | ||
181 | val &= ~mask; | ||
182 | val |= (data & mask); | ||
183 | stv0297_writereg(state, reg, val); | ||
184 | |||
185 | return 0; | ||
186 | } | ||
187 | |||
188 | static int stv0297_readregs(struct stv0297_state *state, u8 reg1, u8 * b, u8 len) | ||
189 | { | ||
190 | int ret; | ||
191 | struct i2c_msg msg[] = { {.addr = state->config->demod_address,.flags = 0,.buf = | ||
192 | ®1,.len = 1}, | ||
193 | {.addr = state->config->demod_address,.flags = I2C_M_RD,.buf = b,.len = len} | ||
194 | }; | ||
195 | |||
196 | // this device needs a STOP between the register and data | ||
197 | if ((ret = i2c_transfer(state->i2c, &msg[0], 1)) != 1) { | ||
198 | dprintk("%s: readreg error (reg == 0x%02x, ret == %i)\n", __FUNCTION__, reg1, ret); | ||
199 | return -1; | ||
200 | } | ||
201 | if ((ret = i2c_transfer(state->i2c, &msg[1], 1)) != 1) { | ||
202 | dprintk("%s: readreg error (reg == 0x%02x, ret == %i)\n", __FUNCTION__, reg1, ret); | ||
203 | return -1; | ||
204 | } | ||
205 | |||
206 | return 0; | ||
207 | } | ||
208 | |||
209 | static u32 stv0297_get_symbolrate(struct stv0297_state *state) | ||
210 | { | ||
211 | u64 tmp; | ||
212 | |||
213 | tmp = stv0297_readreg(state, 0x55); | ||
214 | tmp |= stv0297_readreg(state, 0x56) << 8; | ||
215 | tmp |= stv0297_readreg(state, 0x57) << 16; | ||
216 | tmp |= stv0297_readreg(state, 0x58) << 24; | ||
217 | |||
218 | tmp *= STV0297_CLOCK_KHZ; | ||
219 | tmp >>= 32; | ||
220 | |||
221 | return (u32) tmp; | ||
222 | } | ||
223 | |||
224 | static void stv0297_set_symbolrate(struct stv0297_state *state, u32 srate) | ||
225 | { | ||
226 | long tmp; | ||
227 | |||
228 | tmp = 131072L * srate; /* 131072 = 2^17 */ | ||
229 | tmp = tmp / (STV0297_CLOCK_KHZ / 4); /* 1/4 = 2^-2 */ | ||
230 | tmp = tmp * 8192L; /* 8192 = 2^13 */ | ||
231 | |||
232 | stv0297_writereg(state, 0x55, (unsigned char) (tmp & 0xFF)); | ||
233 | stv0297_writereg(state, 0x56, (unsigned char) (tmp >> 8)); | ||
234 | stv0297_writereg(state, 0x57, (unsigned char) (tmp >> 16)); | ||
235 | stv0297_writereg(state, 0x58, (unsigned char) (tmp >> 24)); | ||
236 | } | ||
237 | |||
238 | static void stv0297_set_sweeprate(struct stv0297_state *state, short fshift, long symrate) | ||
239 | { | ||
240 | long tmp; | ||
241 | |||
242 | tmp = (long) fshift *262144L; /* 262144 = 2*18 */ | ||
243 | tmp /= symrate; | ||
244 | tmp *= 1024; /* 1024 = 2*10 */ | ||
245 | |||
246 | // adjust | ||
247 | if (tmp >= 0) { | ||
248 | tmp += 500000; | ||
249 | } else { | ||
250 | tmp -= 500000; | ||
251 | } | ||
252 | tmp /= 1000000; | ||
253 | |||
254 | stv0297_writereg(state, 0x60, tmp & 0xFF); | ||
255 | stv0297_writereg_mask(state, 0x69, 0xF0, (tmp >> 4) & 0xf0); | ||
256 | } | ||
257 | |||
258 | static void stv0297_set_carrieroffset(struct stv0297_state *state, long offset) | ||
259 | { | ||
260 | long tmp; | ||
261 | |||
262 | /* symrate is hardcoded to 10000 */ | ||
263 | tmp = offset * 26844L; /* (2**28)/10000 */ | ||
264 | if (tmp < 0) | ||
265 | tmp += 0x10000000; | ||
266 | tmp &= 0x0FFFFFFF; | ||
267 | |||
268 | stv0297_writereg(state, 0x66, (unsigned char) (tmp & 0xFF)); | ||
269 | stv0297_writereg(state, 0x67, (unsigned char) (tmp >> 8)); | ||
270 | stv0297_writereg(state, 0x68, (unsigned char) (tmp >> 16)); | ||
271 | stv0297_writereg_mask(state, 0x69, 0x0F, (tmp >> 24) & 0x0f); | ||
272 | } | ||
273 | |||
274 | /* | ||
275 | static long stv0297_get_carrieroffset(struct stv0297_state *state) | ||
276 | { | ||
277 | s64 tmp; | ||
278 | |||
279 | stv0297_writereg(state, 0x6B, 0x00); | ||
280 | |||
281 | tmp = stv0297_readreg(state, 0x66); | ||
282 | tmp |= (stv0297_readreg(state, 0x67) << 8); | ||
283 | tmp |= (stv0297_readreg(state, 0x68) << 16); | ||
284 | tmp |= (stv0297_readreg(state, 0x69) & 0x0F) << 24; | ||
285 | |||
286 | tmp *= stv0297_get_symbolrate(state); | ||
287 | tmp >>= 28; | ||
288 | |||
289 | return (s32) tmp; | ||
290 | } | ||
291 | */ | ||
292 | |||
293 | static void stv0297_set_initialdemodfreq(struct stv0297_state *state, long freq) | ||
294 | { | ||
295 | s32 tmp; | ||
296 | |||
297 | if (freq > 10000) | ||
298 | freq -= STV0297_CLOCK_KHZ; | ||
299 | |||
300 | tmp = (STV0297_CLOCK_KHZ * 1000) / (1 << 16); | ||
301 | tmp = (freq * 1000) / tmp; | ||
302 | if (tmp > 0xffff) | ||
303 | tmp = 0xffff; | ||
304 | |||
305 | stv0297_writereg_mask(state, 0x25, 0x80, 0x80); | ||
306 | stv0297_writereg(state, 0x21, tmp >> 8); | ||
307 | stv0297_writereg(state, 0x20, tmp); | ||
308 | } | ||
309 | |||
310 | static int stv0297_set_qam(struct stv0297_state *state, fe_modulation_t modulation) | ||
311 | { | ||
312 | int val = 0; | ||
313 | |||
314 | switch (modulation) { | ||
315 | case QAM_16: | ||
316 | val = 0; | ||
317 | break; | ||
318 | |||
319 | case QAM_32: | ||
320 | val = 1; | ||
321 | break; | ||
322 | |||
323 | case QAM_64: | ||
324 | val = 4; | ||
325 | break; | ||
326 | |||
327 | case QAM_128: | ||
328 | val = 2; | ||
329 | break; | ||
330 | |||
331 | case QAM_256: | ||
332 | val = 3; | ||
333 | break; | ||
334 | |||
335 | default: | ||
336 | return -EINVAL; | ||
337 | } | ||
338 | |||
339 | stv0297_writereg_mask(state, 0x00, 0x70, val << 4); | ||
340 | |||
341 | return 0; | ||
342 | } | ||
343 | |||
344 | static int stv0297_set_inversion(struct stv0297_state *state, fe_spectral_inversion_t inversion) | ||
345 | { | ||
346 | int val = 0; | ||
347 | |||
348 | switch (inversion) { | ||
349 | case INVERSION_OFF: | ||
350 | val = 0; | ||
351 | break; | ||
352 | |||
353 | case INVERSION_ON: | ||
354 | val = 1; | ||
355 | break; | ||
356 | |||
357 | default: | ||
358 | return -EINVAL; | ||
359 | } | ||
360 | |||
361 | stv0297_writereg_mask(state, 0x83, 0x08, val << 3); | ||
362 | |||
363 | return 0; | ||
364 | } | ||
365 | |||
366 | int stv0297_enable_plli2c(struct dvb_frontend *fe) | ||
367 | { | ||
368 | struct stv0297_state *state = (struct stv0297_state *) fe->demodulator_priv; | ||
369 | |||
370 | stv0297_writereg(state, 0x87, 0x78); | ||
371 | stv0297_writereg(state, 0x86, 0xc8); | ||
372 | |||
373 | return 0; | ||
374 | } | ||
375 | |||
376 | static int stv0297_init(struct dvb_frontend *fe) | ||
377 | { | ||
378 | struct stv0297_state *state = (struct stv0297_state *) fe->demodulator_priv; | ||
379 | int i; | ||
380 | |||
381 | /* soft reset */ | ||
382 | stv0297_writereg_mask(state, 0x80, 1, 1); | ||
383 | stv0297_writereg_mask(state, 0x80, 1, 0); | ||
384 | |||
385 | /* reset deinterleaver */ | ||
386 | stv0297_writereg_mask(state, 0x81, 1, 1); | ||
387 | stv0297_writereg_mask(state, 0x81, 1, 0); | ||
388 | |||
389 | /* load init table */ | ||
390 | for (i = 0; i < sizeof(init_tab); i += 2) { | ||
391 | stv0297_writereg(state, init_tab[i], init_tab[i + 1]); | ||
392 | } | ||
393 | |||
394 | /* set a dummy symbol rate */ | ||
395 | stv0297_set_symbolrate(state, 6900); | ||
396 | |||
397 | /* invert AGC1 polarity */ | ||
398 | stv0297_writereg_mask(state, 0x88, 0x10, 0x10); | ||
399 | |||
400 | /* setup bit error counting */ | ||
401 | stv0297_writereg_mask(state, 0xA0, 0x80, 0x00); | ||
402 | stv0297_writereg_mask(state, 0xA0, 0x10, 0x00); | ||
403 | stv0297_writereg_mask(state, 0xA0, 0x08, 0x00); | ||
404 | stv0297_writereg_mask(state, 0xA0, 0x07, 0x04); | ||
405 | |||
406 | /* min + max PWM */ | ||
407 | stv0297_writereg(state, 0x4a, 0x00); | ||
408 | stv0297_writereg(state, 0x4b, state->pwm); | ||
409 | msleep(200); | ||
410 | |||
411 | if (state->config->pll_init) | ||
412 | state->config->pll_init(fe); | ||
413 | |||
414 | return 0; | ||
415 | } | ||
416 | |||
417 | static int stv0297_sleep(struct dvb_frontend *fe) | ||
418 | { | ||
419 | struct stv0297_state *state = (struct stv0297_state *) fe->demodulator_priv; | ||
420 | |||
421 | stv0297_writereg_mask(state, 0x80, 1, 1); | ||
422 | |||
423 | return 0; | ||
424 | } | ||
425 | |||
426 | static int stv0297_read_status(struct dvb_frontend *fe, fe_status_t * status) | ||
427 | { | ||
428 | struct stv0297_state *state = (struct stv0297_state *) fe->demodulator_priv; | ||
429 | |||
430 | u8 sync = stv0297_readreg(state, 0xDF); | ||
431 | |||
432 | *status = 0; | ||
433 | if (sync & 0x80) | ||
434 | *status |= | ||
435 | FE_HAS_SYNC | FE_HAS_SIGNAL | FE_HAS_CARRIER | FE_HAS_VITERBI | FE_HAS_LOCK; | ||
436 | return 0; | ||
437 | } | ||
438 | |||
439 | static int stv0297_read_ber(struct dvb_frontend *fe, u32 * ber) | ||
440 | { | ||
441 | struct stv0297_state *state = (struct stv0297_state *) fe->demodulator_priv; | ||
442 | u8 BER[3]; | ||
443 | |||
444 | stv0297_writereg(state, 0xA0, 0x80); // Start Counting bit errors for 4096 Bytes | ||
445 | mdelay(25); // Hopefully got 4096 Bytes | ||
446 | stv0297_readregs(state, 0xA0, BER, 3); | ||
447 | mdelay(25); | ||
448 | *ber = (BER[2] << 8 | BER[1]) / (8 * 4096); | ||
449 | |||
450 | return 0; | ||
451 | } | ||
452 | |||
453 | |||
454 | static int stv0297_read_signal_strength(struct dvb_frontend *fe, u16 * strength) | ||
455 | { | ||
456 | struct stv0297_state *state = (struct stv0297_state *) fe->demodulator_priv; | ||
457 | u8 STRENGTH[2]; | ||
458 | |||
459 | stv0297_readregs(state, 0x41, STRENGTH, 2); | ||
460 | *strength = (STRENGTH[1] & 0x03) << 8 | STRENGTH[0]; | ||
461 | |||
462 | return 0; | ||
463 | } | ||
464 | |||
465 | static int stv0297_read_snr(struct dvb_frontend *fe, u16 * snr) | ||
466 | { | ||
467 | struct stv0297_state *state = (struct stv0297_state *) fe->demodulator_priv; | ||
468 | u8 SNR[2]; | ||
469 | |||
470 | stv0297_readregs(state, 0x07, SNR, 2); | ||
471 | *snr = SNR[1] << 8 | SNR[0]; | ||
472 | |||
473 | return 0; | ||
474 | } | ||
475 | |||
476 | static int stv0297_read_ucblocks(struct dvb_frontend *fe, u32 * ucblocks) | ||
477 | { | ||
478 | struct stv0297_state *state = (struct stv0297_state *) fe->demodulator_priv; | ||
479 | |||
480 | *ucblocks = (stv0297_readreg(state, 0xD5) << 8) | ||
481 | | stv0297_readreg(state, 0xD4); | ||
482 | |||
483 | return 0; | ||
484 | } | ||
485 | |||
486 | static int stv0297_set_frontend(struct dvb_frontend *fe, struct dvb_frontend_parameters *p) | ||
487 | { | ||
488 | struct stv0297_state *state = (struct stv0297_state *) fe->demodulator_priv; | ||
489 | int u_threshold; | ||
490 | int initial_u; | ||
491 | int blind_u; | ||
492 | int delay; | ||
493 | int sweeprate; | ||
494 | int carrieroffset; | ||
495 | unsigned long starttime; | ||
496 | unsigned long timeout; | ||
497 | fe_spectral_inversion_t inversion; | ||
498 | |||
499 | switch (p->u.qam.modulation) { | ||
500 | case QAM_16: | ||
501 | case QAM_32: | ||
502 | case QAM_64: | ||
503 | delay = 100; | ||
504 | sweeprate = 1500; | ||
505 | break; | ||
506 | |||
507 | case QAM_128: | ||
508 | delay = 150; | ||
509 | sweeprate = 1000; | ||
510 | break; | ||
511 | |||
512 | case QAM_256: | ||
513 | delay = 200; | ||
514 | sweeprate = 500; | ||
515 | break; | ||
516 | |||
517 | default: | ||
518 | return -EINVAL; | ||
519 | } | ||
520 | |||
521 | // determine inversion dependant parameters | ||
522 | inversion = p->inversion; | ||
523 | if (state->config->invert) | ||
524 | inversion = (inversion == INVERSION_ON) ? INVERSION_OFF : INVERSION_ON; | ||
525 | carrieroffset = -330; | ||
526 | switch (inversion) { | ||
527 | case INVERSION_OFF: | ||
528 | break; | ||
529 | |||
530 | case INVERSION_ON: | ||
531 | sweeprate = -sweeprate; | ||
532 | carrieroffset = -carrieroffset; | ||
533 | break; | ||
534 | |||
535 | default: | ||
536 | return -EINVAL; | ||
537 | } | ||
538 | |||
539 | stv0297_init(fe); | ||
540 | state->config->pll_set(fe, p); | ||
541 | |||
542 | /* clear software interrupts */ | ||
543 | stv0297_writereg(state, 0x82, 0x0); | ||
544 | |||
545 | /* set initial demodulation frequency */ | ||
546 | stv0297_set_initialdemodfreq(state, 7250); | ||
547 | |||
548 | /* setup AGC */ | ||
549 | stv0297_writereg_mask(state, 0x43, 0x10, 0x00); | ||
550 | stv0297_writereg(state, 0x41, 0x00); | ||
551 | stv0297_writereg_mask(state, 0x42, 0x03, 0x01); | ||
552 | stv0297_writereg_mask(state, 0x36, 0x60, 0x00); | ||
553 | stv0297_writereg_mask(state, 0x36, 0x18, 0x00); | ||
554 | stv0297_writereg_mask(state, 0x71, 0x80, 0x80); | ||
555 | stv0297_writereg(state, 0x72, 0x00); | ||
556 | stv0297_writereg(state, 0x73, 0x00); | ||
557 | stv0297_writereg_mask(state, 0x74, 0x0F, 0x00); | ||
558 | stv0297_writereg_mask(state, 0x43, 0x08, 0x00); | ||
559 | stv0297_writereg_mask(state, 0x71, 0x80, 0x00); | ||
560 | |||
561 | /* setup STL */ | ||
562 | stv0297_writereg_mask(state, 0x5a, 0x20, 0x20); | ||
563 | stv0297_writereg_mask(state, 0x5b, 0x02, 0x02); | ||
564 | stv0297_writereg_mask(state, 0x5b, 0x02, 0x00); | ||
565 | stv0297_writereg_mask(state, 0x5b, 0x01, 0x00); | ||
566 | stv0297_writereg_mask(state, 0x5a, 0x40, 0x40); | ||
567 | |||
568 | /* disable frequency sweep */ | ||
569 | stv0297_writereg_mask(state, 0x6a, 0x01, 0x00); | ||
570 | |||
571 | /* reset deinterleaver */ | ||
572 | stv0297_writereg_mask(state, 0x81, 0x01, 0x01); | ||
573 | stv0297_writereg_mask(state, 0x81, 0x01, 0x00); | ||
574 | |||
575 | /* ??? */ | ||
576 | stv0297_writereg_mask(state, 0x83, 0x20, 0x20); | ||
577 | stv0297_writereg_mask(state, 0x83, 0x20, 0x00); | ||
578 | |||
579 | /* reset equaliser */ | ||
580 | u_threshold = stv0297_readreg(state, 0x00) & 0xf; | ||
581 | initial_u = stv0297_readreg(state, 0x01) >> 4; | ||
582 | blind_u = stv0297_readreg(state, 0x01) & 0xf; | ||
583 | stv0297_writereg_mask(state, 0x84, 0x01, 0x01); | ||
584 | stv0297_writereg_mask(state, 0x84, 0x01, 0x00); | ||
585 | stv0297_writereg_mask(state, 0x00, 0x0f, u_threshold); | ||
586 | stv0297_writereg_mask(state, 0x01, 0xf0, initial_u << 4); | ||
587 | stv0297_writereg_mask(state, 0x01, 0x0f, blind_u); | ||
588 | |||
589 | /* data comes from internal A/D */ | ||
590 | stv0297_writereg_mask(state, 0x87, 0x80, 0x00); | ||
591 | |||
592 | /* clear phase registers */ | ||
593 | stv0297_writereg(state, 0x63, 0x00); | ||
594 | stv0297_writereg(state, 0x64, 0x00); | ||
595 | stv0297_writereg(state, 0x65, 0x00); | ||
596 | stv0297_writereg(state, 0x66, 0x00); | ||
597 | stv0297_writereg(state, 0x67, 0x00); | ||
598 | stv0297_writereg(state, 0x68, 0x00); | ||
599 | stv0297_writereg_mask(state, 0x69, 0x0f, 0x00); | ||
600 | |||
601 | /* set parameters */ | ||
602 | stv0297_set_qam(state, p->u.qam.modulation); | ||
603 | stv0297_set_symbolrate(state, p->u.qam.symbol_rate / 1000); | ||
604 | stv0297_set_sweeprate(state, sweeprate, p->u.qam.symbol_rate / 1000); | ||
605 | stv0297_set_carrieroffset(state, carrieroffset); | ||
606 | stv0297_set_inversion(state, inversion); | ||
607 | |||
608 | /* kick off lock */ | ||
609 | stv0297_writereg_mask(state, 0x88, 0x08, 0x08); | ||
610 | stv0297_writereg_mask(state, 0x5a, 0x20, 0x00); | ||
611 | stv0297_writereg_mask(state, 0x6a, 0x01, 0x01); | ||
612 | stv0297_writereg_mask(state, 0x43, 0x40, 0x40); | ||
613 | stv0297_writereg_mask(state, 0x5b, 0x30, 0x00); | ||
614 | stv0297_writereg_mask(state, 0x03, 0x0c, 0x0c); | ||
615 | stv0297_writereg_mask(state, 0x03, 0x03, 0x03); | ||
616 | stv0297_writereg_mask(state, 0x43, 0x10, 0x10); | ||
617 | |||
618 | /* wait for WGAGC lock */ | ||
619 | starttime = jiffies; | ||
620 | timeout = jiffies + (200 * HZ) / 1000; | ||
621 | while (time_before(jiffies, timeout)) { | ||
622 | msleep(10); | ||
623 | if (stv0297_readreg(state, 0x43) & 0x08) | ||
624 | break; | ||
625 | } | ||
626 | if (time_after(jiffies, timeout)) { | ||
627 | goto timeout; | ||
628 | } | ||
629 | msleep(20); | ||
630 | |||
631 | /* wait for equaliser partial convergence */ | ||
632 | timeout = jiffies + (50 * HZ) / 1000; | ||
633 | while (time_before(jiffies, timeout)) { | ||
634 | msleep(10); | ||
635 | |||
636 | if (stv0297_readreg(state, 0x82) & 0x04) { | ||
637 | break; | ||
638 | } | ||
639 | } | ||
640 | if (time_after(jiffies, timeout)) { | ||
641 | goto timeout; | ||
642 | } | ||
643 | |||
644 | /* wait for equaliser full convergence */ | ||
645 | timeout = jiffies + (delay * HZ) / 1000; | ||
646 | while (time_before(jiffies, timeout)) { | ||
647 | msleep(10); | ||
648 | |||
649 | if (stv0297_readreg(state, 0x82) & 0x08) { | ||
650 | break; | ||
651 | } | ||
652 | } | ||
653 | if (time_after(jiffies, timeout)) { | ||
654 | goto timeout; | ||
655 | } | ||
656 | |||
657 | /* disable sweep */ | ||
658 | stv0297_writereg_mask(state, 0x6a, 1, 0); | ||
659 | stv0297_writereg_mask(state, 0x88, 8, 0); | ||
660 | |||
661 | /* wait for main lock */ | ||
662 | timeout = jiffies + (20 * HZ) / 1000; | ||
663 | while (time_before(jiffies, timeout)) { | ||
664 | msleep(10); | ||
665 | |||
666 | if (stv0297_readreg(state, 0xDF) & 0x80) { | ||
667 | break; | ||
668 | } | ||
669 | } | ||
670 | if (time_after(jiffies, timeout)) { | ||
671 | goto timeout; | ||
672 | } | ||
673 | msleep(100); | ||
674 | |||
675 | /* is it still locked after that delay? */ | ||
676 | if (!(stv0297_readreg(state, 0xDF) & 0x80)) { | ||
677 | goto timeout; | ||
678 | } | ||
679 | |||
680 | /* success!! */ | ||
681 | stv0297_writereg_mask(state, 0x5a, 0x40, 0x00); | ||
682 | state->base_freq = p->frequency; | ||
683 | return 0; | ||
684 | |||
685 | timeout: | ||
686 | stv0297_writereg_mask(state, 0x6a, 0x01, 0x00); | ||
687 | return 0; | ||
688 | } | ||
689 | |||
690 | static int stv0297_get_frontend(struct dvb_frontend *fe, struct dvb_frontend_parameters *p) | ||
691 | { | ||
692 | struct stv0297_state *state = (struct stv0297_state *) fe->demodulator_priv; | ||
693 | int reg_00, reg_83; | ||
694 | |||
695 | reg_00 = stv0297_readreg(state, 0x00); | ||
696 | reg_83 = stv0297_readreg(state, 0x83); | ||
697 | |||
698 | p->frequency = state->base_freq; | ||
699 | p->inversion = (reg_83 & 0x08) ? INVERSION_ON : INVERSION_OFF; | ||
700 | if (state->config->invert) | ||
701 | p->inversion = (p->inversion == INVERSION_ON) ? INVERSION_OFF : INVERSION_ON; | ||
702 | p->u.qam.symbol_rate = stv0297_get_symbolrate(state) * 1000; | ||
703 | p->u.qam.fec_inner = FEC_NONE; | ||
704 | |||
705 | switch ((reg_00 >> 4) & 0x7) { | ||
706 | case 0: | ||
707 | p->u.qam.modulation = QAM_16; | ||
708 | break; | ||
709 | case 1: | ||
710 | p->u.qam.modulation = QAM_32; | ||
711 | break; | ||
712 | case 2: | ||
713 | p->u.qam.modulation = QAM_128; | ||
714 | break; | ||
715 | case 3: | ||
716 | p->u.qam.modulation = QAM_256; | ||
717 | break; | ||
718 | case 4: | ||
719 | p->u.qam.modulation = QAM_64; | ||
720 | break; | ||
721 | } | ||
722 | |||
723 | return 0; | ||
724 | } | ||
725 | |||
726 | static void stv0297_release(struct dvb_frontend *fe) | ||
727 | { | ||
728 | struct stv0297_state *state = (struct stv0297_state *) fe->demodulator_priv; | ||
729 | kfree(state); | ||
730 | } | ||
731 | |||
732 | static struct dvb_frontend_ops stv0297_ops; | ||
733 | |||
734 | struct dvb_frontend *stv0297_attach(const struct stv0297_config *config, | ||
735 | struct i2c_adapter *i2c, int pwm) | ||
736 | { | ||
737 | struct stv0297_state *state = NULL; | ||
738 | |||
739 | /* allocate memory for the internal state */ | ||
740 | state = (struct stv0297_state *) kmalloc(sizeof(struct stv0297_state), GFP_KERNEL); | ||
741 | if (state == NULL) | ||
742 | goto error; | ||
743 | |||
744 | /* setup the state */ | ||
745 | state->config = config; | ||
746 | state->i2c = i2c; | ||
747 | memcpy(&state->ops, &stv0297_ops, sizeof(struct dvb_frontend_ops)); | ||
748 | state->base_freq = 0; | ||
749 | state->pwm = pwm; | ||
750 | |||
751 | /* check if the demod is there */ | ||
752 | if ((stv0297_readreg(state, 0x80) & 0x70) != 0x20) | ||
753 | goto error; | ||
754 | |||
755 | /* create dvb_frontend */ | ||
756 | state->frontend.ops = &state->ops; | ||
757 | state->frontend.demodulator_priv = state; | ||
758 | return &state->frontend; | ||
759 | |||
760 | error: | ||
761 | kfree(state); | ||
762 | return NULL; | ||
763 | } | ||
764 | |||
765 | static struct dvb_frontend_ops stv0297_ops = { | ||
766 | |||
767 | .info = { | ||
768 | .name = "ST STV0297 DVB-C", | ||
769 | .type = FE_QAM, | ||
770 | .frequency_min = 64000000, | ||
771 | .frequency_max = 1300000000, | ||
772 | .frequency_stepsize = 62500, | ||
773 | .symbol_rate_min = 870000, | ||
774 | .symbol_rate_max = 11700000, | ||
775 | .caps = FE_CAN_QAM_16 | FE_CAN_QAM_32 | FE_CAN_QAM_64 | | ||
776 | FE_CAN_QAM_128 | FE_CAN_QAM_256 | FE_CAN_FEC_AUTO}, | ||
777 | |||
778 | .release = stv0297_release, | ||
779 | |||
780 | .init = stv0297_init, | ||
781 | .sleep = stv0297_sleep, | ||
782 | |||
783 | .set_frontend = stv0297_set_frontend, | ||
784 | .get_frontend = stv0297_get_frontend, | ||
785 | |||
786 | .read_status = stv0297_read_status, | ||
787 | .read_ber = stv0297_read_ber, | ||
788 | .read_signal_strength = stv0297_read_signal_strength, | ||
789 | .read_snr = stv0297_read_snr, | ||
790 | .read_ucblocks = stv0297_read_ucblocks, | ||
791 | }; | ||
792 | |||
793 | MODULE_DESCRIPTION("ST STV0297 DVB-C Demodulator driver"); | ||
794 | MODULE_AUTHOR("Dennis Noermann and Andrew de Quincey"); | ||
795 | MODULE_LICENSE("GPL"); | ||
796 | |||
797 | EXPORT_SYMBOL(stv0297_attach); | ||
798 | EXPORT_SYMBOL(stv0297_enable_plli2c); | ||
diff --git a/drivers/media/dvb/frontends/stv0297.h b/drivers/media/dvb/frontends/stv0297.h new file mode 100644 index 000000000000..3be535989302 --- /dev/null +++ b/drivers/media/dvb/frontends/stv0297.h | |||
@@ -0,0 +1,44 @@ | |||
1 | /* | ||
2 | Driver for STV0297 demodulator | ||
3 | |||
4 | Copyright (C) 2003-2004 Dennis Noermann <dennis.noermann@noernet.de> | ||
5 | |||
6 | This program is free software; you can redistribute it and/or modify | ||
7 | it under the terms of the GNU General Public License as published by | ||
8 | the Free Software Foundation; either version 2 of the License, or | ||
9 | (at your option) any later version. | ||
10 | |||
11 | This program is distributed in the hope that it will be useful, | ||
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | GNU General Public License for more details. | ||
15 | |||
16 | You should have received a copy of the GNU General Public License | ||
17 | along with this program; if not, write to the Free Software | ||
18 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
19 | */ | ||
20 | |||
21 | #ifndef STV0297_H | ||
22 | #define STV0297_H | ||
23 | |||
24 | #include <linux/dvb/frontend.h> | ||
25 | #include "dvb_frontend.h" | ||
26 | |||
27 | struct stv0297_config | ||
28 | { | ||
29 | /* the demodulator's i2c address */ | ||
30 | u8 demod_address; | ||
31 | |||
32 | /* does the "inversion" need inverted? */ | ||
33 | u8 invert:1; | ||
34 | |||
35 | /* PLL maintenance */ | ||
36 | int (*pll_init)(struct dvb_frontend* fe); | ||
37 | int (*pll_set)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params); | ||
38 | }; | ||
39 | |||
40 | extern struct dvb_frontend* stv0297_attach(const struct stv0297_config* config, | ||
41 | struct i2c_adapter* i2c, int pwm); | ||
42 | extern int stv0297_enable_plli2c(struct dvb_frontend* fe); | ||
43 | |||
44 | #endif // STV0297_H | ||
diff --git a/drivers/media/dvb/frontends/stv0299.c b/drivers/media/dvb/frontends/stv0299.c new file mode 100644 index 000000000000..15b40541b62d --- /dev/null +++ b/drivers/media/dvb/frontends/stv0299.c | |||
@@ -0,0 +1,731 @@ | |||
1 | /* | ||
2 | Driver for ST STV0299 demodulator | ||
3 | |||
4 | Copyright (C) 2001-2002 Convergence Integrated Media GmbH | ||
5 | <ralph@convergence.de>, | ||
6 | <holger@convergence.de>, | ||
7 | <js@convergence.de> | ||
8 | |||
9 | |||
10 | Philips SU1278/SH | ||
11 | |||
12 | Copyright (C) 2002 by Peter Schildmann <peter.schildmann@web.de> | ||
13 | |||
14 | |||
15 | LG TDQF-S001F | ||
16 | |||
17 | Copyright (C) 2002 Felix Domke <tmbinc@elitedvb.net> | ||
18 | & Andreas Oberritter <obi@linuxtv.org> | ||
19 | |||
20 | |||
21 | Support for Samsung TBMU24112IMB used on Technisat SkyStar2 rev. 2.6B | ||
22 | |||
23 | Copyright (C) 2003 Vadim Catana <skystar@moldova.cc>: | ||
24 | |||
25 | Support for Philips SU1278 on Technotrend hardware | ||
26 | |||
27 | Copyright (C) 2004 Andrew de Quincey <adq_dvb@lidskialf.net> | ||
28 | |||
29 | This program is free software; you can redistribute it and/or modify | ||
30 | it under the terms of the GNU General Public License as published by | ||
31 | the Free Software Foundation; either version 2 of the License, or | ||
32 | (at your option) any later version. | ||
33 | |||
34 | This program is distributed in the hope that it will be useful, | ||
35 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
36 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
37 | GNU General Public License for more details. | ||
38 | |||
39 | You should have received a copy of the GNU General Public License | ||
40 | along with this program; if not, write to the Free Software | ||
41 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
42 | |||
43 | */ | ||
44 | |||
45 | #include <linux/init.h> | ||
46 | #include <linux/kernel.h> | ||
47 | #include <linux/module.h> | ||
48 | #include <linux/moduleparam.h> | ||
49 | #include <linux/string.h> | ||
50 | #include <linux/slab.h> | ||
51 | #include <asm/div64.h> | ||
52 | |||
53 | #include "dvb_frontend.h" | ||
54 | #include "stv0299.h" | ||
55 | |||
56 | struct stv0299_state { | ||
57 | struct i2c_adapter* i2c; | ||
58 | struct dvb_frontend_ops ops; | ||
59 | const struct stv0299_config* config; | ||
60 | struct dvb_frontend frontend; | ||
61 | |||
62 | u8 initialised:1; | ||
63 | u32 tuner_frequency; | ||
64 | u32 symbol_rate; | ||
65 | fe_code_rate_t fec_inner; | ||
66 | int errmode; | ||
67 | }; | ||
68 | |||
69 | #define STATUS_BER 0 | ||
70 | #define STATUS_UCBLOCKS 1 | ||
71 | |||
72 | static int debug; | ||
73 | #define dprintk(args...) \ | ||
74 | do { \ | ||
75 | if (debug) printk(KERN_DEBUG "stv0299: " args); \ | ||
76 | } while (0) | ||
77 | |||
78 | |||
79 | static int stv0299_writeregI (struct stv0299_state* state, u8 reg, u8 data) | ||
80 | { | ||
81 | int ret; | ||
82 | u8 buf [] = { reg, data }; | ||
83 | struct i2c_msg msg = { .addr = state->config->demod_address, .flags = 0, .buf = buf, .len = 2 }; | ||
84 | |||
85 | ret = i2c_transfer (state->i2c, &msg, 1); | ||
86 | |||
87 | if (ret != 1) | ||
88 | dprintk("%s: writereg error (reg == 0x%02x, val == 0x%02x, " | ||
89 | "ret == %i)\n", __FUNCTION__, reg, data, ret); | ||
90 | |||
91 | return (ret != 1) ? -EREMOTEIO : 0; | ||
92 | } | ||
93 | |||
94 | int stv0299_writereg (struct dvb_frontend* fe, u8 reg, u8 data) | ||
95 | { | ||
96 | struct stv0299_state* state = (struct stv0299_state*) fe->demodulator_priv; | ||
97 | |||
98 | return stv0299_writeregI(state, reg, data); | ||
99 | } | ||
100 | |||
101 | static u8 stv0299_readreg (struct stv0299_state* state, u8 reg) | ||
102 | { | ||
103 | int ret; | ||
104 | u8 b0 [] = { reg }; | ||
105 | u8 b1 [] = { 0 }; | ||
106 | struct i2c_msg msg [] = { { .addr = state->config->demod_address, .flags = 0, .buf = b0, .len = 1 }, | ||
107 | { .addr = state->config->demod_address, .flags = I2C_M_RD, .buf = b1, .len = 1 } }; | ||
108 | |||
109 | ret = i2c_transfer (state->i2c, msg, 2); | ||
110 | |||
111 | if (ret != 2) | ||
112 | dprintk("%s: readreg error (reg == 0x%02x, ret == %i)\n", | ||
113 | __FUNCTION__, reg, ret); | ||
114 | |||
115 | return b1[0]; | ||
116 | } | ||
117 | |||
118 | static int stv0299_readregs (struct stv0299_state* state, u8 reg1, u8 *b, u8 len) | ||
119 | { | ||
120 | int ret; | ||
121 | struct i2c_msg msg [] = { { .addr = state->config->demod_address, .flags = 0, .buf = ®1, .len = 1 }, | ||
122 | { .addr = state->config->demod_address, .flags = I2C_M_RD, .buf = b, .len = len } }; | ||
123 | |||
124 | ret = i2c_transfer (state->i2c, msg, 2); | ||
125 | |||
126 | if (ret != 2) | ||
127 | dprintk("%s: readreg error (ret == %i)\n", __FUNCTION__, ret); | ||
128 | |||
129 | return ret == 2 ? 0 : ret; | ||
130 | } | ||
131 | |||
132 | static int stv0299_set_FEC (struct stv0299_state* state, fe_code_rate_t fec) | ||
133 | { | ||
134 | dprintk ("%s\n", __FUNCTION__); | ||
135 | |||
136 | switch (fec) { | ||
137 | case FEC_AUTO: | ||
138 | { | ||
139 | return stv0299_writeregI (state, 0x31, 0x1f); | ||
140 | } | ||
141 | case FEC_1_2: | ||
142 | { | ||
143 | return stv0299_writeregI (state, 0x31, 0x01); | ||
144 | } | ||
145 | case FEC_2_3: | ||
146 | { | ||
147 | return stv0299_writeregI (state, 0x31, 0x02); | ||
148 | } | ||
149 | case FEC_3_4: | ||
150 | { | ||
151 | return stv0299_writeregI (state, 0x31, 0x04); | ||
152 | } | ||
153 | case FEC_5_6: | ||
154 | { | ||
155 | return stv0299_writeregI (state, 0x31, 0x08); | ||
156 | } | ||
157 | case FEC_7_8: | ||
158 | { | ||
159 | return stv0299_writeregI (state, 0x31, 0x10); | ||
160 | } | ||
161 | default: | ||
162 | { | ||
163 | return -EINVAL; | ||
164 | } | ||
165 | } | ||
166 | } | ||
167 | |||
168 | static fe_code_rate_t stv0299_get_fec (struct stv0299_state* state) | ||
169 | { | ||
170 | static fe_code_rate_t fec_tab [] = { FEC_2_3, FEC_3_4, FEC_5_6, | ||
171 | FEC_7_8, FEC_1_2 }; | ||
172 | u8 index; | ||
173 | |||
174 | dprintk ("%s\n", __FUNCTION__); | ||
175 | |||
176 | index = stv0299_readreg (state, 0x1b); | ||
177 | index &= 0x7; | ||
178 | |||
179 | if (index > 4) | ||
180 | return FEC_AUTO; | ||
181 | |||
182 | return fec_tab [index]; | ||
183 | } | ||
184 | |||
185 | static int stv0299_wait_diseqc_fifo (struct stv0299_state* state, int timeout) | ||
186 | { | ||
187 | unsigned long start = jiffies; | ||
188 | |||
189 | dprintk ("%s\n", __FUNCTION__); | ||
190 | |||
191 | while (stv0299_readreg(state, 0x0a) & 1) { | ||
192 | if (jiffies - start > timeout) { | ||
193 | dprintk ("%s: timeout!!\n", __FUNCTION__); | ||
194 | return -ETIMEDOUT; | ||
195 | } | ||
196 | msleep(10); | ||
197 | }; | ||
198 | |||
199 | return 0; | ||
200 | } | ||
201 | |||
202 | static int stv0299_wait_diseqc_idle (struct stv0299_state* state, int timeout) | ||
203 | { | ||
204 | unsigned long start = jiffies; | ||
205 | |||
206 | dprintk ("%s\n", __FUNCTION__); | ||
207 | |||
208 | while ((stv0299_readreg(state, 0x0a) & 3) != 2 ) { | ||
209 | if (jiffies - start > timeout) { | ||
210 | dprintk ("%s: timeout!!\n", __FUNCTION__); | ||
211 | return -ETIMEDOUT; | ||
212 | } | ||
213 | msleep(10); | ||
214 | }; | ||
215 | |||
216 | return 0; | ||
217 | } | ||
218 | |||
219 | static int stv0299_set_symbolrate (struct dvb_frontend* fe, u32 srate) | ||
220 | { | ||
221 | struct stv0299_state* state = (struct stv0299_state*) fe->demodulator_priv; | ||
222 | u64 big = srate; | ||
223 | u32 ratio; | ||
224 | |||
225 | // check rate is within limits | ||
226 | if ((srate < 1000000) || (srate > 45000000)) return -EINVAL; | ||
227 | |||
228 | // calculate value to program | ||
229 | big = big << 20; | ||
230 | big += (state->config->mclk-1); // round correctly | ||
231 | do_div(big, state->config->mclk); | ||
232 | ratio = big << 4; | ||
233 | |||
234 | return state->config->set_symbol_rate(fe, srate, ratio); | ||
235 | } | ||
236 | |||
237 | static int stv0299_get_symbolrate (struct stv0299_state* state) | ||
238 | { | ||
239 | u32 Mclk = state->config->mclk / 4096L; | ||
240 | u32 srate; | ||
241 | s32 offset; | ||
242 | u8 sfr[3]; | ||
243 | s8 rtf; | ||
244 | |||
245 | dprintk ("%s\n", __FUNCTION__); | ||
246 | |||
247 | stv0299_readregs (state, 0x1f, sfr, 3); | ||
248 | stv0299_readregs (state, 0x1a, &rtf, 1); | ||
249 | |||
250 | srate = (sfr[0] << 8) | sfr[1]; | ||
251 | srate *= Mclk; | ||
252 | srate /= 16; | ||
253 | srate += (sfr[2] >> 4) * Mclk / 256; | ||
254 | offset = (s32) rtf * (srate / 4096L); | ||
255 | offset /= 128; | ||
256 | |||
257 | dprintk ("%s : srate = %i\n", __FUNCTION__, srate); | ||
258 | dprintk ("%s : ofset = %i\n", __FUNCTION__, offset); | ||
259 | |||
260 | srate += offset; | ||
261 | |||
262 | srate += 1000; | ||
263 | srate /= 2000; | ||
264 | srate *= 2000; | ||
265 | |||
266 | return srate; | ||
267 | } | ||
268 | |||
269 | static int stv0299_send_diseqc_msg (struct dvb_frontend* fe, | ||
270 | struct dvb_diseqc_master_cmd *m) | ||
271 | { | ||
272 | struct stv0299_state* state = (struct stv0299_state*) fe->demodulator_priv; | ||
273 | u8 val; | ||
274 | int i; | ||
275 | |||
276 | dprintk ("%s\n", __FUNCTION__); | ||
277 | |||
278 | if (stv0299_wait_diseqc_idle (state, 100) < 0) | ||
279 | return -ETIMEDOUT; | ||
280 | |||
281 | val = stv0299_readreg (state, 0x08); | ||
282 | |||
283 | if (stv0299_writeregI (state, 0x08, (val & ~0x7) | 0x6)) /* DiSEqC mode */ | ||
284 | return -EREMOTEIO; | ||
285 | |||
286 | for (i=0; i<m->msg_len; i++) { | ||
287 | if (stv0299_wait_diseqc_fifo (state, 100) < 0) | ||
288 | return -ETIMEDOUT; | ||
289 | |||
290 | if (stv0299_writeregI (state, 0x09, m->msg[i])) | ||
291 | return -EREMOTEIO; | ||
292 | } | ||
293 | |||
294 | if (stv0299_wait_diseqc_idle (state, 100) < 0) | ||
295 | return -ETIMEDOUT; | ||
296 | |||
297 | return 0; | ||
298 | } | ||
299 | |||
300 | static int stv0299_send_diseqc_burst (struct dvb_frontend* fe, fe_sec_mini_cmd_t burst) | ||
301 | { | ||
302 | struct stv0299_state* state = (struct stv0299_state*) fe->demodulator_priv; | ||
303 | u8 val; | ||
304 | |||
305 | dprintk ("%s\n", __FUNCTION__); | ||
306 | |||
307 | if (stv0299_wait_diseqc_idle (state, 100) < 0) | ||
308 | return -ETIMEDOUT; | ||
309 | |||
310 | val = stv0299_readreg (state, 0x08); | ||
311 | |||
312 | if (stv0299_writeregI (state, 0x08, (val & ~0x7) | 0x2)) /* burst mode */ | ||
313 | return -EREMOTEIO; | ||
314 | |||
315 | if (stv0299_writeregI (state, 0x09, burst == SEC_MINI_A ? 0x00 : 0xff)) | ||
316 | return -EREMOTEIO; | ||
317 | |||
318 | if (stv0299_wait_diseqc_idle (state, 100) < 0) | ||
319 | return -ETIMEDOUT; | ||
320 | |||
321 | if (stv0299_writeregI (state, 0x08, val)) | ||
322 | return -EREMOTEIO; | ||
323 | |||
324 | return 0; | ||
325 | } | ||
326 | |||
327 | static int stv0299_set_tone (struct dvb_frontend* fe, fe_sec_tone_mode_t tone) | ||
328 | { | ||
329 | struct stv0299_state* state = (struct stv0299_state*) fe->demodulator_priv; | ||
330 | u8 val; | ||
331 | |||
332 | if (stv0299_wait_diseqc_idle (state, 100) < 0) | ||
333 | return -ETIMEDOUT; | ||
334 | |||
335 | val = stv0299_readreg (state, 0x08); | ||
336 | |||
337 | switch (tone) { | ||
338 | case SEC_TONE_ON: | ||
339 | return stv0299_writeregI (state, 0x08, val | 0x3); | ||
340 | |||
341 | case SEC_TONE_OFF: | ||
342 | return stv0299_writeregI (state, 0x08, (val & ~0x3) | 0x02); | ||
343 | |||
344 | default: | ||
345 | return -EINVAL; | ||
346 | } | ||
347 | } | ||
348 | |||
349 | static int stv0299_set_voltage (struct dvb_frontend* fe, fe_sec_voltage_t voltage) | ||
350 | { | ||
351 | struct stv0299_state* state = (struct stv0299_state*) fe->demodulator_priv; | ||
352 | u8 reg0x08; | ||
353 | u8 reg0x0c; | ||
354 | |||
355 | dprintk("%s: %s\n", __FUNCTION__, | ||
356 | voltage == SEC_VOLTAGE_13 ? "SEC_VOLTAGE_13" : | ||
357 | voltage == SEC_VOLTAGE_18 ? "SEC_VOLTAGE_18" : "??"); | ||
358 | |||
359 | reg0x08 = stv0299_readreg (state, 0x08); | ||
360 | reg0x0c = stv0299_readreg (state, 0x0c); | ||
361 | |||
362 | /** | ||
363 | * H/V switching over OP0, OP1 and OP2 are LNB power enable bits | ||
364 | */ | ||
365 | reg0x0c &= 0x0f; | ||
366 | |||
367 | if (voltage == SEC_VOLTAGE_OFF) { | ||
368 | stv0299_writeregI (state, 0x0c, 0x00); /* LNB power off! */ | ||
369 | return stv0299_writeregI (state, 0x08, 0x00); /* LNB power off! */ | ||
370 | } | ||
371 | |||
372 | stv0299_writeregI (state, 0x08, (reg0x08 & 0x3f) | (state->config->lock_output << 6)); | ||
373 | |||
374 | switch (voltage) { | ||
375 | case SEC_VOLTAGE_13: | ||
376 | if (state->config->volt13_op0_op1 == STV0299_VOLT13_OP0) reg0x0c |= 0x10; | ||
377 | else reg0x0c |= 0x40; | ||
378 | |||
379 | return stv0299_writeregI(state, 0x0c, reg0x0c); | ||
380 | |||
381 | case SEC_VOLTAGE_18: | ||
382 | return stv0299_writeregI(state, 0x0c, reg0x0c | 0x50); | ||
383 | default: | ||
384 | return -EINVAL; | ||
385 | }; | ||
386 | } | ||
387 | |||
388 | static int stv0299_send_legacy_dish_cmd(struct dvb_frontend* fe, u32 cmd) | ||
389 | { | ||
390 | u8 last = 1; | ||
391 | int i; | ||
392 | |||
393 | /* reset voltage at the end | ||
394 | if((0x50 & stv0299_readreg (i2c, 0x0c)) == 0x50) | ||
395 | cmd |= 0x80; | ||
396 | else | ||
397 | cmd &= 0x7F; | ||
398 | */ | ||
399 | |||
400 | cmd = cmd << 1; | ||
401 | dprintk("%s switch command: 0x%04x\n",__FUNCTION__, cmd); | ||
402 | |||
403 | stv0299_set_voltage(fe,SEC_VOLTAGE_18); | ||
404 | msleep(32); | ||
405 | |||
406 | for (i=0; i<9; i++) { | ||
407 | if((cmd & 0x01) != last) { | ||
408 | stv0299_set_voltage(fe, last ? SEC_VOLTAGE_13 : SEC_VOLTAGE_18); | ||
409 | last = (last) ? 0 : 1; | ||
410 | } | ||
411 | |||
412 | cmd = cmd >> 1; | ||
413 | |||
414 | if (i != 8) | ||
415 | msleep(8); | ||
416 | } | ||
417 | |||
418 | return 0; | ||
419 | } | ||
420 | |||
421 | static int stv0299_init (struct dvb_frontend* fe) | ||
422 | { | ||
423 | struct stv0299_state* state = (struct stv0299_state*) fe->demodulator_priv; | ||
424 | int i; | ||
425 | |||
426 | dprintk("stv0299: init chip\n"); | ||
427 | |||
428 | for (i=0; !(state->config->inittab[i] == 0xff && state->config->inittab[i+1] == 0xff); i+=2) | ||
429 | stv0299_writeregI(state, state->config->inittab[i], state->config->inittab[i+1]); | ||
430 | |||
431 | if (state->config->pll_init) { | ||
432 | stv0299_writeregI(state, 0x05, 0xb5); /* enable i2c repeater on stv0299 */ | ||
433 | state->config->pll_init(fe); | ||
434 | stv0299_writeregI(state, 0x05, 0x35); /* disable i2c repeater on stv0299 */ | ||
435 | } | ||
436 | |||
437 | return 0; | ||
438 | } | ||
439 | |||
440 | static int stv0299_read_status(struct dvb_frontend* fe, fe_status_t* status) | ||
441 | { | ||
442 | struct stv0299_state* state = (struct stv0299_state*) fe->demodulator_priv; | ||
443 | |||
444 | u8 signal = 0xff - stv0299_readreg (state, 0x18); | ||
445 | u8 sync = stv0299_readreg (state, 0x1b); | ||
446 | |||
447 | dprintk ("%s : FE_READ_STATUS : VSTATUS: 0x%02x\n", __FUNCTION__, sync); | ||
448 | *status = 0; | ||
449 | |||
450 | if (signal > 10) | ||
451 | *status |= FE_HAS_SIGNAL; | ||
452 | |||
453 | if (sync & 0x80) | ||
454 | *status |= FE_HAS_CARRIER; | ||
455 | |||
456 | if (sync & 0x10) | ||
457 | *status |= FE_HAS_VITERBI; | ||
458 | |||
459 | if (sync & 0x08) | ||
460 | *status |= FE_HAS_SYNC; | ||
461 | |||
462 | if ((sync & 0x98) == 0x98) | ||
463 | *status |= FE_HAS_LOCK; | ||
464 | |||
465 | return 0; | ||
466 | } | ||
467 | |||
468 | static int stv0299_read_ber(struct dvb_frontend* fe, u32* ber) | ||
469 | { | ||
470 | struct stv0299_state* state = (struct stv0299_state*) fe->demodulator_priv; | ||
471 | |||
472 | if (state->errmode != STATUS_BER) return 0; | ||
473 | *ber = (stv0299_readreg (state, 0x1d) << 8) | stv0299_readreg (state, 0x1e); | ||
474 | |||
475 | return 0; | ||
476 | } | ||
477 | |||
478 | static int stv0299_read_signal_strength(struct dvb_frontend* fe, u16* strength) | ||
479 | { | ||
480 | struct stv0299_state* state = (struct stv0299_state*) fe->demodulator_priv; | ||
481 | |||
482 | s32 signal = 0xffff - ((stv0299_readreg (state, 0x18) << 8) | ||
483 | | stv0299_readreg (state, 0x19)); | ||
484 | |||
485 | dprintk ("%s : FE_READ_SIGNAL_STRENGTH : AGC2I: 0x%02x%02x, signal=0x%04x\n", __FUNCTION__, | ||
486 | stv0299_readreg (state, 0x18), | ||
487 | stv0299_readreg (state, 0x19), (int) signal); | ||
488 | |||
489 | signal = signal * 5 / 4; | ||
490 | *strength = (signal > 0xffff) ? 0xffff : (signal < 0) ? 0 : signal; | ||
491 | |||
492 | return 0; | ||
493 | } | ||
494 | |||
495 | static int stv0299_read_snr(struct dvb_frontend* fe, u16* snr) | ||
496 | { | ||
497 | struct stv0299_state* state = (struct stv0299_state*) fe->demodulator_priv; | ||
498 | |||
499 | s32 xsnr = 0xffff - ((stv0299_readreg (state, 0x24) << 8) | ||
500 | | stv0299_readreg (state, 0x25)); | ||
501 | xsnr = 3 * (xsnr - 0xa100); | ||
502 | *snr = (xsnr > 0xffff) ? 0xffff : (xsnr < 0) ? 0 : xsnr; | ||
503 | |||
504 | return 0; | ||
505 | } | ||
506 | |||
507 | static int stv0299_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks) | ||
508 | { | ||
509 | struct stv0299_state* state = (struct stv0299_state*) fe->demodulator_priv; | ||
510 | |||
511 | if (state->errmode != STATUS_UCBLOCKS) *ucblocks = 0; | ||
512 | else *ucblocks = (stv0299_readreg (state, 0x1d) << 8) | stv0299_readreg (state, 0x1e); | ||
513 | |||
514 | return 0; | ||
515 | } | ||
516 | |||
517 | static int stv0299_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters * p) | ||
518 | { | ||
519 | struct stv0299_state* state = (struct stv0299_state*) fe->demodulator_priv; | ||
520 | int invval = 0; | ||
521 | |||
522 | dprintk ("%s : FE_SET_FRONTEND\n", __FUNCTION__); | ||
523 | |||
524 | // set the inversion | ||
525 | if (p->inversion == INVERSION_OFF) invval = 0; | ||
526 | else if (p->inversion == INVERSION_ON) invval = 1; | ||
527 | else { | ||
528 | printk("stv0299 does not support auto-inversion\n"); | ||
529 | return -EINVAL; | ||
530 | } | ||
531 | if (state->config->invert) invval = (~invval) & 1; | ||
532 | stv0299_writeregI(state, 0x0c, (stv0299_readreg(state, 0x0c) & 0xfe) | invval); | ||
533 | |||
534 | if (state->config->enhanced_tuning) { | ||
535 | /* check if we should do a finetune */ | ||
536 | int frequency_delta = p->frequency - state->tuner_frequency; | ||
537 | int minmax = p->u.qpsk.symbol_rate / 2000; | ||
538 | if (minmax < 5000) minmax = 5000; | ||
539 | |||
540 | if ((frequency_delta > -minmax) && (frequency_delta < minmax) && (frequency_delta != 0) && | ||
541 | (state->fec_inner == p->u.qpsk.fec_inner) && | ||
542 | (state->symbol_rate == p->u.qpsk.symbol_rate)) { | ||
543 | int Drot_freq = (frequency_delta << 16) / (state->config->mclk / 1000); | ||
544 | |||
545 | // zap the derotator registers first | ||
546 | stv0299_writeregI(state, 0x22, 0x00); | ||
547 | stv0299_writeregI(state, 0x23, 0x00); | ||
548 | |||
549 | // now set them as we want | ||
550 | stv0299_writeregI(state, 0x22, Drot_freq >> 8); | ||
551 | stv0299_writeregI(state, 0x23, Drot_freq); | ||
552 | } else { | ||
553 | /* A "normal" tune is requested */ | ||
554 | stv0299_writeregI(state, 0x05, 0xb5); /* enable i2c repeater on stv0299 */ | ||
555 | state->config->pll_set(fe, p); | ||
556 | stv0299_writeregI(state, 0x05, 0x35); /* disable i2c repeater on stv0299 */ | ||
557 | |||
558 | stv0299_writeregI(state, 0x32, 0x80); | ||
559 | stv0299_writeregI(state, 0x22, 0x00); | ||
560 | stv0299_writeregI(state, 0x23, 0x00); | ||
561 | stv0299_writeregI(state, 0x32, 0x19); | ||
562 | stv0299_set_symbolrate (fe, p->u.qpsk.symbol_rate); | ||
563 | stv0299_set_FEC (state, p->u.qpsk.fec_inner); | ||
564 | } | ||
565 | } else { | ||
566 | stv0299_writeregI(state, 0x05, 0xb5); /* enable i2c repeater on stv0299 */ | ||
567 | state->config->pll_set(fe, p); | ||
568 | stv0299_writeregI(state, 0x05, 0x35); /* disable i2c repeater on stv0299 */ | ||
569 | |||
570 | stv0299_set_FEC (state, p->u.qpsk.fec_inner); | ||
571 | stv0299_set_symbolrate (fe, p->u.qpsk.symbol_rate); | ||
572 | stv0299_writeregI(state, 0x22, 0x00); | ||
573 | stv0299_writeregI(state, 0x23, 0x00); | ||
574 | stv0299_readreg (state, 0x23); | ||
575 | stv0299_writeregI(state, 0x12, 0xb9); | ||
576 | } | ||
577 | |||
578 | state->tuner_frequency = p->frequency; | ||
579 | state->fec_inner = p->u.qpsk.fec_inner; | ||
580 | state->symbol_rate = p->u.qpsk.symbol_rate; | ||
581 | |||
582 | return 0; | ||
583 | } | ||
584 | |||
585 | static int stv0299_get_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters * p) | ||
586 | { | ||
587 | struct stv0299_state* state = (struct stv0299_state*) fe->demodulator_priv; | ||
588 | s32 derot_freq; | ||
589 | int invval; | ||
590 | |||
591 | derot_freq = (s32)(s16) ((stv0299_readreg (state, 0x22) << 8) | ||
592 | | stv0299_readreg (state, 0x23)); | ||
593 | |||
594 | derot_freq *= (state->config->mclk >> 16); | ||
595 | derot_freq += 500; | ||
596 | derot_freq /= 1000; | ||
597 | |||
598 | p->frequency += derot_freq; | ||
599 | |||
600 | invval = stv0299_readreg (state, 0x0c) & 1; | ||
601 | if (state->config->invert) invval = (~invval) & 1; | ||
602 | p->inversion = invval ? INVERSION_ON : INVERSION_OFF; | ||
603 | |||
604 | p->u.qpsk.fec_inner = stv0299_get_fec (state); | ||
605 | p->u.qpsk.symbol_rate = stv0299_get_symbolrate (state); | ||
606 | |||
607 | return 0; | ||
608 | } | ||
609 | |||
610 | static int stv0299_sleep(struct dvb_frontend* fe) | ||
611 | { | ||
612 | struct stv0299_state* state = (struct stv0299_state*) fe->demodulator_priv; | ||
613 | |||
614 | stv0299_writeregI(state, 0x02, 0x80); | ||
615 | state->initialised = 0; | ||
616 | |||
617 | return 0; | ||
618 | } | ||
619 | |||
620 | static int stv0299_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings* fesettings) | ||
621 | { | ||
622 | struct stv0299_state* state = (struct stv0299_state*) fe->demodulator_priv; | ||
623 | |||
624 | fesettings->min_delay_ms = state->config->min_delay_ms; | ||
625 | if (fesettings->parameters.u.qpsk.symbol_rate < 10000000) { | ||
626 | fesettings->step_size = fesettings->parameters.u.qpsk.symbol_rate / 32000; | ||
627 | fesettings->max_drift = 5000; | ||
628 | } else { | ||
629 | fesettings->step_size = fesettings->parameters.u.qpsk.symbol_rate / 16000; | ||
630 | fesettings->max_drift = fesettings->parameters.u.qpsk.symbol_rate / 2000; | ||
631 | } | ||
632 | return 0; | ||
633 | } | ||
634 | |||
635 | static void stv0299_release(struct dvb_frontend* fe) | ||
636 | { | ||
637 | struct stv0299_state* state = (struct stv0299_state*) fe->demodulator_priv; | ||
638 | kfree(state); | ||
639 | } | ||
640 | |||
641 | static struct dvb_frontend_ops stv0299_ops; | ||
642 | |||
643 | struct dvb_frontend* stv0299_attach(const struct stv0299_config* config, | ||
644 | struct i2c_adapter* i2c) | ||
645 | { | ||
646 | struct stv0299_state* state = NULL; | ||
647 | int id; | ||
648 | |||
649 | /* allocate memory for the internal state */ | ||
650 | state = (struct stv0299_state*) kmalloc(sizeof(struct stv0299_state), GFP_KERNEL); | ||
651 | if (state == NULL) goto error; | ||
652 | |||
653 | /* setup the state */ | ||
654 | state->config = config; | ||
655 | state->i2c = i2c; | ||
656 | memcpy(&state->ops, &stv0299_ops, sizeof(struct dvb_frontend_ops)); | ||
657 | state->initialised = 0; | ||
658 | state->tuner_frequency = 0; | ||
659 | state->symbol_rate = 0; | ||
660 | state->fec_inner = 0; | ||
661 | state->errmode = STATUS_BER; | ||
662 | |||
663 | /* check if the demod is there */ | ||
664 | stv0299_writeregI(state, 0x02, 0x34); /* standby off */ | ||
665 | msleep(200); | ||
666 | id = stv0299_readreg(state, 0x00); | ||
667 | |||
668 | /* register 0x00 contains 0xa1 for STV0299 and STV0299B */ | ||
669 | /* register 0x00 might contain 0x80 when returning from standby */ | ||
670 | if (id != 0xa1 && id != 0x80) goto error; | ||
671 | |||
672 | /* create dvb_frontend */ | ||
673 | state->frontend.ops = &state->ops; | ||
674 | state->frontend.demodulator_priv = state; | ||
675 | return &state->frontend; | ||
676 | |||
677 | error: | ||
678 | kfree(state); | ||
679 | return NULL; | ||
680 | } | ||
681 | |||
682 | static struct dvb_frontend_ops stv0299_ops = { | ||
683 | |||
684 | .info = { | ||
685 | .name = "ST STV0299 DVB-S", | ||
686 | .type = FE_QPSK, | ||
687 | .frequency_min = 950000, | ||
688 | .frequency_max = 2150000, | ||
689 | .frequency_stepsize = 125, /* kHz for QPSK frontends */ | ||
690 | .frequency_tolerance = 0, | ||
691 | .symbol_rate_min = 1000000, | ||
692 | .symbol_rate_max = 45000000, | ||
693 | .symbol_rate_tolerance = 500, /* ppm */ | ||
694 | .caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | | ||
695 | FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | | ||
696 | FE_CAN_QPSK | | ||
697 | FE_CAN_FEC_AUTO | ||
698 | }, | ||
699 | |||
700 | .release = stv0299_release, | ||
701 | |||
702 | .init = stv0299_init, | ||
703 | .sleep = stv0299_sleep, | ||
704 | |||
705 | .set_frontend = stv0299_set_frontend, | ||
706 | .get_frontend = stv0299_get_frontend, | ||
707 | .get_tune_settings = stv0299_get_tune_settings, | ||
708 | |||
709 | .read_status = stv0299_read_status, | ||
710 | .read_ber = stv0299_read_ber, | ||
711 | .read_signal_strength = stv0299_read_signal_strength, | ||
712 | .read_snr = stv0299_read_snr, | ||
713 | .read_ucblocks = stv0299_read_ucblocks, | ||
714 | |||
715 | .diseqc_send_master_cmd = stv0299_send_diseqc_msg, | ||
716 | .diseqc_send_burst = stv0299_send_diseqc_burst, | ||
717 | .set_tone = stv0299_set_tone, | ||
718 | .set_voltage = stv0299_set_voltage, | ||
719 | .dishnetwork_send_legacy_command = stv0299_send_legacy_dish_cmd, | ||
720 | }; | ||
721 | |||
722 | module_param(debug, int, 0644); | ||
723 | MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off)."); | ||
724 | |||
725 | MODULE_DESCRIPTION("ST STV0299 DVB Demodulator driver"); | ||
726 | MODULE_AUTHOR("Ralph Metzler, Holger Waechtler, Peter Schildmann, Felix Domke, " | ||
727 | "Andreas Oberritter, Andrew de Quincey, Kenneth Aafløy"); | ||
728 | MODULE_LICENSE("GPL"); | ||
729 | |||
730 | EXPORT_SYMBOL(stv0299_writereg); | ||
731 | EXPORT_SYMBOL(stv0299_attach); | ||
diff --git a/drivers/media/dvb/frontends/stv0299.h b/drivers/media/dvb/frontends/stv0299.h new file mode 100644 index 000000000000..79457a80a11f --- /dev/null +++ b/drivers/media/dvb/frontends/stv0299.h | |||
@@ -0,0 +1,104 @@ | |||
1 | /* | ||
2 | Driver for ST STV0299 demodulator | ||
3 | |||
4 | Copyright (C) 2001-2002 Convergence Integrated Media GmbH | ||
5 | <ralph@convergence.de>, | ||
6 | <holger@convergence.de>, | ||
7 | <js@convergence.de> | ||
8 | |||
9 | |||
10 | Philips SU1278/SH | ||
11 | |||
12 | Copyright (C) 2002 by Peter Schildmann <peter.schildmann@web.de> | ||
13 | |||
14 | |||
15 | LG TDQF-S001F | ||
16 | |||
17 | Copyright (C) 2002 Felix Domke <tmbinc@elitedvb.net> | ||
18 | & Andreas Oberritter <obi@linuxtv.org> | ||
19 | |||
20 | |||
21 | Support for Samsung TBMU24112IMB used on Technisat SkyStar2 rev. 2.6B | ||
22 | |||
23 | Copyright (C) 2003 Vadim Catana <skystar@moldova.cc>: | ||
24 | |||
25 | Support for Philips SU1278 on Technotrend hardware | ||
26 | |||
27 | Copyright (C) 2004 Andrew de Quincey <adq_dvb@lidskialf.net> | ||
28 | |||
29 | This program is free software; you can redistribute it and/or modify | ||
30 | it under the terms of the GNU General Public License as published by | ||
31 | the Free Software Foundation; either version 2 of the License, or | ||
32 | (at your option) any later version. | ||
33 | |||
34 | This program is distributed in the hope that it will be useful, | ||
35 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
36 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
37 | GNU General Public License for more details. | ||
38 | |||
39 | You should have received a copy of the GNU General Public License | ||
40 | along with this program; if not, write to the Free Software | ||
41 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
42 | |||
43 | */ | ||
44 | |||
45 | #ifndef STV0299_H | ||
46 | #define STV0299_H | ||
47 | |||
48 | #include <linux/dvb/frontend.h> | ||
49 | #include "dvb_frontend.h" | ||
50 | |||
51 | #define STV0229_LOCKOUTPUT_0 0 | ||
52 | #define STV0229_LOCKOUTPUT_1 1 | ||
53 | #define STV0229_LOCKOUTPUT_CF 2 | ||
54 | #define STV0229_LOCKOUTPUT_LK 3 | ||
55 | |||
56 | #define STV0299_VOLT13_OP0 0 | ||
57 | #define STV0299_VOLT13_OP1 1 | ||
58 | |||
59 | struct stv0299_config | ||
60 | { | ||
61 | /* the demodulator's i2c address */ | ||
62 | u8 demod_address; | ||
63 | |||
64 | /* inittab - array of pairs of values. | ||
65 | * First of each pair is the register, second is the value. | ||
66 | * List should be terminated with an 0xff, 0xff pair. | ||
67 | */ | ||
68 | u8* inittab; | ||
69 | |||
70 | /* master clock to use */ | ||
71 | u32 mclk; | ||
72 | |||
73 | /* does the inversion require inversion? */ | ||
74 | u8 invert:1; | ||
75 | |||
76 | /* Should the enhanced tuning code be used? */ | ||
77 | u8 enhanced_tuning:1; | ||
78 | |||
79 | /* Skip reinitialisation? */ | ||
80 | u8 skip_reinit:1; | ||
81 | |||
82 | /* LOCK OUTPUT setting */ | ||
83 | u8 lock_output:2; | ||
84 | |||
85 | /* Is 13v controlled by OP0 or OP1? */ | ||
86 | u8 volt13_op0_op1:1; | ||
87 | |||
88 | /* minimum delay before retuning */ | ||
89 | int min_delay_ms; | ||
90 | |||
91 | /* Set the symbol rate */ | ||
92 | int (*set_symbol_rate)(struct dvb_frontend* fe, u32 srate, u32 ratio); | ||
93 | |||
94 | /* PLL maintenance */ | ||
95 | int (*pll_init)(struct dvb_frontend* fe); | ||
96 | int (*pll_set)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params); | ||
97 | }; | ||
98 | |||
99 | extern int stv0299_writereg (struct dvb_frontend* fe, u8 reg, u8 data); | ||
100 | |||
101 | extern struct dvb_frontend* stv0299_attach(const struct stv0299_config* config, | ||
102 | struct i2c_adapter* i2c); | ||
103 | |||
104 | #endif // STV0299_H | ||
diff --git a/drivers/media/dvb/frontends/tda10021.c b/drivers/media/dvb/frontends/tda10021.c new file mode 100644 index 000000000000..4e40d95ee95d --- /dev/null +++ b/drivers/media/dvb/frontends/tda10021.c | |||
@@ -0,0 +1,469 @@ | |||
1 | /* | ||
2 | TDA10021 - Single Chip Cable Channel Receiver driver module | ||
3 | used on the the Siemens DVB-C cards | ||
4 | |||
5 | Copyright (C) 1999 Convergence Integrated Media GmbH <ralph@convergence.de> | ||
6 | Copyright (C) 2004 Markus Schulz <msc@antzsystem.de> | ||
7 | Support for TDA10021 | ||
8 | |||
9 | This program is free software; you can redistribute it and/or modify | ||
10 | it under the terms of the GNU General Public License as published by | ||
11 | the Free Software Foundation; either version 2 of the License, or | ||
12 | (at your option) any later version. | ||
13 | |||
14 | This program is distributed in the hope that it will be useful, | ||
15 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
16 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
17 | GNU General Public License for more details. | ||
18 | |||
19 | You should have received a copy of the GNU General Public License | ||
20 | along with this program; if not, write to the Free Software | ||
21 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
22 | */ | ||
23 | |||
24 | #include <linux/config.h> | ||
25 | #include <linux/delay.h> | ||
26 | #include <linux/errno.h> | ||
27 | #include <linux/init.h> | ||
28 | #include <linux/kernel.h> | ||
29 | #include <linux/module.h> | ||
30 | #include <linux/string.h> | ||
31 | #include <linux/slab.h> | ||
32 | |||
33 | #include "dvb_frontend.h" | ||
34 | #include "tda10021.h" | ||
35 | |||
36 | |||
37 | struct tda10021_state { | ||
38 | struct i2c_adapter* i2c; | ||
39 | struct dvb_frontend_ops ops; | ||
40 | /* configuration settings */ | ||
41 | const struct tda10021_config* config; | ||
42 | struct dvb_frontend frontend; | ||
43 | |||
44 | u8 pwm; | ||
45 | u8 reg0; | ||
46 | }; | ||
47 | |||
48 | |||
49 | #if 0 | ||
50 | #define dprintk(x...) printk(x) | ||
51 | #else | ||
52 | #define dprintk(x...) | ||
53 | #endif | ||
54 | |||
55 | static int verbose; | ||
56 | |||
57 | #define XIN 57840000UL | ||
58 | #define DISABLE_INVERSION(reg0) do { reg0 |= 0x20; } while (0) | ||
59 | #define ENABLE_INVERSION(reg0) do { reg0 &= ~0x20; } while (0) | ||
60 | #define HAS_INVERSION(reg0) (!(reg0 & 0x20)) | ||
61 | |||
62 | #define FIN (XIN >> 4) | ||
63 | |||
64 | static int tda10021_inittab_size = 0x40; | ||
65 | static u8 tda10021_inittab[0x40]= | ||
66 | { | ||
67 | 0x73, 0x6a, 0x23, 0x0a, 0x02, 0x37, 0x77, 0x1a, | ||
68 | 0x37, 0x6a, 0x17, 0x8a, 0x1e, 0x86, 0x43, 0x40, | ||
69 | 0xb8, 0x3f, 0xa0, 0x00, 0xcd, 0x01, 0x00, 0xff, | ||
70 | 0x11, 0x00, 0x7c, 0x31, 0x30, 0x20, 0x00, 0x00, | ||
71 | 0x02, 0x00, 0x00, 0x7d, 0x00, 0x00, 0x00, 0x00, | ||
72 | 0x07, 0x00, 0x33, 0x11, 0x0d, 0x95, 0x08, 0x58, | ||
73 | 0x00, 0x00, 0x80, 0x00, 0x80, 0xff, 0x00, 0x00, | ||
74 | 0x04, 0x2d, 0x2f, 0xff, 0x00, 0x00, 0x00, 0x00, | ||
75 | }; | ||
76 | |||
77 | static int tda10021_writereg (struct tda10021_state* state, u8 reg, u8 data) | ||
78 | { | ||
79 | u8 buf[] = { reg, data }; | ||
80 | struct i2c_msg msg = { .addr = state->config->demod_address, .flags = 0, .buf = buf, .len = 2 }; | ||
81 | int ret; | ||
82 | |||
83 | ret = i2c_transfer (state->i2c, &msg, 1); | ||
84 | if (ret != 1) | ||
85 | printk("DVB: TDA10021(%d): %s, writereg error " | ||
86 | "(reg == 0x%02x, val == 0x%02x, ret == %i)\n", | ||
87 | state->frontend.dvb->num, __FUNCTION__, reg, data, ret); | ||
88 | |||
89 | msleep(10); | ||
90 | return (ret != 1) ? -EREMOTEIO : 0; | ||
91 | } | ||
92 | |||
93 | static u8 tda10021_readreg (struct tda10021_state* state, u8 reg) | ||
94 | { | ||
95 | u8 b0 [] = { reg }; | ||
96 | u8 b1 [] = { 0 }; | ||
97 | struct i2c_msg msg [] = { { .addr = state->config->demod_address, .flags = 0, .buf = b0, .len = 1 }, | ||
98 | { .addr = state->config->demod_address, .flags = I2C_M_RD, .buf = b1, .len = 1 } }; | ||
99 | int ret; | ||
100 | |||
101 | ret = i2c_transfer (state->i2c, msg, 2); | ||
102 | if (ret != 2) | ||
103 | printk("DVB: TDA10021(%d): %s: readreg error (ret == %i)\n", | ||
104 | state->frontend.dvb->num, __FUNCTION__, ret); | ||
105 | return b1[0]; | ||
106 | } | ||
107 | |||
108 | //get access to tuner | ||
109 | static int lock_tuner(struct tda10021_state* state) | ||
110 | { | ||
111 | u8 buf[2] = { 0x0f, tda10021_inittab[0x0f] | 0x80 }; | ||
112 | struct i2c_msg msg = {.addr=state->config->demod_address, .flags=0, .buf=buf, .len=2}; | ||
113 | |||
114 | if(i2c_transfer(state->i2c, &msg, 1) != 1) | ||
115 | { | ||
116 | printk("tda10021: lock tuner fails\n"); | ||
117 | return -EREMOTEIO; | ||
118 | } | ||
119 | return 0; | ||
120 | } | ||
121 | |||
122 | //release access from tuner | ||
123 | static int unlock_tuner(struct tda10021_state* state) | ||
124 | { | ||
125 | u8 buf[2] = { 0x0f, tda10021_inittab[0x0f] & 0x7f }; | ||
126 | struct i2c_msg msg_post={.addr=state->config->demod_address, .flags=0, .buf=buf, .len=2}; | ||
127 | |||
128 | if(i2c_transfer(state->i2c, &msg_post, 1) != 1) | ||
129 | { | ||
130 | printk("tda10021: unlock tuner fails\n"); | ||
131 | return -EREMOTEIO; | ||
132 | } | ||
133 | return 0; | ||
134 | } | ||
135 | |||
136 | static int tda10021_setup_reg0 (struct tda10021_state* state, u8 reg0, | ||
137 | fe_spectral_inversion_t inversion) | ||
138 | { | ||
139 | reg0 |= state->reg0 & 0x63; | ||
140 | |||
141 | if (INVERSION_ON == inversion) | ||
142 | ENABLE_INVERSION(reg0); | ||
143 | else if (INVERSION_OFF == inversion) | ||
144 | DISABLE_INVERSION(reg0); | ||
145 | |||
146 | tda10021_writereg (state, 0x00, reg0 & 0xfe); | ||
147 | tda10021_writereg (state, 0x00, reg0 | 0x01); | ||
148 | |||
149 | state->reg0 = reg0; | ||
150 | return 0; | ||
151 | } | ||
152 | |||
153 | static int tda10021_set_symbolrate (struct tda10021_state* state, u32 symbolrate) | ||
154 | { | ||
155 | s32 BDR; | ||
156 | s32 BDRI; | ||
157 | s16 SFIL=0; | ||
158 | u16 NDEC = 0; | ||
159 | u32 tmp, ratio; | ||
160 | |||
161 | if (symbolrate > XIN/2) | ||
162 | symbolrate = XIN/2; | ||
163 | if (symbolrate < 500000) | ||
164 | symbolrate = 500000; | ||
165 | |||
166 | if (symbolrate < XIN/16) NDEC = 1; | ||
167 | if (symbolrate < XIN/32) NDEC = 2; | ||
168 | if (symbolrate < XIN/64) NDEC = 3; | ||
169 | |||
170 | if (symbolrate < (u32)(XIN/12.3)) SFIL = 1; | ||
171 | if (symbolrate < (u32)(XIN/16)) SFIL = 0; | ||
172 | if (symbolrate < (u32)(XIN/24.6)) SFIL = 1; | ||
173 | if (symbolrate < (u32)(XIN/32)) SFIL = 0; | ||
174 | if (symbolrate < (u32)(XIN/49.2)) SFIL = 1; | ||
175 | if (symbolrate < (u32)(XIN/64)) SFIL = 0; | ||
176 | if (symbolrate < (u32)(XIN/98.4)) SFIL = 1; | ||
177 | |||
178 | symbolrate <<= NDEC; | ||
179 | ratio = (symbolrate << 4) / FIN; | ||
180 | tmp = ((symbolrate << 4) % FIN) << 8; | ||
181 | ratio = (ratio << 8) + tmp / FIN; | ||
182 | tmp = (tmp % FIN) << 8; | ||
183 | ratio = (ratio << 8) + (tmp + FIN/2) / FIN; | ||
184 | |||
185 | BDR = ratio; | ||
186 | BDRI = (((XIN << 5) / symbolrate) + 1) / 2; | ||
187 | |||
188 | if (BDRI > 0xFF) | ||
189 | BDRI = 0xFF; | ||
190 | |||
191 | SFIL = (SFIL << 4) | tda10021_inittab[0x0E]; | ||
192 | |||
193 | NDEC = (NDEC << 6) | tda10021_inittab[0x03]; | ||
194 | |||
195 | tda10021_writereg (state, 0x03, NDEC); | ||
196 | tda10021_writereg (state, 0x0a, BDR&0xff); | ||
197 | tda10021_writereg (state, 0x0b, (BDR>> 8)&0xff); | ||
198 | tda10021_writereg (state, 0x0c, (BDR>>16)&0x3f); | ||
199 | |||
200 | tda10021_writereg (state, 0x0d, BDRI); | ||
201 | tda10021_writereg (state, 0x0e, SFIL); | ||
202 | |||
203 | return 0; | ||
204 | } | ||
205 | |||
206 | static int tda10021_init (struct dvb_frontend *fe) | ||
207 | { | ||
208 | struct tda10021_state* state = (struct tda10021_state*) fe->demodulator_priv; | ||
209 | int i; | ||
210 | |||
211 | dprintk("DVB: TDA10021(%d): init chip\n", fe->adapter->num); | ||
212 | |||
213 | //tda10021_writereg (fe, 0, 0); | ||
214 | |||
215 | for (i=0; i<tda10021_inittab_size; i++) | ||
216 | tda10021_writereg (state, i, tda10021_inittab[i]); | ||
217 | |||
218 | tda10021_writereg (state, 0x34, state->pwm); | ||
219 | |||
220 | //Comment by markus | ||
221 | //0x2A[3-0] == PDIV -> P multiplaying factor (P=PDIV+1)(default 0) | ||
222 | //0x2A[4] == BYPPLL -> Power down mode (default 1) | ||
223 | //0x2A[5] == LCK -> PLL Lock Flag | ||
224 | //0x2A[6] == POLAXIN -> Polarity of the input reference clock (default 0) | ||
225 | |||
226 | //Activate PLL | ||
227 | tda10021_writereg(state, 0x2a, tda10021_inittab[0x2a] & 0xef); | ||
228 | |||
229 | if (state->config->pll_init) { | ||
230 | lock_tuner(state); | ||
231 | state->config->pll_init(fe); | ||
232 | unlock_tuner(state); | ||
233 | } | ||
234 | |||
235 | return 0; | ||
236 | } | ||
237 | |||
238 | static int tda10021_set_parameters (struct dvb_frontend *fe, | ||
239 | struct dvb_frontend_parameters *p) | ||
240 | { | ||
241 | struct tda10021_state* state = (struct tda10021_state*) fe->demodulator_priv; | ||
242 | |||
243 | //table for QAM4-QAM256 ready QAM4 QAM16 QAM32 QAM64 QAM128 QAM256 | ||
244 | //CONF | ||
245 | static const u8 reg0x00 [] = { 0x14, 0x00, 0x04, 0x08, 0x0c, 0x10 }; | ||
246 | //AGCREF value | ||
247 | static const u8 reg0x01 [] = { 0x78, 0x8c, 0x8c, 0x6a, 0x78, 0x5c }; | ||
248 | //LTHR value | ||
249 | static const u8 reg0x05 [] = { 0x78, 0x87, 0x64, 0x46, 0x36, 0x26 }; | ||
250 | //MSETH | ||
251 | static const u8 reg0x08 [] = { 0x8c, 0xa2, 0x74, 0x43, 0x34, 0x23 }; | ||
252 | //AREF | ||
253 | static const u8 reg0x09 [] = { 0x96, 0x91, 0x96, 0x6a, 0x7e, 0x6b }; | ||
254 | |||
255 | int qam = p->u.qam.modulation; | ||
256 | |||
257 | if (qam < 0 || qam > 5) | ||
258 | return -EINVAL; | ||
259 | |||
260 | //printk("tda10021: set frequency to %d qam=%d symrate=%d\n", p->frequency,qam,p->u.qam.symbol_rate); | ||
261 | |||
262 | lock_tuner(state); | ||
263 | state->config->pll_set(fe, p); | ||
264 | unlock_tuner(state); | ||
265 | |||
266 | tda10021_set_symbolrate (state, p->u.qam.symbol_rate); | ||
267 | tda10021_writereg (state, 0x34, state->pwm); | ||
268 | |||
269 | tda10021_writereg (state, 0x01, reg0x01[qam]); | ||
270 | tda10021_writereg (state, 0x05, reg0x05[qam]); | ||
271 | tda10021_writereg (state, 0x08, reg0x08[qam]); | ||
272 | tda10021_writereg (state, 0x09, reg0x09[qam]); | ||
273 | |||
274 | tda10021_setup_reg0 (state, reg0x00[qam], p->inversion); | ||
275 | |||
276 | return 0; | ||
277 | } | ||
278 | |||
279 | static int tda10021_read_status(struct dvb_frontend* fe, fe_status_t* status) | ||
280 | { | ||
281 | struct tda10021_state* state = (struct tda10021_state*) fe->demodulator_priv; | ||
282 | int sync; | ||
283 | |||
284 | *status = 0; | ||
285 | //0x11[0] == EQALGO -> Equalizer algorithms state | ||
286 | //0x11[1] == CARLOCK -> Carrier locked | ||
287 | //0x11[2] == FSYNC -> Frame synchronisation | ||
288 | //0x11[3] == FEL -> Front End locked | ||
289 | //0x11[6] == NODVB -> DVB Mode Information | ||
290 | sync = tda10021_readreg (state, 0x11); | ||
291 | |||
292 | if (sync & 2) | ||
293 | *status |= FE_HAS_SIGNAL|FE_HAS_CARRIER; | ||
294 | |||
295 | if (sync & 4) | ||
296 | *status |= FE_HAS_SYNC|FE_HAS_VITERBI; | ||
297 | |||
298 | if (sync & 8) | ||
299 | *status |= FE_HAS_LOCK; | ||
300 | |||
301 | return 0; | ||
302 | } | ||
303 | |||
304 | static int tda10021_read_ber(struct dvb_frontend* fe, u32* ber) | ||
305 | { | ||
306 | struct tda10021_state* state = (struct tda10021_state*) fe->demodulator_priv; | ||
307 | |||
308 | u32 _ber = tda10021_readreg(state, 0x14) | | ||
309 | (tda10021_readreg(state, 0x15) << 8) | | ||
310 | ((tda10021_readreg(state, 0x16) & 0x0f) << 16); | ||
311 | *ber = 10 * _ber; | ||
312 | |||
313 | return 0; | ||
314 | } | ||
315 | |||
316 | static int tda10021_read_signal_strength(struct dvb_frontend* fe, u16* strength) | ||
317 | { | ||
318 | struct tda10021_state* state = (struct tda10021_state*) fe->demodulator_priv; | ||
319 | |||
320 | u8 gain = tda10021_readreg(state, 0x17); | ||
321 | *strength = (gain << 8) | gain; | ||
322 | |||
323 | return 0; | ||
324 | } | ||
325 | |||
326 | static int tda10021_read_snr(struct dvb_frontend* fe, u16* snr) | ||
327 | { | ||
328 | struct tda10021_state* state = (struct tda10021_state*) fe->demodulator_priv; | ||
329 | |||
330 | u8 quality = ~tda10021_readreg(state, 0x18); | ||
331 | *snr = (quality << 8) | quality; | ||
332 | |||
333 | return 0; | ||
334 | } | ||
335 | |||
336 | static int tda10021_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks) | ||
337 | { | ||
338 | struct tda10021_state* state = (struct tda10021_state*) fe->demodulator_priv; | ||
339 | |||
340 | *ucblocks = tda10021_readreg (state, 0x13) & 0x7f; | ||
341 | if (*ucblocks == 0x7f) | ||
342 | *ucblocks = 0xffffffff; | ||
343 | |||
344 | /* reset uncorrected block counter */ | ||
345 | tda10021_writereg (state, 0x10, tda10021_inittab[0x10] & 0xdf); | ||
346 | tda10021_writereg (state, 0x10, tda10021_inittab[0x10]); | ||
347 | |||
348 | return 0; | ||
349 | } | ||
350 | |||
351 | static int tda10021_get_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p) | ||
352 | { | ||
353 | struct tda10021_state* state = (struct tda10021_state*) fe->demodulator_priv; | ||
354 | int sync; | ||
355 | s8 afc = 0; | ||
356 | |||
357 | sync = tda10021_readreg(state, 0x11); | ||
358 | afc = tda10021_readreg(state, 0x19); | ||
359 | if (verbose) { | ||
360 | /* AFC only valid when carrier has been recovered */ | ||
361 | printk(sync & 2 ? "DVB: TDA10021(%d): AFC (%d) %dHz\n" : | ||
362 | "DVB: TDA10021(%d): [AFC (%d) %dHz]\n", | ||
363 | state->frontend.dvb->num, afc, | ||
364 | -((s32)p->u.qam.symbol_rate * afc) >> 10); | ||
365 | } | ||
366 | |||
367 | p->inversion = HAS_INVERSION(state->reg0) ? INVERSION_ON : INVERSION_OFF; | ||
368 | p->u.qam.modulation = ((state->reg0 >> 2) & 7) + QAM_16; | ||
369 | |||
370 | p->u.qam.fec_inner = FEC_NONE; | ||
371 | p->frequency = ((p->frequency + 31250) / 62500) * 62500; | ||
372 | |||
373 | if (sync & 2) | ||
374 | p->frequency -= ((s32)p->u.qam.symbol_rate * afc) >> 10; | ||
375 | |||
376 | return 0; | ||
377 | } | ||
378 | |||
379 | static int tda10021_sleep(struct dvb_frontend* fe) | ||
380 | { | ||
381 | struct tda10021_state* state = (struct tda10021_state*) fe->demodulator_priv; | ||
382 | |||
383 | tda10021_writereg (state, 0x1b, 0x02); /* pdown ADC */ | ||
384 | tda10021_writereg (state, 0x00, 0x80); /* standby */ | ||
385 | |||
386 | return 0; | ||
387 | } | ||
388 | |||
389 | static void tda10021_release(struct dvb_frontend* fe) | ||
390 | { | ||
391 | struct tda10021_state* state = (struct tda10021_state*) fe->demodulator_priv; | ||
392 | kfree(state); | ||
393 | } | ||
394 | |||
395 | static struct dvb_frontend_ops tda10021_ops; | ||
396 | |||
397 | struct dvb_frontend* tda10021_attach(const struct tda10021_config* config, | ||
398 | struct i2c_adapter* i2c, | ||
399 | u8 pwm) | ||
400 | { | ||
401 | struct tda10021_state* state = NULL; | ||
402 | |||
403 | /* allocate memory for the internal state */ | ||
404 | state = (struct tda10021_state*) kmalloc(sizeof(struct tda10021_state), GFP_KERNEL); | ||
405 | if (state == NULL) goto error; | ||
406 | |||
407 | /* setup the state */ | ||
408 | state->config = config; | ||
409 | state->i2c = i2c; | ||
410 | memcpy(&state->ops, &tda10021_ops, sizeof(struct dvb_frontend_ops)); | ||
411 | state->pwm = pwm; | ||
412 | state->reg0 = tda10021_inittab[0]; | ||
413 | |||
414 | /* check if the demod is there */ | ||
415 | if ((tda10021_readreg(state, 0x1a) & 0xf0) != 0x70) goto error; | ||
416 | |||
417 | /* create dvb_frontend */ | ||
418 | state->frontend.ops = &state->ops; | ||
419 | state->frontend.demodulator_priv = state; | ||
420 | return &state->frontend; | ||
421 | |||
422 | error: | ||
423 | kfree(state); | ||
424 | return NULL; | ||
425 | } | ||
426 | |||
427 | static struct dvb_frontend_ops tda10021_ops = { | ||
428 | |||
429 | .info = { | ||
430 | .name = "Philips TDA10021 DVB-C", | ||
431 | .type = FE_QAM, | ||
432 | .frequency_stepsize = 62500, | ||
433 | .frequency_min = 51000000, | ||
434 | .frequency_max = 858000000, | ||
435 | .symbol_rate_min = (XIN/2)/64, /* SACLK/64 == (XIN/2)/64 */ | ||
436 | .symbol_rate_max = (XIN/2)/4, /* SACLK/4 */ | ||
437 | #if 0 | ||
438 | .frequency_tolerance = ???, | ||
439 | .symbol_rate_tolerance = ???, /* ppm */ /* == 8% (spec p. 5) */ | ||
440 | #endif | ||
441 | .caps = 0x400 | //FE_CAN_QAM_4 | ||
442 | FE_CAN_QAM_16 | FE_CAN_QAM_32 | FE_CAN_QAM_64 | | ||
443 | FE_CAN_QAM_128 | FE_CAN_QAM_256 | | ||
444 | FE_CAN_FEC_AUTO | ||
445 | }, | ||
446 | |||
447 | .release = tda10021_release, | ||
448 | |||
449 | .init = tda10021_init, | ||
450 | .sleep = tda10021_sleep, | ||
451 | |||
452 | .set_frontend = tda10021_set_parameters, | ||
453 | .get_frontend = tda10021_get_frontend, | ||
454 | |||
455 | .read_status = tda10021_read_status, | ||
456 | .read_ber = tda10021_read_ber, | ||
457 | .read_signal_strength = tda10021_read_signal_strength, | ||
458 | .read_snr = tda10021_read_snr, | ||
459 | .read_ucblocks = tda10021_read_ucblocks, | ||
460 | }; | ||
461 | |||
462 | module_param(verbose, int, 0644); | ||
463 | MODULE_PARM_DESC(verbose, "print AFC offset after tuning for debugging the PWM setting"); | ||
464 | |||
465 | MODULE_DESCRIPTION("Philips TDA10021 DVB-C demodulator driver"); | ||
466 | MODULE_AUTHOR("Ralph Metzler, Holger Waechtler, Markus Schulz"); | ||
467 | MODULE_LICENSE("GPL"); | ||
468 | |||
469 | EXPORT_SYMBOL(tda10021_attach); | ||
diff --git a/drivers/media/dvb/frontends/tda10021.h b/drivers/media/dvb/frontends/tda10021.h new file mode 100644 index 000000000000..7d6a51ce291e --- /dev/null +++ b/drivers/media/dvb/frontends/tda10021.h | |||
@@ -0,0 +1,42 @@ | |||
1 | /* | ||
2 | TDA10021 - Single Chip Cable Channel Receiver driver module | ||
3 | used on the the Siemens DVB-C cards | ||
4 | |||
5 | Copyright (C) 1999 Convergence Integrated Media GmbH <ralph@convergence.de> | ||
6 | Copyright (C) 2004 Markus Schulz <msc@antzsystem.de> | ||
7 | Support for TDA10021 | ||
8 | |||
9 | This program is free software; you can redistribute it and/or modify | ||
10 | it under the terms of the GNU General Public License as published by | ||
11 | the Free Software Foundation; either version 2 of the License, or | ||
12 | (at your option) any later version. | ||
13 | |||
14 | This program is distributed in the hope that it will be useful, | ||
15 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
16 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
17 | GNU General Public License for more details. | ||
18 | |||
19 | You should have received a copy of the GNU General Public License | ||
20 | along with this program; if not, write to the Free Software | ||
21 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
22 | */ | ||
23 | |||
24 | #ifndef TDA10021_H | ||
25 | #define TDA10021_H | ||
26 | |||
27 | #include <linux/dvb/frontend.h> | ||
28 | |||
29 | struct tda10021_config | ||
30 | { | ||
31 | /* the demodulator's i2c address */ | ||
32 | u8 demod_address; | ||
33 | |||
34 | /* PLL maintenance */ | ||
35 | int (*pll_init)(struct dvb_frontend* fe); | ||
36 | int (*pll_set)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params); | ||
37 | }; | ||
38 | |||
39 | extern struct dvb_frontend* tda10021_attach(const struct tda10021_config* config, | ||
40 | struct i2c_adapter* i2c, u8 pwm); | ||
41 | |||
42 | #endif // TDA10021_H | ||
diff --git a/drivers/media/dvb/frontends/tda1004x.c b/drivers/media/dvb/frontends/tda1004x.c new file mode 100644 index 000000000000..687ad9cf3384 --- /dev/null +++ b/drivers/media/dvb/frontends/tda1004x.c | |||
@@ -0,0 +1,1206 @@ | |||
1 | /* | ||
2 | Driver for Philips tda1004xh OFDM Demodulator | ||
3 | |||
4 | (c) 2003, 2004 Andrew de Quincey & Robert Schlabbach | ||
5 | |||
6 | This program is free software; you can redistribute it and/or modify | ||
7 | it under the terms of the GNU General Public License as published by | ||
8 | the Free Software Foundation; either version 2 of the License, or | ||
9 | (at your option) any later version. | ||
10 | |||
11 | This program is distributed in the hope that it will be useful, | ||
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | |||
15 | GNU General Public License for more details. | ||
16 | |||
17 | You should have received a copy of the GNU General Public License | ||
18 | along with this program; if not, write to the Free Software | ||
19 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
20 | |||
21 | */ | ||
22 | /* | ||
23 | * This driver needs external firmware. Please use the commands | ||
24 | * "<kerneldir>/Documentation/dvb/get_dvb_firmware tda10045", | ||
25 | * "<kerneldir>/Documentation/dvb/get_dvb_firmware tda10046" to | ||
26 | * download/extract them, and then copy them to /usr/lib/hotplug/firmware. | ||
27 | */ | ||
28 | #define TDA10045_DEFAULT_FIRMWARE "dvb-fe-tda10045.fw" | ||
29 | #define TDA10046_DEFAULT_FIRMWARE "dvb-fe-tda10046.fw" | ||
30 | |||
31 | #include <linux/init.h> | ||
32 | #include <linux/module.h> | ||
33 | #include <linux/moduleparam.h> | ||
34 | #include <linux/device.h> | ||
35 | #include "dvb_frontend.h" | ||
36 | #include "tda1004x.h" | ||
37 | |||
38 | #define TDA1004X_DEMOD_TDA10045 0 | ||
39 | #define TDA1004X_DEMOD_TDA10046 1 | ||
40 | |||
41 | |||
42 | struct tda1004x_state { | ||
43 | struct i2c_adapter* i2c; | ||
44 | struct dvb_frontend_ops ops; | ||
45 | const struct tda1004x_config* config; | ||
46 | struct dvb_frontend frontend; | ||
47 | |||
48 | /* private demod data */ | ||
49 | u8 initialised:1; | ||
50 | u8 demod_type; | ||
51 | }; | ||
52 | |||
53 | |||
54 | static int debug; | ||
55 | #define dprintk(args...) \ | ||
56 | do { \ | ||
57 | if (debug) printk(KERN_DEBUG "tda1004x: " args); \ | ||
58 | } while (0) | ||
59 | |||
60 | #define TDA1004X_CHIPID 0x00 | ||
61 | #define TDA1004X_AUTO 0x01 | ||
62 | #define TDA1004X_IN_CONF1 0x02 | ||
63 | #define TDA1004X_IN_CONF2 0x03 | ||
64 | #define TDA1004X_OUT_CONF1 0x04 | ||
65 | #define TDA1004X_OUT_CONF2 0x05 | ||
66 | #define TDA1004X_STATUS_CD 0x06 | ||
67 | #define TDA1004X_CONFC4 0x07 | ||
68 | #define TDA1004X_DSSPARE2 0x0C | ||
69 | #define TDA10045H_CODE_IN 0x0D | ||
70 | #define TDA10045H_FWPAGE 0x0E | ||
71 | #define TDA1004X_SCAN_CPT 0x10 | ||
72 | #define TDA1004X_DSP_CMD 0x11 | ||
73 | #define TDA1004X_DSP_ARG 0x12 | ||
74 | #define TDA1004X_DSP_DATA1 0x13 | ||
75 | #define TDA1004X_DSP_DATA2 0x14 | ||
76 | #define TDA1004X_CONFADC1 0x15 | ||
77 | #define TDA1004X_CONFC1 0x16 | ||
78 | #define TDA10045H_S_AGC 0x1a | ||
79 | #define TDA10046H_AGC_TUN_LEVEL 0x1a | ||
80 | #define TDA1004X_SNR 0x1c | ||
81 | #define TDA1004X_CONF_TS1 0x1e | ||
82 | #define TDA1004X_CONF_TS2 0x1f | ||
83 | #define TDA1004X_CBER_RESET 0x20 | ||
84 | #define TDA1004X_CBER_MSB 0x21 | ||
85 | #define TDA1004X_CBER_LSB 0x22 | ||
86 | #define TDA1004X_CVBER_LUT 0x23 | ||
87 | #define TDA1004X_VBER_MSB 0x24 | ||
88 | #define TDA1004X_VBER_MID 0x25 | ||
89 | #define TDA1004X_VBER_LSB 0x26 | ||
90 | #define TDA1004X_UNCOR 0x27 | ||
91 | |||
92 | #define TDA10045H_CONFPLL_P 0x2D | ||
93 | #define TDA10045H_CONFPLL_M_MSB 0x2E | ||
94 | #define TDA10045H_CONFPLL_M_LSB 0x2F | ||
95 | #define TDA10045H_CONFPLL_N 0x30 | ||
96 | |||
97 | #define TDA10046H_CONFPLL1 0x2D | ||
98 | #define TDA10046H_CONFPLL2 0x2F | ||
99 | #define TDA10046H_CONFPLL3 0x30 | ||
100 | #define TDA10046H_TIME_WREF1 0x31 | ||
101 | #define TDA10046H_TIME_WREF2 0x32 | ||
102 | #define TDA10046H_TIME_WREF3 0x33 | ||
103 | #define TDA10046H_TIME_WREF4 0x34 | ||
104 | #define TDA10046H_TIME_WREF5 0x35 | ||
105 | |||
106 | #define TDA10045H_UNSURW_MSB 0x31 | ||
107 | #define TDA10045H_UNSURW_LSB 0x32 | ||
108 | #define TDA10045H_WREF_MSB 0x33 | ||
109 | #define TDA10045H_WREF_MID 0x34 | ||
110 | #define TDA10045H_WREF_LSB 0x35 | ||
111 | #define TDA10045H_MUXOUT 0x36 | ||
112 | #define TDA1004X_CONFADC2 0x37 | ||
113 | |||
114 | #define TDA10045H_IOFFSET 0x38 | ||
115 | |||
116 | #define TDA10046H_CONF_TRISTATE1 0x3B | ||
117 | #define TDA10046H_CONF_TRISTATE2 0x3C | ||
118 | #define TDA10046H_CONF_POLARITY 0x3D | ||
119 | #define TDA10046H_FREQ_OFFSET 0x3E | ||
120 | #define TDA10046H_GPIO_OUT_SEL 0x41 | ||
121 | #define TDA10046H_GPIO_SELECT 0x42 | ||
122 | #define TDA10046H_AGC_CONF 0x43 | ||
123 | #define TDA10046H_AGC_GAINS 0x46 | ||
124 | #define TDA10046H_AGC_TUN_MIN 0x47 | ||
125 | #define TDA10046H_AGC_TUN_MAX 0x48 | ||
126 | #define TDA10046H_AGC_IF_MIN 0x49 | ||
127 | #define TDA10046H_AGC_IF_MAX 0x4A | ||
128 | |||
129 | #define TDA10046H_FREQ_PHY2_MSB 0x4D | ||
130 | #define TDA10046H_FREQ_PHY2_LSB 0x4E | ||
131 | |||
132 | #define TDA10046H_CVBER_CTRL 0x4F | ||
133 | #define TDA10046H_AGC_IF_LEVEL 0x52 | ||
134 | #define TDA10046H_CODE_CPT 0x57 | ||
135 | #define TDA10046H_CODE_IN 0x58 | ||
136 | |||
137 | |||
138 | static int tda1004x_write_byteI(struct tda1004x_state *state, int reg, int data) | ||
139 | { | ||
140 | int ret; | ||
141 | u8 buf[] = { reg, data }; | ||
142 | struct i2c_msg msg = { .addr=0, .flags=0, .buf=buf, .len=2 }; | ||
143 | |||
144 | dprintk("%s: reg=0x%x, data=0x%x\n", __FUNCTION__, reg, data); | ||
145 | |||
146 | msg.addr = state->config->demod_address; | ||
147 | ret = i2c_transfer(state->i2c, &msg, 1); | ||
148 | |||
149 | if (ret != 1) | ||
150 | dprintk("%s: error reg=0x%x, data=0x%x, ret=%i\n", | ||
151 | __FUNCTION__, reg, data, ret); | ||
152 | |||
153 | dprintk("%s: success reg=0x%x, data=0x%x, ret=%i\n", __FUNCTION__, | ||
154 | reg, data, ret); | ||
155 | return (ret != 1) ? -1 : 0; | ||
156 | } | ||
157 | |||
158 | static int tda1004x_read_byte(struct tda1004x_state *state, int reg) | ||
159 | { | ||
160 | int ret; | ||
161 | u8 b0[] = { reg }; | ||
162 | u8 b1[] = { 0 }; | ||
163 | struct i2c_msg msg[] = {{ .addr=0, .flags=0, .buf=b0, .len=1}, | ||
164 | { .addr=0, .flags=I2C_M_RD, .buf=b1, .len = 1}}; | ||
165 | |||
166 | dprintk("%s: reg=0x%x\n", __FUNCTION__, reg); | ||
167 | |||
168 | msg[0].addr = state->config->demod_address; | ||
169 | msg[1].addr = state->config->demod_address; | ||
170 | ret = i2c_transfer(state->i2c, msg, 2); | ||
171 | |||
172 | if (ret != 2) { | ||
173 | dprintk("%s: error reg=0x%x, ret=%i\n", __FUNCTION__, reg, | ||
174 | ret); | ||
175 | return -1; | ||
176 | } | ||
177 | |||
178 | dprintk("%s: success reg=0x%x, data=0x%x, ret=%i\n", __FUNCTION__, | ||
179 | reg, b1[0], ret); | ||
180 | return b1[0]; | ||
181 | } | ||
182 | |||
183 | static int tda1004x_write_mask(struct tda1004x_state *state, int reg, int mask, int data) | ||
184 | { | ||
185 | int val; | ||
186 | dprintk("%s: reg=0x%x, mask=0x%x, data=0x%x\n", __FUNCTION__, reg, | ||
187 | mask, data); | ||
188 | |||
189 | // read a byte and check | ||
190 | val = tda1004x_read_byte(state, reg); | ||
191 | if (val < 0) | ||
192 | return val; | ||
193 | |||
194 | // mask if off | ||
195 | val = val & ~mask; | ||
196 | val |= data & 0xff; | ||
197 | |||
198 | // write it out again | ||
199 | return tda1004x_write_byteI(state, reg, val); | ||
200 | } | ||
201 | |||
202 | static int tda1004x_write_buf(struct tda1004x_state *state, int reg, unsigned char *buf, int len) | ||
203 | { | ||
204 | int i; | ||
205 | int result; | ||
206 | |||
207 | dprintk("%s: reg=0x%x, len=0x%x\n", __FUNCTION__, reg, len); | ||
208 | |||
209 | result = 0; | ||
210 | for (i = 0; i < len; i++) { | ||
211 | result = tda1004x_write_byteI(state, reg + i, buf[i]); | ||
212 | if (result != 0) | ||
213 | break; | ||
214 | } | ||
215 | |||
216 | return result; | ||
217 | } | ||
218 | |||
219 | static int tda1004x_enable_tuner_i2c(struct tda1004x_state *state) | ||
220 | { | ||
221 | int result; | ||
222 | dprintk("%s\n", __FUNCTION__); | ||
223 | |||
224 | result = tda1004x_write_mask(state, TDA1004X_CONFC4, 2, 2); | ||
225 | msleep(1); | ||
226 | return result; | ||
227 | } | ||
228 | |||
229 | static int tda1004x_disable_tuner_i2c(struct tda1004x_state *state) | ||
230 | { | ||
231 | dprintk("%s\n", __FUNCTION__); | ||
232 | |||
233 | return tda1004x_write_mask(state, TDA1004X_CONFC4, 2, 0); | ||
234 | } | ||
235 | |||
236 | static int tda10045h_set_bandwidth(struct tda1004x_state *state, | ||
237 | fe_bandwidth_t bandwidth) | ||
238 | { | ||
239 | static u8 bandwidth_6mhz[] = { 0x02, 0x00, 0x3d, 0x00, 0x60, 0x1e, 0xa7, 0x45, 0x4f }; | ||
240 | static u8 bandwidth_7mhz[] = { 0x02, 0x00, 0x37, 0x00, 0x4a, 0x2f, 0x6d, 0x76, 0xdb }; | ||
241 | static u8 bandwidth_8mhz[] = { 0x02, 0x00, 0x3d, 0x00, 0x48, 0x17, 0x89, 0xc7, 0x14 }; | ||
242 | |||
243 | switch (bandwidth) { | ||
244 | case BANDWIDTH_6_MHZ: | ||
245 | tda1004x_write_buf(state, TDA10045H_CONFPLL_P, bandwidth_6mhz, sizeof(bandwidth_6mhz)); | ||
246 | break; | ||
247 | |||
248 | case BANDWIDTH_7_MHZ: | ||
249 | tda1004x_write_buf(state, TDA10045H_CONFPLL_P, bandwidth_7mhz, sizeof(bandwidth_7mhz)); | ||
250 | break; | ||
251 | |||
252 | case BANDWIDTH_8_MHZ: | ||
253 | tda1004x_write_buf(state, TDA10045H_CONFPLL_P, bandwidth_8mhz, sizeof(bandwidth_8mhz)); | ||
254 | break; | ||
255 | |||
256 | default: | ||
257 | return -EINVAL; | ||
258 | } | ||
259 | |||
260 | tda1004x_write_byteI(state, TDA10045H_IOFFSET, 0); | ||
261 | |||
262 | return 0; | ||
263 | } | ||
264 | |||
265 | static int tda10046h_set_bandwidth(struct tda1004x_state *state, | ||
266 | fe_bandwidth_t bandwidth) | ||
267 | { | ||
268 | static u8 bandwidth_6mhz[] = { 0x80, 0x15, 0xfe, 0xab, 0x8e }; | ||
269 | static u8 bandwidth_7mhz[] = { 0x6e, 0x02, 0x53, 0xc8, 0x25 }; | ||
270 | static u8 bandwidth_8mhz[] = { 0x60, 0x12, 0xa8, 0xe4, 0xbd }; | ||
271 | |||
272 | switch (bandwidth) { | ||
273 | case BANDWIDTH_6_MHZ: | ||
274 | tda1004x_write_buf(state, TDA10046H_TIME_WREF1, bandwidth_6mhz, sizeof(bandwidth_6mhz)); | ||
275 | break; | ||
276 | |||
277 | case BANDWIDTH_7_MHZ: | ||
278 | tda1004x_write_buf(state, TDA10046H_TIME_WREF1, bandwidth_7mhz, sizeof(bandwidth_7mhz)); | ||
279 | break; | ||
280 | |||
281 | case BANDWIDTH_8_MHZ: | ||
282 | tda1004x_write_buf(state, TDA10046H_TIME_WREF1, bandwidth_8mhz, sizeof(bandwidth_8mhz)); | ||
283 | break; | ||
284 | |||
285 | default: | ||
286 | return -EINVAL; | ||
287 | } | ||
288 | |||
289 | return 0; | ||
290 | } | ||
291 | |||
292 | static int tda1004x_do_upload(struct tda1004x_state *state, | ||
293 | unsigned char *mem, unsigned int len, | ||
294 | u8 dspCodeCounterReg, u8 dspCodeInReg) | ||
295 | { | ||
296 | u8 buf[65]; | ||
297 | struct i2c_msg fw_msg = {.addr = 0,.flags = 0,.buf = buf,.len = 0 }; | ||
298 | int tx_size; | ||
299 | int pos = 0; | ||
300 | |||
301 | /* clear code counter */ | ||
302 | tda1004x_write_byteI(state, dspCodeCounterReg, 0); | ||
303 | fw_msg.addr = state->config->demod_address; | ||
304 | |||
305 | buf[0] = dspCodeInReg; | ||
306 | while (pos != len) { | ||
307 | |||
308 | // work out how much to send this time | ||
309 | tx_size = len - pos; | ||
310 | if (tx_size > 0x10) { | ||
311 | tx_size = 0x10; | ||
312 | } | ||
313 | |||
314 | // send the chunk | ||
315 | memcpy(buf + 1, mem + pos, tx_size); | ||
316 | fw_msg.len = tx_size + 1; | ||
317 | if (i2c_transfer(state->i2c, &fw_msg, 1) != 1) { | ||
318 | printk("tda1004x: Error during firmware upload\n"); | ||
319 | return -EIO; | ||
320 | } | ||
321 | pos += tx_size; | ||
322 | |||
323 | dprintk("%s: fw_pos=0x%x\n", __FUNCTION__, pos); | ||
324 | } | ||
325 | return 0; | ||
326 | } | ||
327 | |||
328 | static int tda1004x_check_upload_ok(struct tda1004x_state *state, u8 dspVersion) | ||
329 | { | ||
330 | u8 data1, data2; | ||
331 | |||
332 | // check upload was OK | ||
333 | tda1004x_write_mask(state, TDA1004X_CONFC4, 0x10, 0); // we want to read from the DSP | ||
334 | tda1004x_write_byteI(state, TDA1004X_DSP_CMD, 0x67); | ||
335 | |||
336 | data1 = tda1004x_read_byte(state, TDA1004X_DSP_DATA1); | ||
337 | data2 = tda1004x_read_byte(state, TDA1004X_DSP_DATA2); | ||
338 | if (data1 != 0x67 || data2 != dspVersion) { | ||
339 | return -EIO; | ||
340 | } | ||
341 | |||
342 | return 0; | ||
343 | } | ||
344 | |||
345 | static int tda10045_fwupload(struct dvb_frontend* fe) | ||
346 | { | ||
347 | struct tda1004x_state* state = fe->demodulator_priv; | ||
348 | int ret; | ||
349 | const struct firmware *fw; | ||
350 | |||
351 | |||
352 | /* don't re-upload unless necessary */ | ||
353 | if (tda1004x_check_upload_ok(state, 0x2c) == 0) return 0; | ||
354 | |||
355 | /* request the firmware, this will block until someone uploads it */ | ||
356 | printk("tda1004x: waiting for firmware upload (%s)...\n", TDA10045_DEFAULT_FIRMWARE); | ||
357 | ret = state->config->request_firmware(fe, &fw, TDA10045_DEFAULT_FIRMWARE); | ||
358 | if (ret) { | ||
359 | printk("tda1004x: no firmware upload (timeout or file not found?)\n"); | ||
360 | return ret; | ||
361 | } | ||
362 | |||
363 | /* reset chip */ | ||
364 | tda1004x_write_mask(state, TDA1004X_CONFC4, 0x10, 0); | ||
365 | tda1004x_write_mask(state, TDA1004X_CONFC4, 8, 8); | ||
366 | tda1004x_write_mask(state, TDA1004X_CONFC4, 8, 0); | ||
367 | msleep(10); | ||
368 | |||
369 | /* set parameters */ | ||
370 | tda10045h_set_bandwidth(state, BANDWIDTH_8_MHZ); | ||
371 | |||
372 | ret = tda1004x_do_upload(state, fw->data, fw->size, TDA10045H_FWPAGE, TDA10045H_CODE_IN); | ||
373 | if (ret) | ||
374 | return ret; | ||
375 | printk("tda1004x: firmware upload complete\n"); | ||
376 | |||
377 | /* wait for DSP to initialise */ | ||
378 | /* DSPREADY doesn't seem to work on the TDA10045H */ | ||
379 | msleep(100); | ||
380 | |||
381 | return tda1004x_check_upload_ok(state, 0x2c); | ||
382 | } | ||
383 | |||
384 | static int tda10046_fwupload(struct dvb_frontend* fe) | ||
385 | { | ||
386 | struct tda1004x_state* state = fe->demodulator_priv; | ||
387 | unsigned long timeout; | ||
388 | int ret; | ||
389 | const struct firmware *fw; | ||
390 | |||
391 | /* reset + wake up chip */ | ||
392 | tda1004x_write_mask(state, TDA1004X_CONFC4, 1, 0); | ||
393 | tda1004x_write_mask(state, TDA10046H_CONF_TRISTATE1, 1, 0); | ||
394 | msleep(100); | ||
395 | |||
396 | /* don't re-upload unless necessary */ | ||
397 | if (tda1004x_check_upload_ok(state, 0x20) == 0) return 0; | ||
398 | |||
399 | /* request the firmware, this will block until someone uploads it */ | ||
400 | printk("tda1004x: waiting for firmware upload (%s)...\n", TDA10046_DEFAULT_FIRMWARE); | ||
401 | ret = state->config->request_firmware(fe, &fw, TDA10046_DEFAULT_FIRMWARE); | ||
402 | if (ret) { | ||
403 | printk("tda1004x: no firmware upload (timeout or file not found?)\n"); | ||
404 | return ret; | ||
405 | } | ||
406 | |||
407 | /* set parameters */ | ||
408 | tda1004x_write_byteI(state, TDA10046H_CONFPLL2, 10); | ||
409 | tda1004x_write_byteI(state, TDA10046H_CONFPLL3, 0); | ||
410 | tda1004x_write_byteI(state, TDA10046H_FREQ_OFFSET, 99); | ||
411 | tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_MSB, 0xd4); | ||
412 | tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_LSB, 0x2c); | ||
413 | tda1004x_write_mask(state, TDA1004X_CONFC4, 8, 8); // going to boot from HOST | ||
414 | |||
415 | ret = tda1004x_do_upload(state, fw->data, fw->size, TDA10046H_CODE_CPT, TDA10046H_CODE_IN); | ||
416 | if (ret) | ||
417 | return ret; | ||
418 | printk("tda1004x: firmware upload complete\n"); | ||
419 | |||
420 | /* wait for DSP to initialise */ | ||
421 | timeout = jiffies + HZ; | ||
422 | while(!(tda1004x_read_byte(state, TDA1004X_STATUS_CD) & 0x20)) { | ||
423 | if (time_after(jiffies, timeout)) { | ||
424 | printk("tda1004x: DSP failed to initialised.\n"); | ||
425 | return -EIO; | ||
426 | } | ||
427 | msleep(1); | ||
428 | } | ||
429 | |||
430 | return tda1004x_check_upload_ok(state, 0x20); | ||
431 | } | ||
432 | |||
433 | static int tda1004x_encode_fec(int fec) | ||
434 | { | ||
435 | // convert known FEC values | ||
436 | switch (fec) { | ||
437 | case FEC_1_2: | ||
438 | return 0; | ||
439 | case FEC_2_3: | ||
440 | return 1; | ||
441 | case FEC_3_4: | ||
442 | return 2; | ||
443 | case FEC_5_6: | ||
444 | return 3; | ||
445 | case FEC_7_8: | ||
446 | return 4; | ||
447 | } | ||
448 | |||
449 | // unsupported | ||
450 | return -EINVAL; | ||
451 | } | ||
452 | |||
453 | static int tda1004x_decode_fec(int tdafec) | ||
454 | { | ||
455 | // convert known FEC values | ||
456 | switch (tdafec) { | ||
457 | case 0: | ||
458 | return FEC_1_2; | ||
459 | case 1: | ||
460 | return FEC_2_3; | ||
461 | case 2: | ||
462 | return FEC_3_4; | ||
463 | case 3: | ||
464 | return FEC_5_6; | ||
465 | case 4: | ||
466 | return FEC_7_8; | ||
467 | } | ||
468 | |||
469 | // unsupported | ||
470 | return -1; | ||
471 | } | ||
472 | |||
473 | int tda1004x_write_byte(struct dvb_frontend* fe, int reg, int data) | ||
474 | { | ||
475 | struct tda1004x_state* state = fe->demodulator_priv; | ||
476 | |||
477 | return tda1004x_write_byteI(state, reg, data); | ||
478 | } | ||
479 | |||
480 | static int tda10045_init(struct dvb_frontend* fe) | ||
481 | { | ||
482 | struct tda1004x_state* state = fe->demodulator_priv; | ||
483 | |||
484 | dprintk("%s\n", __FUNCTION__); | ||
485 | |||
486 | if (state->initialised) return 0; | ||
487 | |||
488 | if (tda10045_fwupload(fe)) { | ||
489 | printk("tda1004x: firmware upload failed\n"); | ||
490 | return -EIO; | ||
491 | } | ||
492 | |||
493 | tda1004x_write_mask(state, TDA1004X_CONFADC1, 0x10, 0); // wake up the ADC | ||
494 | |||
495 | // Init the PLL | ||
496 | if (state->config->pll_init) { | ||
497 | tda1004x_enable_tuner_i2c(state); | ||
498 | state->config->pll_init(fe); | ||
499 | tda1004x_disable_tuner_i2c(state); | ||
500 | } | ||
501 | |||
502 | // tda setup | ||
503 | tda1004x_write_mask(state, TDA1004X_CONFC4, 0x20, 0); // disable DSP watchdog timer | ||
504 | tda1004x_write_mask(state, TDA1004X_AUTO, 8, 0); // select HP stream | ||
505 | tda1004x_write_mask(state, TDA1004X_CONFC1, 0x40, 0); // set polarity of VAGC signal | ||
506 | tda1004x_write_mask(state, TDA1004X_CONFC1, 0x80, 0x80); // enable pulse killer | ||
507 | tda1004x_write_mask(state, TDA1004X_AUTO, 0x10, 0x10); // enable auto offset | ||
508 | tda1004x_write_mask(state, TDA1004X_IN_CONF2, 0xC0, 0x0); // no frequency offset | ||
509 | tda1004x_write_byteI(state, TDA1004X_CONF_TS1, 0); // setup MPEG2 TS interface | ||
510 | tda1004x_write_byteI(state, TDA1004X_CONF_TS2, 0); // setup MPEG2 TS interface | ||
511 | tda1004x_write_mask(state, TDA1004X_VBER_MSB, 0xe0, 0xa0); // 10^6 VBER measurement bits | ||
512 | tda1004x_write_mask(state, TDA1004X_CONFC1, 0x10, 0); // VAGC polarity | ||
513 | tda1004x_write_byteI(state, TDA1004X_CONFADC1, 0x2e); | ||
514 | |||
515 | tda1004x_write_mask(state, 0x1f, 0x01, state->config->invert_oclk); | ||
516 | |||
517 | state->initialised = 1; | ||
518 | return 0; | ||
519 | } | ||
520 | |||
521 | static int tda10046_init(struct dvb_frontend* fe) | ||
522 | { | ||
523 | struct tda1004x_state* state = fe->demodulator_priv; | ||
524 | dprintk("%s\n", __FUNCTION__); | ||
525 | |||
526 | if (state->initialised) return 0; | ||
527 | |||
528 | if (tda10046_fwupload(fe)) { | ||
529 | printk("tda1004x: firmware upload failed\n"); | ||
530 | return -EIO; | ||
531 | } | ||
532 | |||
533 | tda1004x_write_mask(state, TDA1004X_CONFC4, 1, 0); // wake up the chip | ||
534 | |||
535 | // Init the PLL | ||
536 | if (state->config->pll_init) { | ||
537 | tda1004x_enable_tuner_i2c(state); | ||
538 | state->config->pll_init(fe); | ||
539 | tda1004x_disable_tuner_i2c(state); | ||
540 | } | ||
541 | |||
542 | // tda setup | ||
543 | tda1004x_write_mask(state, TDA1004X_CONFC4, 0x20, 0); // disable DSP watchdog timer | ||
544 | tda1004x_write_mask(state, TDA1004X_CONFC1, 0x40, 0x40); | ||
545 | tda1004x_write_mask(state, TDA1004X_AUTO, 8, 0); // select HP stream | ||
546 | tda1004x_write_mask(state, TDA1004X_CONFC1, 0x80, 0); // disable pulse killer | ||
547 | tda1004x_write_byteI(state, TDA10046H_CONFPLL2, 10); // PLL M = 10 | ||
548 | tda1004x_write_byteI(state, TDA10046H_CONFPLL3, 0); // PLL P = N = 0 | ||
549 | tda1004x_write_byteI(state, TDA10046H_FREQ_OFFSET, 99); // FREQOFFS = 99 | ||
550 | tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_MSB, 0xd4); // } PHY2 = -11221 | ||
551 | tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_LSB, 0x2c); // } | ||
552 | tda1004x_write_byteI(state, TDA10046H_AGC_CONF, 0); // AGC setup | ||
553 | tda1004x_write_mask(state, TDA10046H_CONF_POLARITY, 0x60, 0x60); // set AGC polarities | ||
554 | tda1004x_write_byteI(state, TDA10046H_AGC_TUN_MIN, 0); // } | ||
555 | tda1004x_write_byteI(state, TDA10046H_AGC_TUN_MAX, 0xff); // } AGC min/max values | ||
556 | tda1004x_write_byteI(state, TDA10046H_AGC_IF_MIN, 0); // } | ||
557 | tda1004x_write_byteI(state, TDA10046H_AGC_IF_MAX, 0xff); // } | ||
558 | tda1004x_write_mask(state, TDA10046H_CVBER_CTRL, 0x30, 0x10); // 10^6 VBER measurement bits | ||
559 | tda1004x_write_byteI(state, TDA10046H_AGC_GAINS, 1); // IF gain 2, TUN gain 1 | ||
560 | tda1004x_write_mask(state, TDA1004X_AUTO, 0x80, 0); // crystal is 50ppm | ||
561 | tda1004x_write_byteI(state, TDA1004X_CONF_TS1, 7); // MPEG2 interface config | ||
562 | tda1004x_write_mask(state, TDA1004X_CONF_TS2, 0x31, 0); // MPEG2 interface config | ||
563 | tda1004x_write_mask(state, TDA10046H_CONF_TRISTATE1, 0x9e, 0); // disable AGC_TUN | ||
564 | tda1004x_write_byteI(state, TDA10046H_CONF_TRISTATE2, 0xe1); // tristate setup | ||
565 | tda1004x_write_byteI(state, TDA10046H_GPIO_OUT_SEL, 0xcc); // GPIO output config | ||
566 | tda1004x_write_mask(state, TDA10046H_GPIO_SELECT, 8, 8); // GPIO select | ||
567 | tda10046h_set_bandwidth(state, BANDWIDTH_8_MHZ); // default bandwidth 8 MHz | ||
568 | |||
569 | tda1004x_write_mask(state, 0x3a, 0x80, state->config->invert_oclk << 7); | ||
570 | |||
571 | state->initialised = 1; | ||
572 | return 0; | ||
573 | } | ||
574 | |||
575 | static int tda1004x_set_fe(struct dvb_frontend* fe, | ||
576 | struct dvb_frontend_parameters *fe_params) | ||
577 | { | ||
578 | struct tda1004x_state* state = fe->demodulator_priv; | ||
579 | int tmp; | ||
580 | int inversion; | ||
581 | |||
582 | dprintk("%s\n", __FUNCTION__); | ||
583 | |||
584 | if (state->demod_type == TDA1004X_DEMOD_TDA10046) { | ||
585 | // setup auto offset | ||
586 | tda1004x_write_mask(state, TDA1004X_AUTO, 0x10, 0x10); | ||
587 | tda1004x_write_mask(state, TDA1004X_IN_CONF1, 0x80, 0); | ||
588 | tda1004x_write_mask(state, TDA1004X_IN_CONF2, 0xC0, 0); | ||
589 | |||
590 | // disable agc_conf[2] | ||
591 | tda1004x_write_mask(state, TDA10046H_AGC_CONF, 4, 0); | ||
592 | } | ||
593 | |||
594 | // set frequency | ||
595 | tda1004x_enable_tuner_i2c(state); | ||
596 | state->config->pll_set(fe, fe_params); | ||
597 | tda1004x_disable_tuner_i2c(state); | ||
598 | |||
599 | if (state->demod_type == TDA1004X_DEMOD_TDA10046) | ||
600 | tda1004x_write_mask(state, TDA10046H_AGC_CONF, 4, 4); | ||
601 | |||
602 | // Hardcoded to use auto as much as possible on the TDA10045 as it | ||
603 | // is very unreliable if AUTO mode is _not_ used. | ||
604 | if (state->demod_type == TDA1004X_DEMOD_TDA10045) { | ||
605 | fe_params->u.ofdm.code_rate_HP = FEC_AUTO; | ||
606 | fe_params->u.ofdm.guard_interval = GUARD_INTERVAL_AUTO; | ||
607 | fe_params->u.ofdm.transmission_mode = TRANSMISSION_MODE_AUTO; | ||
608 | } | ||
609 | |||
610 | // Set standard params.. or put them to auto | ||
611 | if ((fe_params->u.ofdm.code_rate_HP == FEC_AUTO) || | ||
612 | (fe_params->u.ofdm.code_rate_LP == FEC_AUTO) || | ||
613 | (fe_params->u.ofdm.constellation == QAM_AUTO) || | ||
614 | (fe_params->u.ofdm.hierarchy_information == HIERARCHY_AUTO)) { | ||
615 | tda1004x_write_mask(state, TDA1004X_AUTO, 1, 1); // enable auto | ||
616 | tda1004x_write_mask(state, TDA1004X_IN_CONF1, 0x03, 0); // turn off constellation bits | ||
617 | tda1004x_write_mask(state, TDA1004X_IN_CONF1, 0x60, 0); // turn off hierarchy bits | ||
618 | tda1004x_write_mask(state, TDA1004X_IN_CONF2, 0x3f, 0); // turn off FEC bits | ||
619 | } else { | ||
620 | tda1004x_write_mask(state, TDA1004X_AUTO, 1, 0); // disable auto | ||
621 | |||
622 | // set HP FEC | ||
623 | tmp = tda1004x_encode_fec(fe_params->u.ofdm.code_rate_HP); | ||
624 | if (tmp < 0) return tmp; | ||
625 | tda1004x_write_mask(state, TDA1004X_IN_CONF2, 7, tmp); | ||
626 | |||
627 | // set LP FEC | ||
628 | tmp = tda1004x_encode_fec(fe_params->u.ofdm.code_rate_LP); | ||
629 | if (tmp < 0) return tmp; | ||
630 | tda1004x_write_mask(state, TDA1004X_IN_CONF2, 0x38, tmp << 3); | ||
631 | |||
632 | // set constellation | ||
633 | switch (fe_params->u.ofdm.constellation) { | ||
634 | case QPSK: | ||
635 | tda1004x_write_mask(state, TDA1004X_IN_CONF1, 3, 0); | ||
636 | break; | ||
637 | |||
638 | case QAM_16: | ||
639 | tda1004x_write_mask(state, TDA1004X_IN_CONF1, 3, 1); | ||
640 | break; | ||
641 | |||
642 | case QAM_64: | ||
643 | tda1004x_write_mask(state, TDA1004X_IN_CONF1, 3, 2); | ||
644 | break; | ||
645 | |||
646 | default: | ||
647 | return -EINVAL; | ||
648 | } | ||
649 | |||
650 | // set hierarchy | ||
651 | switch (fe_params->u.ofdm.hierarchy_information) { | ||
652 | case HIERARCHY_NONE: | ||
653 | tda1004x_write_mask(state, TDA1004X_IN_CONF1, 0x60, 0 << 5); | ||
654 | break; | ||
655 | |||
656 | case HIERARCHY_1: | ||
657 | tda1004x_write_mask(state, TDA1004X_IN_CONF1, 0x60, 1 << 5); | ||
658 | break; | ||
659 | |||
660 | case HIERARCHY_2: | ||
661 | tda1004x_write_mask(state, TDA1004X_IN_CONF1, 0x60, 2 << 5); | ||
662 | break; | ||
663 | |||
664 | case HIERARCHY_4: | ||
665 | tda1004x_write_mask(state, TDA1004X_IN_CONF1, 0x60, 3 << 5); | ||
666 | break; | ||
667 | |||
668 | default: | ||
669 | return -EINVAL; | ||
670 | } | ||
671 | } | ||
672 | |||
673 | // set bandwidth | ||
674 | switch(state->demod_type) { | ||
675 | case TDA1004X_DEMOD_TDA10045: | ||
676 | tda10045h_set_bandwidth(state, fe_params->u.ofdm.bandwidth); | ||
677 | break; | ||
678 | |||
679 | case TDA1004X_DEMOD_TDA10046: | ||
680 | tda10046h_set_bandwidth(state, fe_params->u.ofdm.bandwidth); | ||
681 | break; | ||
682 | } | ||
683 | |||
684 | // set inversion | ||
685 | inversion = fe_params->inversion; | ||
686 | if (state->config->invert) inversion = inversion ? INVERSION_OFF : INVERSION_ON; | ||
687 | switch (inversion) { | ||
688 | case INVERSION_OFF: | ||
689 | tda1004x_write_mask(state, TDA1004X_CONFC1, 0x20, 0); | ||
690 | break; | ||
691 | |||
692 | case INVERSION_ON: | ||
693 | tda1004x_write_mask(state, TDA1004X_CONFC1, 0x20, 0x20); | ||
694 | break; | ||
695 | |||
696 | default: | ||
697 | return -EINVAL; | ||
698 | } | ||
699 | |||
700 | // set guard interval | ||
701 | switch (fe_params->u.ofdm.guard_interval) { | ||
702 | case GUARD_INTERVAL_1_32: | ||
703 | tda1004x_write_mask(state, TDA1004X_AUTO, 2, 0); | ||
704 | tda1004x_write_mask(state, TDA1004X_IN_CONF1, 0x0c, 0 << 2); | ||
705 | break; | ||
706 | |||
707 | case GUARD_INTERVAL_1_16: | ||
708 | tda1004x_write_mask(state, TDA1004X_AUTO, 2, 0); | ||
709 | tda1004x_write_mask(state, TDA1004X_IN_CONF1, 0x0c, 1 << 2); | ||
710 | break; | ||
711 | |||
712 | case GUARD_INTERVAL_1_8: | ||
713 | tda1004x_write_mask(state, TDA1004X_AUTO, 2, 0); | ||
714 | tda1004x_write_mask(state, TDA1004X_IN_CONF1, 0x0c, 2 << 2); | ||
715 | break; | ||
716 | |||
717 | case GUARD_INTERVAL_1_4: | ||
718 | tda1004x_write_mask(state, TDA1004X_AUTO, 2, 0); | ||
719 | tda1004x_write_mask(state, TDA1004X_IN_CONF1, 0x0c, 3 << 2); | ||
720 | break; | ||
721 | |||
722 | case GUARD_INTERVAL_AUTO: | ||
723 | tda1004x_write_mask(state, TDA1004X_AUTO, 2, 2); | ||
724 | tda1004x_write_mask(state, TDA1004X_IN_CONF1, 0x0c, 0 << 2); | ||
725 | break; | ||
726 | |||
727 | default: | ||
728 | return -EINVAL; | ||
729 | } | ||
730 | |||
731 | // set transmission mode | ||
732 | switch (fe_params->u.ofdm.transmission_mode) { | ||
733 | case TRANSMISSION_MODE_2K: | ||
734 | tda1004x_write_mask(state, TDA1004X_AUTO, 4, 0); | ||
735 | tda1004x_write_mask(state, TDA1004X_IN_CONF1, 0x10, 0 << 4); | ||
736 | break; | ||
737 | |||
738 | case TRANSMISSION_MODE_8K: | ||
739 | tda1004x_write_mask(state, TDA1004X_AUTO, 4, 0); | ||
740 | tda1004x_write_mask(state, TDA1004X_IN_CONF1, 0x10, 1 << 4); | ||
741 | break; | ||
742 | |||
743 | case TRANSMISSION_MODE_AUTO: | ||
744 | tda1004x_write_mask(state, TDA1004X_AUTO, 4, 4); | ||
745 | tda1004x_write_mask(state, TDA1004X_IN_CONF1, 0x10, 0); | ||
746 | break; | ||
747 | |||
748 | default: | ||
749 | return -EINVAL; | ||
750 | } | ||
751 | |||
752 | // start the lock | ||
753 | switch(state->demod_type) { | ||
754 | case TDA1004X_DEMOD_TDA10045: | ||
755 | tda1004x_write_mask(state, TDA1004X_CONFC4, 8, 8); | ||
756 | tda1004x_write_mask(state, TDA1004X_CONFC4, 8, 0); | ||
757 | msleep(10); | ||
758 | break; | ||
759 | |||
760 | case TDA1004X_DEMOD_TDA10046: | ||
761 | tda1004x_write_mask(state, TDA1004X_AUTO, 0x40, 0x40); | ||
762 | msleep(10); | ||
763 | break; | ||
764 | } | ||
765 | |||
766 | return 0; | ||
767 | } | ||
768 | |||
769 | static int tda1004x_get_fe(struct dvb_frontend* fe, struct dvb_frontend_parameters *fe_params) | ||
770 | { | ||
771 | struct tda1004x_state* state = fe->demodulator_priv; | ||
772 | dprintk("%s\n", __FUNCTION__); | ||
773 | |||
774 | // inversion status | ||
775 | fe_params->inversion = INVERSION_OFF; | ||
776 | if (tda1004x_read_byte(state, TDA1004X_CONFC1) & 0x20) { | ||
777 | fe_params->inversion = INVERSION_ON; | ||
778 | } | ||
779 | if (state->config->invert) fe_params->inversion = fe_params->inversion ? INVERSION_OFF : INVERSION_ON; | ||
780 | |||
781 | // bandwidth | ||
782 | switch(state->demod_type) { | ||
783 | case TDA1004X_DEMOD_TDA10045: | ||
784 | switch (tda1004x_read_byte(state, TDA10045H_WREF_LSB)) { | ||
785 | case 0x14: | ||
786 | fe_params->u.ofdm.bandwidth = BANDWIDTH_8_MHZ; | ||
787 | break; | ||
788 | case 0xdb: | ||
789 | fe_params->u.ofdm.bandwidth = BANDWIDTH_7_MHZ; | ||
790 | break; | ||
791 | case 0x4f: | ||
792 | fe_params->u.ofdm.bandwidth = BANDWIDTH_6_MHZ; | ||
793 | break; | ||
794 | } | ||
795 | break; | ||
796 | |||
797 | case TDA1004X_DEMOD_TDA10046: | ||
798 | switch (tda1004x_read_byte(state, TDA10046H_TIME_WREF1)) { | ||
799 | case 0x60: | ||
800 | fe_params->u.ofdm.bandwidth = BANDWIDTH_8_MHZ; | ||
801 | break; | ||
802 | case 0x6e: | ||
803 | fe_params->u.ofdm.bandwidth = BANDWIDTH_7_MHZ; | ||
804 | break; | ||
805 | case 0x80: | ||
806 | fe_params->u.ofdm.bandwidth = BANDWIDTH_6_MHZ; | ||
807 | break; | ||
808 | } | ||
809 | break; | ||
810 | } | ||
811 | |||
812 | // FEC | ||
813 | fe_params->u.ofdm.code_rate_HP = | ||
814 | tda1004x_decode_fec(tda1004x_read_byte(state, TDA1004X_OUT_CONF2) & 7); | ||
815 | fe_params->u.ofdm.code_rate_LP = | ||
816 | tda1004x_decode_fec((tda1004x_read_byte(state, TDA1004X_OUT_CONF2) >> 3) & 7); | ||
817 | |||
818 | // constellation | ||
819 | switch (tda1004x_read_byte(state, TDA1004X_OUT_CONF1) & 3) { | ||
820 | case 0: | ||
821 | fe_params->u.ofdm.constellation = QPSK; | ||
822 | break; | ||
823 | case 1: | ||
824 | fe_params->u.ofdm.constellation = QAM_16; | ||
825 | break; | ||
826 | case 2: | ||
827 | fe_params->u.ofdm.constellation = QAM_64; | ||
828 | break; | ||
829 | } | ||
830 | |||
831 | // transmission mode | ||
832 | fe_params->u.ofdm.transmission_mode = TRANSMISSION_MODE_2K; | ||
833 | if (tda1004x_read_byte(state, TDA1004X_OUT_CONF1) & 0x10) { | ||
834 | fe_params->u.ofdm.transmission_mode = TRANSMISSION_MODE_8K; | ||
835 | } | ||
836 | |||
837 | // guard interval | ||
838 | switch ((tda1004x_read_byte(state, TDA1004X_OUT_CONF1) & 0x0c) >> 2) { | ||
839 | case 0: | ||
840 | fe_params->u.ofdm.guard_interval = GUARD_INTERVAL_1_32; | ||
841 | break; | ||
842 | case 1: | ||
843 | fe_params->u.ofdm.guard_interval = GUARD_INTERVAL_1_16; | ||
844 | break; | ||
845 | case 2: | ||
846 | fe_params->u.ofdm.guard_interval = GUARD_INTERVAL_1_8; | ||
847 | break; | ||
848 | case 3: | ||
849 | fe_params->u.ofdm.guard_interval = GUARD_INTERVAL_1_4; | ||
850 | break; | ||
851 | } | ||
852 | |||
853 | // hierarchy | ||
854 | switch ((tda1004x_read_byte(state, TDA1004X_OUT_CONF1) & 0x60) >> 5) { | ||
855 | case 0: | ||
856 | fe_params->u.ofdm.hierarchy_information = HIERARCHY_NONE; | ||
857 | break; | ||
858 | case 1: | ||
859 | fe_params->u.ofdm.hierarchy_information = HIERARCHY_1; | ||
860 | break; | ||
861 | case 2: | ||
862 | fe_params->u.ofdm.hierarchy_information = HIERARCHY_2; | ||
863 | break; | ||
864 | case 3: | ||
865 | fe_params->u.ofdm.hierarchy_information = HIERARCHY_4; | ||
866 | break; | ||
867 | } | ||
868 | |||
869 | return 0; | ||
870 | } | ||
871 | |||
872 | static int tda1004x_read_status(struct dvb_frontend* fe, fe_status_t * fe_status) | ||
873 | { | ||
874 | struct tda1004x_state* state = fe->demodulator_priv; | ||
875 | int status; | ||
876 | int cber; | ||
877 | int vber; | ||
878 | |||
879 | dprintk("%s\n", __FUNCTION__); | ||
880 | |||
881 | // read status | ||
882 | status = tda1004x_read_byte(state, TDA1004X_STATUS_CD); | ||
883 | if (status == -1) { | ||
884 | return -EIO; | ||
885 | } | ||
886 | |||
887 | // decode | ||
888 | *fe_status = 0; | ||
889 | if (status & 4) *fe_status |= FE_HAS_SIGNAL; | ||
890 | if (status & 2) *fe_status |= FE_HAS_CARRIER; | ||
891 | if (status & 8) *fe_status |= FE_HAS_VITERBI | FE_HAS_SYNC | FE_HAS_LOCK; | ||
892 | |||
893 | // if we don't already have VITERBI (i.e. not LOCKED), see if the viterbi | ||
894 | // is getting anything valid | ||
895 | if (!(*fe_status & FE_HAS_VITERBI)) { | ||
896 | // read the CBER | ||
897 | cber = tda1004x_read_byte(state, TDA1004X_CBER_LSB); | ||
898 | if (cber == -1) return -EIO; | ||
899 | status = tda1004x_read_byte(state, TDA1004X_CBER_MSB); | ||
900 | if (status == -1) return -EIO; | ||
901 | cber |= (status << 8); | ||
902 | tda1004x_read_byte(state, TDA1004X_CBER_RESET); | ||
903 | |||
904 | if (cber != 65535) { | ||
905 | *fe_status |= FE_HAS_VITERBI; | ||
906 | } | ||
907 | } | ||
908 | |||
909 | // if we DO have some valid VITERBI output, but don't already have SYNC | ||
910 | // bytes (i.e. not LOCKED), see if the RS decoder is getting anything valid. | ||
911 | if ((*fe_status & FE_HAS_VITERBI) && (!(*fe_status & FE_HAS_SYNC))) { | ||
912 | // read the VBER | ||
913 | vber = tda1004x_read_byte(state, TDA1004X_VBER_LSB); | ||
914 | if (vber == -1) return -EIO; | ||
915 | status = tda1004x_read_byte(state, TDA1004X_VBER_MID); | ||
916 | if (status == -1) return -EIO; | ||
917 | vber |= (status << 8); | ||
918 | status = tda1004x_read_byte(state, TDA1004X_VBER_MSB); | ||
919 | if (status == -1) return -EIO; | ||
920 | vber |= ((status << 16) & 0x0f); | ||
921 | tda1004x_read_byte(state, TDA1004X_CVBER_LUT); | ||
922 | |||
923 | // if RS has passed some valid TS packets, then we must be | ||
924 | // getting some SYNC bytes | ||
925 | if (vber < 16632) { | ||
926 | *fe_status |= FE_HAS_SYNC; | ||
927 | } | ||
928 | } | ||
929 | |||
930 | // success | ||
931 | dprintk("%s: fe_status=0x%x\n", __FUNCTION__, *fe_status); | ||
932 | return 0; | ||
933 | } | ||
934 | |||
935 | static int tda1004x_read_signal_strength(struct dvb_frontend* fe, u16 * signal) | ||
936 | { | ||
937 | struct tda1004x_state* state = fe->demodulator_priv; | ||
938 | int tmp; | ||
939 | int reg = 0; | ||
940 | |||
941 | dprintk("%s\n", __FUNCTION__); | ||
942 | |||
943 | // determine the register to use | ||
944 | switch(state->demod_type) { | ||
945 | case TDA1004X_DEMOD_TDA10045: | ||
946 | reg = TDA10045H_S_AGC; | ||
947 | break; | ||
948 | |||
949 | case TDA1004X_DEMOD_TDA10046: | ||
950 | reg = TDA10046H_AGC_IF_LEVEL; | ||
951 | break; | ||
952 | } | ||
953 | |||
954 | // read it | ||
955 | tmp = tda1004x_read_byte(state, reg); | ||
956 | if (tmp < 0) | ||
957 | return -EIO; | ||
958 | |||
959 | *signal = (tmp << 8) | tmp; | ||
960 | dprintk("%s: signal=0x%x\n", __FUNCTION__, *signal); | ||
961 | return 0; | ||
962 | } | ||
963 | |||
964 | static int tda1004x_read_snr(struct dvb_frontend* fe, u16 * snr) | ||
965 | { | ||
966 | struct tda1004x_state* state = fe->demodulator_priv; | ||
967 | int tmp; | ||
968 | |||
969 | dprintk("%s\n", __FUNCTION__); | ||
970 | |||
971 | // read it | ||
972 | tmp = tda1004x_read_byte(state, TDA1004X_SNR); | ||
973 | if (tmp < 0) | ||
974 | return -EIO; | ||
975 | if (tmp) { | ||
976 | tmp = 255 - tmp; | ||
977 | } | ||
978 | |||
979 | *snr = ((tmp << 8) | tmp); | ||
980 | dprintk("%s: snr=0x%x\n", __FUNCTION__, *snr); | ||
981 | return 0; | ||
982 | } | ||
983 | |||
984 | static int tda1004x_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks) | ||
985 | { | ||
986 | struct tda1004x_state* state = fe->demodulator_priv; | ||
987 | int tmp; | ||
988 | int tmp2; | ||
989 | int counter; | ||
990 | |||
991 | dprintk("%s\n", __FUNCTION__); | ||
992 | |||
993 | // read the UCBLOCKS and reset | ||
994 | counter = 0; | ||
995 | tmp = tda1004x_read_byte(state, TDA1004X_UNCOR); | ||
996 | if (tmp < 0) | ||
997 | return -EIO; | ||
998 | tmp &= 0x7f; | ||
999 | while (counter++ < 5) { | ||
1000 | tda1004x_write_mask(state, TDA1004X_UNCOR, 0x80, 0); | ||
1001 | tda1004x_write_mask(state, TDA1004X_UNCOR, 0x80, 0); | ||
1002 | tda1004x_write_mask(state, TDA1004X_UNCOR, 0x80, 0); | ||
1003 | |||
1004 | tmp2 = tda1004x_read_byte(state, TDA1004X_UNCOR); | ||
1005 | if (tmp2 < 0) | ||
1006 | return -EIO; | ||
1007 | tmp2 &= 0x7f; | ||
1008 | if ((tmp2 < tmp) || (tmp2 == 0)) | ||
1009 | break; | ||
1010 | } | ||
1011 | |||
1012 | if (tmp != 0x7f) { | ||
1013 | *ucblocks = tmp; | ||
1014 | } else { | ||
1015 | *ucblocks = 0xffffffff; | ||
1016 | } | ||
1017 | dprintk("%s: ucblocks=0x%x\n", __FUNCTION__, *ucblocks); | ||
1018 | return 0; | ||
1019 | } | ||
1020 | |||
1021 | static int tda1004x_read_ber(struct dvb_frontend* fe, u32* ber) | ||
1022 | { | ||
1023 | struct tda1004x_state* state = fe->demodulator_priv; | ||
1024 | int tmp; | ||
1025 | |||
1026 | dprintk("%s\n", __FUNCTION__); | ||
1027 | |||
1028 | // read it in | ||
1029 | tmp = tda1004x_read_byte(state, TDA1004X_CBER_LSB); | ||
1030 | if (tmp < 0) return -EIO; | ||
1031 | *ber = tmp << 1; | ||
1032 | tmp = tda1004x_read_byte(state, TDA1004X_CBER_MSB); | ||
1033 | if (tmp < 0) return -EIO; | ||
1034 | *ber |= (tmp << 9); | ||
1035 | tda1004x_read_byte(state, TDA1004X_CBER_RESET); | ||
1036 | |||
1037 | dprintk("%s: ber=0x%x\n", __FUNCTION__, *ber); | ||
1038 | return 0; | ||
1039 | } | ||
1040 | |||
1041 | static int tda1004x_sleep(struct dvb_frontend* fe) | ||
1042 | { | ||
1043 | struct tda1004x_state* state = fe->demodulator_priv; | ||
1044 | |||
1045 | switch(state->demod_type) { | ||
1046 | case TDA1004X_DEMOD_TDA10045: | ||
1047 | tda1004x_write_mask(state, TDA1004X_CONFADC1, 0x10, 0x10); | ||
1048 | break; | ||
1049 | |||
1050 | case TDA1004X_DEMOD_TDA10046: | ||
1051 | tda1004x_write_mask(state, TDA1004X_CONFC4, 1, 1); | ||
1052 | break; | ||
1053 | } | ||
1054 | state->initialised = 0; | ||
1055 | |||
1056 | return 0; | ||
1057 | } | ||
1058 | |||
1059 | static int tda1004x_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings* fesettings) | ||
1060 | { | ||
1061 | fesettings->min_delay_ms = 800; | ||
1062 | fesettings->step_size = 166667; | ||
1063 | fesettings->max_drift = 166667*2; | ||
1064 | return 0; | ||
1065 | } | ||
1066 | |||
1067 | static void tda1004x_release(struct dvb_frontend* fe) | ||
1068 | { | ||
1069 | struct tda1004x_state* state = (struct tda1004x_state*) fe->demodulator_priv; | ||
1070 | kfree(state); | ||
1071 | } | ||
1072 | |||
1073 | static struct dvb_frontend_ops tda10045_ops; | ||
1074 | |||
1075 | struct dvb_frontend* tda10045_attach(const struct tda1004x_config* config, | ||
1076 | struct i2c_adapter* i2c) | ||
1077 | { | ||
1078 | struct tda1004x_state* state = NULL; | ||
1079 | |||
1080 | /* allocate memory for the internal state */ | ||
1081 | state = (struct tda1004x_state*) kmalloc(sizeof(struct tda1004x_state), GFP_KERNEL); | ||
1082 | if (state == NULL) goto error; | ||
1083 | |||
1084 | /* setup the state */ | ||
1085 | state->config = config; | ||
1086 | state->i2c = i2c; | ||
1087 | memcpy(&state->ops, &tda10045_ops, sizeof(struct dvb_frontend_ops)); | ||
1088 | state->initialised = 0; | ||
1089 | state->demod_type = TDA1004X_DEMOD_TDA10045; | ||
1090 | |||
1091 | /* check if the demod is there */ | ||
1092 | if (tda1004x_read_byte(state, TDA1004X_CHIPID) != 0x25) goto error; | ||
1093 | |||
1094 | /* create dvb_frontend */ | ||
1095 | state->frontend.ops = &state->ops; | ||
1096 | state->frontend.demodulator_priv = state; | ||
1097 | return &state->frontend; | ||
1098 | |||
1099 | error: | ||
1100 | kfree(state); | ||
1101 | return NULL; | ||
1102 | } | ||
1103 | |||
1104 | static struct dvb_frontend_ops tda10046_ops; | ||
1105 | |||
1106 | struct dvb_frontend* tda10046_attach(const struct tda1004x_config* config, | ||
1107 | struct i2c_adapter* i2c) | ||
1108 | { | ||
1109 | struct tda1004x_state* state = NULL; | ||
1110 | |||
1111 | /* allocate memory for the internal state */ | ||
1112 | state = (struct tda1004x_state*) kmalloc(sizeof(struct tda1004x_state), GFP_KERNEL); | ||
1113 | if (state == NULL) goto error; | ||
1114 | |||
1115 | /* setup the state */ | ||
1116 | state->config = config; | ||
1117 | state->i2c = i2c; | ||
1118 | memcpy(&state->ops, &tda10046_ops, sizeof(struct dvb_frontend_ops)); | ||
1119 | state->initialised = 0; | ||
1120 | state->demod_type = TDA1004X_DEMOD_TDA10046; | ||
1121 | |||
1122 | /* check if the demod is there */ | ||
1123 | if (tda1004x_read_byte(state, TDA1004X_CHIPID) != 0x46) goto error; | ||
1124 | |||
1125 | /* create dvb_frontend */ | ||
1126 | state->frontend.ops = &state->ops; | ||
1127 | state->frontend.demodulator_priv = state; | ||
1128 | return &state->frontend; | ||
1129 | |||
1130 | error: | ||
1131 | if (state) kfree(state); | ||
1132 | return NULL; | ||
1133 | } | ||
1134 | |||
1135 | static struct dvb_frontend_ops tda10045_ops = { | ||
1136 | |||
1137 | .info = { | ||
1138 | .name = "Philips TDA10045H DVB-T", | ||
1139 | .type = FE_OFDM, | ||
1140 | .frequency_min = 51000000, | ||
1141 | .frequency_max = 858000000, | ||
1142 | .frequency_stepsize = 166667, | ||
1143 | .caps = | ||
1144 | FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | | ||
1145 | FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO | | ||
1146 | FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO | | ||
1147 | FE_CAN_TRANSMISSION_MODE_AUTO | FE_CAN_GUARD_INTERVAL_AUTO | ||
1148 | }, | ||
1149 | |||
1150 | .release = tda1004x_release, | ||
1151 | |||
1152 | .init = tda10045_init, | ||
1153 | .sleep = tda1004x_sleep, | ||
1154 | |||
1155 | .set_frontend = tda1004x_set_fe, | ||
1156 | .get_frontend = tda1004x_get_fe, | ||
1157 | .get_tune_settings = tda1004x_get_tune_settings, | ||
1158 | |||
1159 | .read_status = tda1004x_read_status, | ||
1160 | .read_ber = tda1004x_read_ber, | ||
1161 | .read_signal_strength = tda1004x_read_signal_strength, | ||
1162 | .read_snr = tda1004x_read_snr, | ||
1163 | .read_ucblocks = tda1004x_read_ucblocks, | ||
1164 | }; | ||
1165 | |||
1166 | static struct dvb_frontend_ops tda10046_ops = { | ||
1167 | |||
1168 | .info = { | ||
1169 | .name = "Philips TDA10046H DVB-T", | ||
1170 | .type = FE_OFDM, | ||
1171 | .frequency_min = 51000000, | ||
1172 | .frequency_max = 858000000, | ||
1173 | .frequency_stepsize = 166667, | ||
1174 | .caps = | ||
1175 | FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | | ||
1176 | FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO | | ||
1177 | FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO | | ||
1178 | FE_CAN_TRANSMISSION_MODE_AUTO | FE_CAN_GUARD_INTERVAL_AUTO | ||
1179 | }, | ||
1180 | |||
1181 | .release = tda1004x_release, | ||
1182 | |||
1183 | .init = tda10046_init, | ||
1184 | .sleep = tda1004x_sleep, | ||
1185 | |||
1186 | .set_frontend = tda1004x_set_fe, | ||
1187 | .get_frontend = tda1004x_get_fe, | ||
1188 | .get_tune_settings = tda1004x_get_tune_settings, | ||
1189 | |||
1190 | .read_status = tda1004x_read_status, | ||
1191 | .read_ber = tda1004x_read_ber, | ||
1192 | .read_signal_strength = tda1004x_read_signal_strength, | ||
1193 | .read_snr = tda1004x_read_snr, | ||
1194 | .read_ucblocks = tda1004x_read_ucblocks, | ||
1195 | }; | ||
1196 | |||
1197 | module_param(debug, int, 0644); | ||
1198 | MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off)."); | ||
1199 | |||
1200 | MODULE_DESCRIPTION("Philips TDA10045H & TDA10046H DVB-T Demodulator"); | ||
1201 | MODULE_AUTHOR("Andrew de Quincey & Robert Schlabbach"); | ||
1202 | MODULE_LICENSE("GPL"); | ||
1203 | |||
1204 | EXPORT_SYMBOL(tda10045_attach); | ||
1205 | EXPORT_SYMBOL(tda10046_attach); | ||
1206 | EXPORT_SYMBOL(tda1004x_write_byte); | ||
diff --git a/drivers/media/dvb/frontends/tda1004x.h b/drivers/media/dvb/frontends/tda1004x.h new file mode 100644 index 000000000000..e452fc0bad11 --- /dev/null +++ b/drivers/media/dvb/frontends/tda1004x.h | |||
@@ -0,0 +1,56 @@ | |||
1 | /* | ||
2 | Driver for Philips tda1004xh OFDM Frontend | ||
3 | |||
4 | (c) 2004 Andrew de Quincey | ||
5 | |||
6 | This program is free software; you can redistribute it and/or modify | ||
7 | it under the terms of the GNU General Public License as published by | ||
8 | the Free Software Foundation; either version 2 of the License, or | ||
9 | (at your option) any later version. | ||
10 | |||
11 | This program is distributed in the hope that it will be useful, | ||
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | |||
15 | GNU General Public License for more details. | ||
16 | |||
17 | You should have received a copy of the GNU General Public License | ||
18 | along with this program; if not, write to the Free Software | ||
19 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
20 | |||
21 | */ | ||
22 | |||
23 | #ifndef TDA1004X_H | ||
24 | #define TDA1004X_H | ||
25 | |||
26 | #include <linux/dvb/frontend.h> | ||
27 | #include <linux/firmware.h> | ||
28 | |||
29 | struct tda1004x_config | ||
30 | { | ||
31 | /* the demodulator's i2c address */ | ||
32 | u8 demod_address; | ||
33 | |||
34 | /* does the "inversion" need inverted? */ | ||
35 | u8 invert:1; | ||
36 | |||
37 | /* Does the OCLK signal need inverted? */ | ||
38 | u8 invert_oclk:1; | ||
39 | |||
40 | /* PLL maintenance */ | ||
41 | int (*pll_init)(struct dvb_frontend* fe); | ||
42 | int (*pll_set)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params); | ||
43 | |||
44 | /* request firmware for device */ | ||
45 | int (*request_firmware)(struct dvb_frontend* fe, const struct firmware **fw, char* name); | ||
46 | }; | ||
47 | |||
48 | extern struct dvb_frontend* tda10045_attach(const struct tda1004x_config* config, | ||
49 | struct i2c_adapter* i2c); | ||
50 | |||
51 | extern struct dvb_frontend* tda10046_attach(const struct tda1004x_config* config, | ||
52 | struct i2c_adapter* i2c); | ||
53 | |||
54 | extern int tda1004x_write_byte(struct dvb_frontend* fe, int reg, int data); | ||
55 | |||
56 | #endif // TDA1004X_H | ||
diff --git a/drivers/media/dvb/frontends/tda8083.c b/drivers/media/dvb/frontends/tda8083.c new file mode 100644 index 000000000000..da82e90d6d13 --- /dev/null +++ b/drivers/media/dvb/frontends/tda8083.c | |||
@@ -0,0 +1,456 @@ | |||
1 | /* | ||
2 | Driver for Philips TDA8083 based QPSK Demodulator | ||
3 | |||
4 | Copyright (C) 2001 Convergence Integrated Media GmbH | ||
5 | |||
6 | written by Ralph Metzler <ralph@convergence.de> | ||
7 | |||
8 | adoption to the new DVB frontend API and diagnostic ioctl's | ||
9 | by Holger Waechtler <holger@convergence.de> | ||
10 | |||
11 | This program is free software; you can redistribute it and/or modify | ||
12 | it under the terms of the GNU General Public License as published by | ||
13 | the Free Software Foundation; either version 2 of the License, or | ||
14 | (at your option) any later version. | ||
15 | |||
16 | This program is distributed in the hope that it will be useful, | ||
17 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
18 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
19 | GNU General Public License for more details. | ||
20 | |||
21 | You should have received a copy of the GNU General Public License | ||
22 | along with this program; if not, write to the Free Software | ||
23 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
24 | |||
25 | */ | ||
26 | |||
27 | #include <linux/init.h> | ||
28 | #include <linux/kernel.h> | ||
29 | #include <linux/module.h> | ||
30 | #include <linux/moduleparam.h> | ||
31 | #include <linux/string.h> | ||
32 | #include <linux/slab.h> | ||
33 | #include "dvb_frontend.h" | ||
34 | #include "tda8083.h" | ||
35 | |||
36 | |||
37 | struct tda8083_state { | ||
38 | struct i2c_adapter* i2c; | ||
39 | struct dvb_frontend_ops ops; | ||
40 | /* configuration settings */ | ||
41 | const struct tda8083_config* config; | ||
42 | struct dvb_frontend frontend; | ||
43 | }; | ||
44 | |||
45 | static int debug; | ||
46 | #define dprintk(args...) \ | ||
47 | do { \ | ||
48 | if (debug) printk(KERN_DEBUG "tda8083: " args); \ | ||
49 | } while (0) | ||
50 | |||
51 | |||
52 | static u8 tda8083_init_tab [] = { | ||
53 | 0x04, 0x00, 0x4a, 0x79, 0x04, 0x00, 0xff, 0xea, | ||
54 | 0x48, 0x42, 0x79, 0x60, 0x70, 0x52, 0x9a, 0x10, | ||
55 | 0x0e, 0x10, 0xf2, 0xa7, 0x93, 0x0b, 0x05, 0xc8, | ||
56 | 0x9d, 0x00, 0x42, 0x80, 0x00, 0x60, 0x40, 0x00, | ||
57 | 0x00, 0x75, 0x00, 0xe0, 0x00, 0x00, 0x00, 0x00, | ||
58 | 0x00, 0x00, 0x00, 0x00 | ||
59 | }; | ||
60 | |||
61 | |||
62 | static int tda8083_writereg (struct tda8083_state* state, u8 reg, u8 data) | ||
63 | { | ||
64 | int ret; | ||
65 | u8 buf [] = { reg, data }; | ||
66 | struct i2c_msg msg = { .addr = state->config->demod_address, .flags = 0, .buf = buf, .len = 2 }; | ||
67 | |||
68 | ret = i2c_transfer(state->i2c, &msg, 1); | ||
69 | |||
70 | if (ret != 1) | ||
71 | dprintk ("%s: writereg error (reg %02x, ret == %i)\n", | ||
72 | __FUNCTION__, reg, ret); | ||
73 | |||
74 | return (ret != 1) ? -1 : 0; | ||
75 | } | ||
76 | |||
77 | static int tda8083_readregs (struct tda8083_state* state, u8 reg1, u8 *b, u8 len) | ||
78 | { | ||
79 | int ret; | ||
80 | struct i2c_msg msg [] = { { .addr = state->config->demod_address, .flags = 0, .buf = ®1, .len = 1 }, | ||
81 | { .addr = state->config->demod_address, .flags = I2C_M_RD, .buf = b, .len = len } }; | ||
82 | |||
83 | ret = i2c_transfer(state->i2c, msg, 2); | ||
84 | |||
85 | if (ret != 2) | ||
86 | dprintk ("%s: readreg error (reg %02x, ret == %i)\n", | ||
87 | __FUNCTION__, reg1, ret); | ||
88 | |||
89 | return ret == 2 ? 0 : -1; | ||
90 | } | ||
91 | |||
92 | static inline u8 tda8083_readreg (struct tda8083_state* state, u8 reg) | ||
93 | { | ||
94 | u8 val; | ||
95 | |||
96 | tda8083_readregs (state, reg, &val, 1); | ||
97 | |||
98 | return val; | ||
99 | } | ||
100 | |||
101 | static int tda8083_set_inversion (struct tda8083_state* state, fe_spectral_inversion_t inversion) | ||
102 | { | ||
103 | /* XXX FIXME: implement other modes than FEC_AUTO */ | ||
104 | if (inversion == INVERSION_AUTO) | ||
105 | return 0; | ||
106 | |||
107 | return -EINVAL; | ||
108 | } | ||
109 | |||
110 | static int tda8083_set_fec (struct tda8083_state* state, fe_code_rate_t fec) | ||
111 | { | ||
112 | if (fec == FEC_AUTO) | ||
113 | return tda8083_writereg (state, 0x07, 0xff); | ||
114 | |||
115 | if (fec >= FEC_1_2 && fec <= FEC_8_9) | ||
116 | return tda8083_writereg (state, 0x07, 1 << (FEC_8_9 - fec)); | ||
117 | |||
118 | return -EINVAL; | ||
119 | } | ||
120 | |||
121 | static fe_code_rate_t tda8083_get_fec (struct tda8083_state* state) | ||
122 | { | ||
123 | u8 index; | ||
124 | static fe_code_rate_t fec_tab [] = { FEC_8_9, FEC_1_2, FEC_2_3, FEC_3_4, | ||
125 | FEC_4_5, FEC_5_6, FEC_6_7, FEC_7_8 }; | ||
126 | |||
127 | index = tda8083_readreg(state, 0x0e) & 0x07; | ||
128 | |||
129 | return fec_tab [index]; | ||
130 | } | ||
131 | |||
132 | static int tda8083_set_symbolrate (struct tda8083_state* state, u32 srate) | ||
133 | { | ||
134 | u32 ratio; | ||
135 | u32 tmp; | ||
136 | u8 filter; | ||
137 | |||
138 | if (srate > 32000000) | ||
139 | srate = 32000000; | ||
140 | if (srate < 500000) | ||
141 | srate = 500000; | ||
142 | |||
143 | filter = 0; | ||
144 | if (srate < 24000000) | ||
145 | filter = 2; | ||
146 | if (srate < 16000000) | ||
147 | filter = 3; | ||
148 | |||
149 | tmp = 31250 << 16; | ||
150 | ratio = tmp / srate; | ||
151 | |||
152 | tmp = (tmp % srate) << 8; | ||
153 | ratio = (ratio << 8) + tmp / srate; | ||
154 | |||
155 | tmp = (tmp % srate) << 8; | ||
156 | ratio = (ratio << 8) + tmp / srate; | ||
157 | |||
158 | dprintk("tda8083: ratio == %08x\n", (unsigned int) ratio); | ||
159 | |||
160 | tda8083_writereg (state, 0x05, filter); | ||
161 | tda8083_writereg (state, 0x02, (ratio >> 16) & 0xff); | ||
162 | tda8083_writereg (state, 0x03, (ratio >> 8) & 0xff); | ||
163 | tda8083_writereg (state, 0x04, (ratio ) & 0xff); | ||
164 | |||
165 | tda8083_writereg (state, 0x00, 0x3c); | ||
166 | tda8083_writereg (state, 0x00, 0x04); | ||
167 | |||
168 | return 1; | ||
169 | } | ||
170 | |||
171 | static void tda8083_wait_diseqc_fifo (struct tda8083_state* state, int timeout) | ||
172 | { | ||
173 | unsigned long start = jiffies; | ||
174 | |||
175 | while (jiffies - start < timeout && | ||
176 | !(tda8083_readreg(state, 0x02) & 0x80)) | ||
177 | { | ||
178 | msleep(50); | ||
179 | }; | ||
180 | } | ||
181 | |||
182 | static int tda8083_set_tone (struct tda8083_state* state, fe_sec_tone_mode_t tone) | ||
183 | { | ||
184 | tda8083_writereg (state, 0x26, 0xf1); | ||
185 | |||
186 | switch (tone) { | ||
187 | case SEC_TONE_OFF: | ||
188 | return tda8083_writereg (state, 0x29, 0x00); | ||
189 | case SEC_TONE_ON: | ||
190 | return tda8083_writereg (state, 0x29, 0x80); | ||
191 | default: | ||
192 | return -EINVAL; | ||
193 | }; | ||
194 | } | ||
195 | |||
196 | static int tda8083_set_voltage (struct tda8083_state* state, fe_sec_voltage_t voltage) | ||
197 | { | ||
198 | switch (voltage) { | ||
199 | case SEC_VOLTAGE_13: | ||
200 | return tda8083_writereg (state, 0x20, 0x00); | ||
201 | case SEC_VOLTAGE_18: | ||
202 | return tda8083_writereg (state, 0x20, 0x11); | ||
203 | default: | ||
204 | return -EINVAL; | ||
205 | }; | ||
206 | } | ||
207 | |||
208 | static int tda8083_send_diseqc_burst (struct tda8083_state* state, fe_sec_mini_cmd_t burst) | ||
209 | { | ||
210 | switch (burst) { | ||
211 | case SEC_MINI_A: | ||
212 | tda8083_writereg (state, 0x29, (5 << 2)); /* send burst A */ | ||
213 | break; | ||
214 | case SEC_MINI_B: | ||
215 | tda8083_writereg (state, 0x29, (7 << 2)); /* send B */ | ||
216 | break; | ||
217 | default: | ||
218 | return -EINVAL; | ||
219 | }; | ||
220 | |||
221 | tda8083_wait_diseqc_fifo (state, 100); | ||
222 | |||
223 | return 0; | ||
224 | } | ||
225 | |||
226 | static int tda8083_send_diseqc_msg (struct dvb_frontend* fe, | ||
227 | struct dvb_diseqc_master_cmd *m) | ||
228 | { | ||
229 | struct tda8083_state* state = (struct tda8083_state*) fe->demodulator_priv; | ||
230 | int i; | ||
231 | |||
232 | tda8083_writereg (state, 0x29, (m->msg_len - 3) | (1 << 2)); /* enable */ | ||
233 | |||
234 | for (i=0; i<m->msg_len; i++) | ||
235 | tda8083_writereg (state, 0x23 + i, m->msg[i]); | ||
236 | |||
237 | tda8083_writereg (state, 0x29, (m->msg_len - 3) | (3 << 2)); /* send!! */ | ||
238 | |||
239 | tda8083_wait_diseqc_fifo (state, 100); | ||
240 | |||
241 | return 0; | ||
242 | } | ||
243 | |||
244 | static int tda8083_read_status(struct dvb_frontend* fe, fe_status_t* status) | ||
245 | { | ||
246 | struct tda8083_state* state = (struct tda8083_state*) fe->demodulator_priv; | ||
247 | |||
248 | u8 signal = ~tda8083_readreg (state, 0x01); | ||
249 | u8 sync = tda8083_readreg (state, 0x02); | ||
250 | |||
251 | *status = 0; | ||
252 | |||
253 | if (signal > 10) | ||
254 | *status |= FE_HAS_SIGNAL; | ||
255 | |||
256 | if (sync & 0x01) | ||
257 | *status |= FE_HAS_CARRIER; | ||
258 | |||
259 | if (sync & 0x02) | ||
260 | *status |= FE_HAS_VITERBI; | ||
261 | |||
262 | if (sync & 0x10) | ||
263 | *status |= FE_HAS_SYNC; | ||
264 | |||
265 | if ((sync & 0x1f) == 0x1f) | ||
266 | *status |= FE_HAS_LOCK; | ||
267 | |||
268 | return 0; | ||
269 | } | ||
270 | |||
271 | static int tda8083_read_signal_strength(struct dvb_frontend* fe, u16* strength) | ||
272 | { | ||
273 | struct tda8083_state* state = (struct tda8083_state*) fe->demodulator_priv; | ||
274 | |||
275 | u8 signal = ~tda8083_readreg (state, 0x01); | ||
276 | *strength = (signal << 8) | signal; | ||
277 | |||
278 | return 0; | ||
279 | } | ||
280 | |||
281 | static int tda8083_read_snr(struct dvb_frontend* fe, u16* snr) | ||
282 | { | ||
283 | struct tda8083_state* state = (struct tda8083_state*) fe->demodulator_priv; | ||
284 | |||
285 | u8 _snr = tda8083_readreg (state, 0x08); | ||
286 | *snr = (_snr << 8) | _snr; | ||
287 | |||
288 | return 0; | ||
289 | } | ||
290 | |||
291 | static int tda8083_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p) | ||
292 | { | ||
293 | struct tda8083_state* state = (struct tda8083_state*) fe->demodulator_priv; | ||
294 | |||
295 | state->config->pll_set(fe, p); | ||
296 | tda8083_set_inversion (state, p->inversion); | ||
297 | tda8083_set_fec (state, p->u.qpsk.fec_inner); | ||
298 | tda8083_set_symbolrate (state, p->u.qpsk.symbol_rate); | ||
299 | |||
300 | tda8083_writereg (state, 0x00, 0x3c); | ||
301 | tda8083_writereg (state, 0x00, 0x04); | ||
302 | |||
303 | return 0; | ||
304 | } | ||
305 | |||
306 | static int tda8083_get_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p) | ||
307 | { | ||
308 | struct tda8083_state* state = (struct tda8083_state*) fe->demodulator_priv; | ||
309 | |||
310 | /* FIXME: get symbolrate & frequency offset...*/ | ||
311 | /*p->frequency = ???;*/ | ||
312 | p->inversion = (tda8083_readreg (state, 0x0e) & 0x80) ? | ||
313 | INVERSION_ON : INVERSION_OFF; | ||
314 | p->u.qpsk.fec_inner = tda8083_get_fec (state); | ||
315 | /*p->u.qpsk.symbol_rate = tda8083_get_symbolrate (state);*/ | ||
316 | |||
317 | return 0; | ||
318 | } | ||
319 | |||
320 | static int tda8083_sleep(struct dvb_frontend* fe) | ||
321 | { | ||
322 | struct tda8083_state* state = (struct tda8083_state*) fe->demodulator_priv; | ||
323 | |||
324 | tda8083_writereg (state, 0x00, 0x02); | ||
325 | return 0; | ||
326 | } | ||
327 | |||
328 | static int tda8083_init(struct dvb_frontend* fe) | ||
329 | { | ||
330 | struct tda8083_state* state = (struct tda8083_state*) fe->demodulator_priv; | ||
331 | int i; | ||
332 | |||
333 | for (i=0; i<44; i++) | ||
334 | tda8083_writereg (state, i, tda8083_init_tab[i]); | ||
335 | |||
336 | if (state->config->pll_init) state->config->pll_init(fe); | ||
337 | |||
338 | tda8083_writereg (state, 0x00, 0x3c); | ||
339 | tda8083_writereg (state, 0x00, 0x04); | ||
340 | |||
341 | return 0; | ||
342 | } | ||
343 | |||
344 | static int tda8083_diseqc_send_burst(struct dvb_frontend* fe, fe_sec_mini_cmd_t burst) | ||
345 | { | ||
346 | struct tda8083_state* state = (struct tda8083_state*) fe->demodulator_priv; | ||
347 | |||
348 | tda8083_send_diseqc_burst (state, burst); | ||
349 | tda8083_writereg (state, 0x00, 0x3c); | ||
350 | tda8083_writereg (state, 0x00, 0x04); | ||
351 | |||
352 | return 0; | ||
353 | } | ||
354 | |||
355 | static int tda8083_diseqc_set_tone(struct dvb_frontend* fe, fe_sec_tone_mode_t tone) | ||
356 | { | ||
357 | struct tda8083_state* state = (struct tda8083_state*) fe->demodulator_priv; | ||
358 | |||
359 | tda8083_set_tone (state, tone); | ||
360 | tda8083_writereg (state, 0x00, 0x3c); | ||
361 | tda8083_writereg (state, 0x00, 0x04); | ||
362 | |||
363 | return 0; | ||
364 | } | ||
365 | |||
366 | static int tda8083_diseqc_set_voltage(struct dvb_frontend* fe, fe_sec_voltage_t voltage) | ||
367 | { | ||
368 | struct tda8083_state* state = (struct tda8083_state*) fe->demodulator_priv; | ||
369 | |||
370 | tda8083_set_voltage (state, voltage); | ||
371 | tda8083_writereg (state, 0x00, 0x3c); | ||
372 | tda8083_writereg (state, 0x00, 0x04); | ||
373 | |||
374 | return 0; | ||
375 | } | ||
376 | |||
377 | static void tda8083_release(struct dvb_frontend* fe) | ||
378 | { | ||
379 | struct tda8083_state* state = (struct tda8083_state*) fe->demodulator_priv; | ||
380 | kfree(state); | ||
381 | } | ||
382 | |||
383 | static struct dvb_frontend_ops tda8083_ops; | ||
384 | |||
385 | struct dvb_frontend* tda8083_attach(const struct tda8083_config* config, | ||
386 | struct i2c_adapter* i2c) | ||
387 | { | ||
388 | struct tda8083_state* state = NULL; | ||
389 | |||
390 | /* allocate memory for the internal state */ | ||
391 | state = (struct tda8083_state*) kmalloc(sizeof(struct tda8083_state), GFP_KERNEL); | ||
392 | if (state == NULL) goto error; | ||
393 | |||
394 | /* setup the state */ | ||
395 | state->config = config; | ||
396 | state->i2c = i2c; | ||
397 | memcpy(&state->ops, &tda8083_ops, sizeof(struct dvb_frontend_ops)); | ||
398 | |||
399 | /* check if the demod is there */ | ||
400 | if ((tda8083_readreg(state, 0x00)) != 0x05) goto error; | ||
401 | |||
402 | /* create dvb_frontend */ | ||
403 | state->frontend.ops = &state->ops; | ||
404 | state->frontend.demodulator_priv = state; | ||
405 | return &state->frontend; | ||
406 | |||
407 | error: | ||
408 | kfree(state); | ||
409 | return NULL; | ||
410 | } | ||
411 | |||
412 | static struct dvb_frontend_ops tda8083_ops = { | ||
413 | |||
414 | .info = { | ||
415 | .name = "Philips TDA8083 DVB-S", | ||
416 | .type = FE_QPSK, | ||
417 | .frequency_min = 950000, /* FIXME: guessed! */ | ||
418 | .frequency_max = 1400000, /* FIXME: guessed! */ | ||
419 | .frequency_stepsize = 125, /* kHz for QPSK frontends */ | ||
420 | /* .frequency_tolerance = ???,*/ | ||
421 | .symbol_rate_min = 1000000, /* FIXME: guessed! */ | ||
422 | .symbol_rate_max = 45000000, /* FIXME: guessed! */ | ||
423 | /* .symbol_rate_tolerance = ???,*/ | ||
424 | .caps = FE_CAN_INVERSION_AUTO | | ||
425 | FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | | ||
426 | FE_CAN_FEC_4_5 | FE_CAN_FEC_5_6 | FE_CAN_FEC_6_7 | | ||
427 | FE_CAN_FEC_7_8 | FE_CAN_FEC_8_9 | FE_CAN_FEC_AUTO | | ||
428 | FE_CAN_QPSK | FE_CAN_MUTE_TS | ||
429 | }, | ||
430 | |||
431 | .release = tda8083_release, | ||
432 | |||
433 | .init = tda8083_init, | ||
434 | .sleep = tda8083_sleep, | ||
435 | |||
436 | .set_frontend = tda8083_set_frontend, | ||
437 | .get_frontend = tda8083_get_frontend, | ||
438 | |||
439 | .read_status = tda8083_read_status, | ||
440 | .read_signal_strength = tda8083_read_signal_strength, | ||
441 | .read_snr = tda8083_read_snr, | ||
442 | |||
443 | .diseqc_send_master_cmd = tda8083_send_diseqc_msg, | ||
444 | .diseqc_send_burst = tda8083_diseqc_send_burst, | ||
445 | .set_tone = tda8083_diseqc_set_tone, | ||
446 | .set_voltage = tda8083_diseqc_set_voltage, | ||
447 | }; | ||
448 | |||
449 | module_param(debug, int, 0644); | ||
450 | MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off)."); | ||
451 | |||
452 | MODULE_DESCRIPTION("Philips TDA8083 DVB-S Demodulator"); | ||
453 | MODULE_AUTHOR("Ralph Metzler, Holger Waechtler"); | ||
454 | MODULE_LICENSE("GPL"); | ||
455 | |||
456 | EXPORT_SYMBOL(tda8083_attach); | ||
diff --git a/drivers/media/dvb/frontends/tda8083.h b/drivers/media/dvb/frontends/tda8083.h new file mode 100644 index 000000000000..466663307bf1 --- /dev/null +++ b/drivers/media/dvb/frontends/tda8083.h | |||
@@ -0,0 +1,45 @@ | |||
1 | /* | ||
2 | Driver for Grundig 29504-491, a Philips TDA8083 based QPSK Frontend | ||
3 | |||
4 | Copyright (C) 2001 Convergence Integrated Media GmbH | ||
5 | |||
6 | written by Ralph Metzler <ralph@convergence.de> | ||
7 | |||
8 | adoption to the new DVB frontend API and diagnostic ioctl's | ||
9 | by Holger Waechtler <holger@convergence.de> | ||
10 | |||
11 | This program is free software; you can redistribute it and/or modify | ||
12 | it under the terms of the GNU General Public License as published by | ||
13 | the Free Software Foundation; either version 2 of the License, or | ||
14 | (at your option) any later version. | ||
15 | |||
16 | This program is distributed in the hope that it will be useful, | ||
17 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
18 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
19 | GNU General Public License for more details. | ||
20 | |||
21 | You should have received a copy of the GNU General Public License | ||
22 | along with this program; if not, write to the Free Software | ||
23 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
24 | |||
25 | */ | ||
26 | |||
27 | #ifndef TDA8083_H | ||
28 | #define TDA8083_H | ||
29 | |||
30 | #include <linux/dvb/frontend.h> | ||
31 | |||
32 | struct tda8083_config | ||
33 | { | ||
34 | /* the demodulator's i2c address */ | ||
35 | u8 demod_address; | ||
36 | |||
37 | /* PLL maintenance */ | ||
38 | int (*pll_init)(struct dvb_frontend* fe); | ||
39 | int (*pll_set)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params); | ||
40 | }; | ||
41 | |||
42 | extern struct dvb_frontend* tda8083_attach(const struct tda8083_config* config, | ||
43 | struct i2c_adapter* i2c); | ||
44 | |||
45 | #endif // TDA8083_H | ||
diff --git a/drivers/media/dvb/frontends/tda80xx.c b/drivers/media/dvb/frontends/tda80xx.c new file mode 100644 index 000000000000..c99632114283 --- /dev/null +++ b/drivers/media/dvb/frontends/tda80xx.c | |||
@@ -0,0 +1,734 @@ | |||
1 | /* | ||
2 | * tda80xx.c | ||
3 | * | ||
4 | * Philips TDA8044 / TDA8083 QPSK demodulator driver | ||
5 | * | ||
6 | * Copyright (C) 2001 Felix Domke <tmbinc@elitedvb.net> | ||
7 | * Copyright (C) 2002-2004 Andreas Oberritter <obi@linuxtv.org> | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or modify | ||
10 | * it under the terms of the GNU General Public License as published by | ||
11 | * the Free Software Foundation; either version 2 of the License, or | ||
12 | * (at your option) any later version. | ||
13 | * | ||
14 | * This program is distributed in the hope that it will be useful, | ||
15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
17 | * GNU General Public License for more details. | ||
18 | * | ||
19 | * You should have received a copy of the GNU General Public License | ||
20 | * along with this program; if not, write to the Free Software | ||
21 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
22 | */ | ||
23 | |||
24 | #include <linux/config.h> | ||
25 | #include <linux/delay.h> | ||
26 | #include <linux/init.h> | ||
27 | #include <linux/spinlock.h> | ||
28 | #include <linux/threads.h> | ||
29 | #include <linux/interrupt.h> | ||
30 | #include <asm/irq.h> | ||
31 | #include <linux/kernel.h> | ||
32 | #include <linux/module.h> | ||
33 | #include <linux/slab.h> | ||
34 | #include <asm/div64.h> | ||
35 | |||
36 | #include "dvb_frontend.h" | ||
37 | #include "tda80xx.h" | ||
38 | |||
39 | enum { | ||
40 | ID_TDA8044 = 0x04, | ||
41 | ID_TDA8083 = 0x05, | ||
42 | }; | ||
43 | |||
44 | |||
45 | struct tda80xx_state { | ||
46 | |||
47 | struct i2c_adapter* i2c; | ||
48 | |||
49 | struct dvb_frontend_ops ops; | ||
50 | |||
51 | /* configuration settings */ | ||
52 | const struct tda80xx_config* config; | ||
53 | |||
54 | struct dvb_frontend frontend; | ||
55 | |||
56 | u32 clk; | ||
57 | int afc_loop; | ||
58 | struct work_struct worklet; | ||
59 | fe_code_rate_t code_rate; | ||
60 | fe_spectral_inversion_t spectral_inversion; | ||
61 | fe_status_t status; | ||
62 | u8 id; | ||
63 | }; | ||
64 | |||
65 | static int debug = 1; | ||
66 | #define dprintk if (debug) printk | ||
67 | |||
68 | static u8 tda8044_inittab_pre[] = { | ||
69 | 0x02, 0x00, 0x6f, 0xb5, 0x86, 0x22, 0x00, 0xea, | ||
70 | 0x30, 0x42, 0x98, 0x68, 0x70, 0x42, 0x99, 0x58, | ||
71 | 0x95, 0x10, 0xf5, 0xe7, 0x93, 0x0b, 0x15, 0x68, | ||
72 | 0x9a, 0x90, 0x61, 0x80, 0x00, 0xe0, 0x40, 0x00, | ||
73 | 0x0f, 0x15, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
74 | 0x00, 0x00 | ||
75 | }; | ||
76 | |||
77 | static u8 tda8044_inittab_post[] = { | ||
78 | 0x04, 0x00, 0x6f, 0xb5, 0x86, 0x22, 0x00, 0xea, | ||
79 | 0x30, 0x42, 0x98, 0x68, 0x70, 0x42, 0x99, 0x50, | ||
80 | 0x95, 0x10, 0xf5, 0xe7, 0x93, 0x0b, 0x15, 0x68, | ||
81 | 0x9a, 0x90, 0x61, 0x80, 0x00, 0xe0, 0x40, 0x6c, | ||
82 | 0x0f, 0x15, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
83 | 0x00, 0x00 | ||
84 | }; | ||
85 | |||
86 | static u8 tda8083_inittab[] = { | ||
87 | 0x04, 0x00, 0x4a, 0x79, 0x04, 0x00, 0xff, 0xea, | ||
88 | 0x48, 0x42, 0x79, 0x60, 0x70, 0x52, 0x9a, 0x10, | ||
89 | 0x0e, 0x10, 0xf2, 0xa7, 0x93, 0x0b, 0x05, 0xc8, | ||
90 | 0x9d, 0x00, 0x42, 0x80, 0x00, 0x60, 0x40, 0x00, | ||
91 | 0x00, 0x75, 0x00, 0xe0, 0x00, 0x00, 0x00, 0x00, | ||
92 | 0x00, 0x00, 0x00, 0x00 | ||
93 | }; | ||
94 | |||
95 | static __inline__ u32 tda80xx_div(u32 a, u32 b) | ||
96 | { | ||
97 | return (a + (b / 2)) / b; | ||
98 | } | ||
99 | |||
100 | static __inline__ u32 tda80xx_gcd(u32 a, u32 b) | ||
101 | { | ||
102 | u32 r; | ||
103 | |||
104 | while ((r = a % b)) { | ||
105 | a = b; | ||
106 | b = r; | ||
107 | } | ||
108 | |||
109 | return b; | ||
110 | } | ||
111 | |||
112 | static int tda80xx_read(struct tda80xx_state* state, u8 reg, u8 *buf, u8 len) | ||
113 | { | ||
114 | int ret; | ||
115 | struct i2c_msg msg[] = { { .addr = state->config->demod_address, .flags = 0, .buf = ®, .len = 1 }, | ||
116 | { .addr = state->config->demod_address, .flags = I2C_M_RD, .buf = buf, .len = len } }; | ||
117 | |||
118 | ret = i2c_transfer(state->i2c, msg, 2); | ||
119 | |||
120 | if (ret != 2) | ||
121 | dprintk("%s: readreg error (reg %02x, ret == %i)\n", | ||
122 | __FUNCTION__, reg, ret); | ||
123 | |||
124 | mdelay(10); | ||
125 | |||
126 | return (ret == 2) ? 0 : -EREMOTEIO; | ||
127 | } | ||
128 | |||
129 | static int tda80xx_write(struct tda80xx_state* state, u8 reg, const u8 *buf, u8 len) | ||
130 | { | ||
131 | int ret; | ||
132 | u8 wbuf[len + 1]; | ||
133 | struct i2c_msg msg = { .addr = state->config->demod_address, .flags = 0, .buf = wbuf, .len = len + 1 }; | ||
134 | |||
135 | wbuf[0] = reg; | ||
136 | memcpy(&wbuf[1], buf, len); | ||
137 | |||
138 | ret = i2c_transfer(state->i2c, &msg, 1); | ||
139 | |||
140 | if (ret != 1) | ||
141 | dprintk("%s: i2c xfer error (ret == %i)\n", __FUNCTION__, ret); | ||
142 | |||
143 | mdelay(10); | ||
144 | |||
145 | return (ret == 1) ? 0 : -EREMOTEIO; | ||
146 | } | ||
147 | |||
148 | static __inline__ u8 tda80xx_readreg(struct tda80xx_state* state, u8 reg) | ||
149 | { | ||
150 | u8 val; | ||
151 | |||
152 | tda80xx_read(state, reg, &val, 1); | ||
153 | |||
154 | return val; | ||
155 | } | ||
156 | |||
157 | static __inline__ int tda80xx_writereg(struct tda80xx_state* state, u8 reg, u8 data) | ||
158 | { | ||
159 | return tda80xx_write(state, reg, &data, 1); | ||
160 | } | ||
161 | |||
162 | static int tda80xx_set_parameters(struct tda80xx_state* state, | ||
163 | fe_spectral_inversion_t inversion, | ||
164 | u32 symbol_rate, | ||
165 | fe_code_rate_t fec_inner) | ||
166 | { | ||
167 | u8 buf[15]; | ||
168 | u64 ratio; | ||
169 | u32 clk; | ||
170 | u32 k; | ||
171 | u32 sr = symbol_rate; | ||
172 | u32 gcd; | ||
173 | u8 scd; | ||
174 | |||
175 | if (symbol_rate > (state->clk * 3) / 16) | ||
176 | scd = 0; | ||
177 | else if (symbol_rate > (state->clk * 3) / 32) | ||
178 | scd = 1; | ||
179 | else if (symbol_rate > (state->clk * 3) / 64) | ||
180 | scd = 2; | ||
181 | else | ||
182 | scd = 3; | ||
183 | |||
184 | clk = scd ? (state->clk / (scd * 2)) : state->clk; | ||
185 | |||
186 | /* | ||
187 | * Viterbi decoder: | ||
188 | * Differential decoding off | ||
189 | * Spectral inversion unknown | ||
190 | * QPSK modulation | ||
191 | */ | ||
192 | if (inversion == INVERSION_ON) | ||
193 | buf[0] = 0x60; | ||
194 | else if (inversion == INVERSION_OFF) | ||
195 | buf[0] = 0x20; | ||
196 | else | ||
197 | buf[0] = 0x00; | ||
198 | |||
199 | /* | ||
200 | * CLK ratio: | ||
201 | * system clock frequency is up to 64 or 96 MHz | ||
202 | * | ||
203 | * formula: | ||
204 | * r = k * clk / symbol_rate | ||
205 | * | ||
206 | * k: 2^21 for caa 0..3, | ||
207 | * 2^20 for caa 4..5, | ||
208 | * 2^19 for caa 6..7 | ||
209 | */ | ||
210 | if (symbol_rate <= (clk * 3) / 32) | ||
211 | k = (1 << 19); | ||
212 | else if (symbol_rate <= (clk * 3) / 16) | ||
213 | k = (1 << 20); | ||
214 | else | ||
215 | k = (1 << 21); | ||
216 | |||
217 | gcd = tda80xx_gcd(clk, sr); | ||
218 | clk /= gcd; | ||
219 | sr /= gcd; | ||
220 | |||
221 | gcd = tda80xx_gcd(k, sr); | ||
222 | k /= gcd; | ||
223 | sr /= gcd; | ||
224 | |||
225 | ratio = (u64)k * (u64)clk; | ||
226 | do_div(ratio, sr); | ||
227 | |||
228 | buf[1] = ratio >> 16; | ||
229 | buf[2] = ratio >> 8; | ||
230 | buf[3] = ratio; | ||
231 | |||
232 | /* nyquist filter roll-off factor 35% */ | ||
233 | buf[4] = 0x20; | ||
234 | |||
235 | clk = scd ? (state->clk / (scd * 2)) : state->clk; | ||
236 | |||
237 | /* Anti Alias Filter */ | ||
238 | if (symbol_rate < (clk * 3) / 64) | ||
239 | printk("tda80xx: unsupported symbol rate: %u\n", symbol_rate); | ||
240 | else if (symbol_rate <= clk / 16) | ||
241 | buf[4] |= 0x07; | ||
242 | else if (symbol_rate <= (clk * 3) / 32) | ||
243 | buf[4] |= 0x06; | ||
244 | else if (symbol_rate <= clk / 8) | ||
245 | buf[4] |= 0x05; | ||
246 | else if (symbol_rate <= (clk * 3) / 16) | ||
247 | buf[4] |= 0x04; | ||
248 | else if (symbol_rate <= clk / 4) | ||
249 | buf[4] |= 0x03; | ||
250 | else if (symbol_rate <= (clk * 3) / 8) | ||
251 | buf[4] |= 0x02; | ||
252 | else if (symbol_rate <= clk / 2) | ||
253 | buf[4] |= 0x01; | ||
254 | else | ||
255 | buf[4] |= 0x00; | ||
256 | |||
257 | /* Sigma Delta converter */ | ||
258 | buf[5] = 0x00; | ||
259 | |||
260 | /* FEC: Possible puncturing rates */ | ||
261 | if (fec_inner == FEC_NONE) | ||
262 | buf[6] = 0x00; | ||
263 | else if ((fec_inner >= FEC_1_2) && (fec_inner <= FEC_8_9)) | ||
264 | buf[6] = (1 << (8 - fec_inner)); | ||
265 | else if (fec_inner == FEC_AUTO) | ||
266 | buf[6] = 0xff; | ||
267 | else | ||
268 | return -EINVAL; | ||
269 | |||
270 | /* carrier lock detector threshold value */ | ||
271 | buf[7] = 0x30; | ||
272 | /* AFC1: proportional part settings */ | ||
273 | buf[8] = 0x42; | ||
274 | /* AFC1: integral part settings */ | ||
275 | buf[9] = 0x98; | ||
276 | /* PD: Leaky integrator SCPC mode */ | ||
277 | buf[10] = 0x28; | ||
278 | /* AFC2, AFC1 controls */ | ||
279 | buf[11] = 0x30; | ||
280 | /* PD: proportional part settings */ | ||
281 | buf[12] = 0x42; | ||
282 | /* PD: integral part settings */ | ||
283 | buf[13] = 0x99; | ||
284 | /* AGC */ | ||
285 | buf[14] = 0x50 | scd; | ||
286 | |||
287 | printk("symbol_rate=%u clk=%u\n", symbol_rate, clk); | ||
288 | |||
289 | return tda80xx_write(state, 0x01, buf, sizeof(buf)); | ||
290 | } | ||
291 | |||
292 | static int tda80xx_set_clk(struct tda80xx_state* state) | ||
293 | { | ||
294 | u8 buf[2]; | ||
295 | |||
296 | /* CLK proportional part */ | ||
297 | buf[0] = (0x06 << 5) | 0x08; /* CMP[2:0], CSP[4:0] */ | ||
298 | /* CLK integral part */ | ||
299 | buf[1] = (0x04 << 5) | 0x1a; /* CMI[2:0], CSI[4:0] */ | ||
300 | |||
301 | return tda80xx_write(state, 0x17, buf, sizeof(buf)); | ||
302 | } | ||
303 | |||
304 | #if 0 | ||
305 | static int tda80xx_set_scpc_freq_offset(struct tda80xx_state* state) | ||
306 | { | ||
307 | /* a constant value is nonsense here imho */ | ||
308 | return tda80xx_writereg(state, 0x22, 0xf9); | ||
309 | } | ||
310 | #endif | ||
311 | |||
312 | static int tda80xx_close_loop(struct tda80xx_state* state) | ||
313 | { | ||
314 | u8 buf[2]; | ||
315 | |||
316 | /* PD: Loop closed, LD: lock detect enable, SCPC: Sweep mode - AFC1 loop closed */ | ||
317 | buf[0] = 0x68; | ||
318 | /* AFC1: Loop closed, CAR Feedback: 8192 */ | ||
319 | buf[1] = 0x70; | ||
320 | |||
321 | return tda80xx_write(state, 0x0b, buf, sizeof(buf)); | ||
322 | } | ||
323 | |||
324 | static irqreturn_t tda80xx_irq(int irq, void *priv, struct pt_regs *pt) | ||
325 | { | ||
326 | schedule_work(priv); | ||
327 | |||
328 | return IRQ_HANDLED; | ||
329 | } | ||
330 | |||
331 | static void tda80xx_read_status_int(struct tda80xx_state* state) | ||
332 | { | ||
333 | u8 val; | ||
334 | |||
335 | static const fe_spectral_inversion_t inv_tab[] = { | ||
336 | INVERSION_OFF, INVERSION_ON | ||
337 | }; | ||
338 | |||
339 | static const fe_code_rate_t fec_tab[] = { | ||
340 | FEC_8_9, FEC_1_2, FEC_2_3, FEC_3_4, | ||
341 | FEC_4_5, FEC_5_6, FEC_6_7, FEC_7_8, | ||
342 | }; | ||
343 | |||
344 | val = tda80xx_readreg(state, 0x02); | ||
345 | |||
346 | state->status = 0; | ||
347 | |||
348 | if (val & 0x01) /* demodulator lock */ | ||
349 | state->status |= FE_HAS_SIGNAL; | ||
350 | if (val & 0x02) /* clock recovery lock */ | ||
351 | state->status |= FE_HAS_CARRIER; | ||
352 | if (val & 0x04) /* viterbi lock */ | ||
353 | state->status |= FE_HAS_VITERBI; | ||
354 | if (val & 0x08) /* deinterleaver lock (packet sync) */ | ||
355 | state->status |= FE_HAS_SYNC; | ||
356 | if (val & 0x10) /* derandomizer lock (frame sync) */ | ||
357 | state->status |= FE_HAS_LOCK; | ||
358 | if (val & 0x20) /* frontend can not lock */ | ||
359 | state->status |= FE_TIMEDOUT; | ||
360 | |||
361 | if ((state->status & (FE_HAS_CARRIER)) && (state->afc_loop)) { | ||
362 | printk("tda80xx: closing loop\n"); | ||
363 | tda80xx_close_loop(state); | ||
364 | state->afc_loop = 0; | ||
365 | } | ||
366 | |||
367 | if (state->status & (FE_HAS_VITERBI | FE_HAS_SYNC | FE_HAS_LOCK)) { | ||
368 | val = tda80xx_readreg(state, 0x0e); | ||
369 | state->code_rate = fec_tab[val & 0x07]; | ||
370 | if (state->status & (FE_HAS_SYNC | FE_HAS_LOCK)) | ||
371 | state->spectral_inversion = inv_tab[(val >> 7) & 0x01]; | ||
372 | else | ||
373 | state->spectral_inversion = INVERSION_AUTO; | ||
374 | } | ||
375 | else { | ||
376 | state->code_rate = FEC_AUTO; | ||
377 | } | ||
378 | } | ||
379 | |||
380 | static void tda80xx_worklet(void *priv) | ||
381 | { | ||
382 | struct tda80xx_state *state = priv; | ||
383 | |||
384 | tda80xx_writereg(state, 0x00, 0x04); | ||
385 | enable_irq(state->config->irq); | ||
386 | |||
387 | tda80xx_read_status_int(state); | ||
388 | } | ||
389 | |||
390 | static void tda80xx_wait_diseqc_fifo(struct tda80xx_state* state) | ||
391 | { | ||
392 | size_t i; | ||
393 | |||
394 | for (i = 0; i < 100; i++) { | ||
395 | if (tda80xx_readreg(state, 0x02) & 0x80) | ||
396 | break; | ||
397 | msleep(10); | ||
398 | } | ||
399 | } | ||
400 | |||
401 | static int tda8044_init(struct dvb_frontend* fe) | ||
402 | { | ||
403 | struct tda80xx_state* state = (struct tda80xx_state*) fe->demodulator_priv; | ||
404 | int ret; | ||
405 | |||
406 | /* | ||
407 | * this function is a mess... | ||
408 | */ | ||
409 | |||
410 | if ((ret = tda80xx_write(state, 0x00, tda8044_inittab_pre, sizeof(tda8044_inittab_pre)))) | ||
411 | return ret; | ||
412 | |||
413 | tda80xx_writereg(state, 0x0f, 0x50); | ||
414 | #if 1 | ||
415 | tda80xx_writereg(state, 0x20, 0x8F); /* FIXME */ | ||
416 | tda80xx_writereg(state, 0x20, state->config->volt18setting); /* FIXME */ | ||
417 | //tda80xx_writereg(state, 0x00, 0x04); | ||
418 | tda80xx_writereg(state, 0x00, 0x0C); | ||
419 | #endif | ||
420 | //tda80xx_writereg(state, 0x00, 0x08); /* Reset AFC1 loop filter */ | ||
421 | |||
422 | tda80xx_write(state, 0x00, tda8044_inittab_post, sizeof(tda8044_inittab_post)); | ||
423 | |||
424 | if (state->config->pll_init) { | ||
425 | tda80xx_writereg(state, 0x1c, 0x80); | ||
426 | state->config->pll_init(fe); | ||
427 | tda80xx_writereg(state, 0x1c, 0x00); | ||
428 | } | ||
429 | |||
430 | return 0; | ||
431 | } | ||
432 | |||
433 | static int tda8083_init(struct dvb_frontend* fe) | ||
434 | { | ||
435 | struct tda80xx_state* state = (struct tda80xx_state*) fe->demodulator_priv; | ||
436 | |||
437 | tda80xx_write(state, 0x00, tda8083_inittab, sizeof(tda8083_inittab)); | ||
438 | |||
439 | if (state->config->pll_init) { | ||
440 | tda80xx_writereg(state, 0x1c, 0x80); | ||
441 | state->config->pll_init(fe); | ||
442 | tda80xx_writereg(state, 0x1c, 0x00); | ||
443 | } | ||
444 | |||
445 | return 0; | ||
446 | } | ||
447 | |||
448 | static int tda80xx_set_voltage(struct dvb_frontend* fe, fe_sec_voltage_t voltage) | ||
449 | { | ||
450 | struct tda80xx_state* state = (struct tda80xx_state*) fe->demodulator_priv; | ||
451 | |||
452 | switch (voltage) { | ||
453 | case SEC_VOLTAGE_13: | ||
454 | return tda80xx_writereg(state, 0x20, state->config->volt13setting); | ||
455 | case SEC_VOLTAGE_18: | ||
456 | return tda80xx_writereg(state, 0x20, state->config->volt18setting); | ||
457 | case SEC_VOLTAGE_OFF: | ||
458 | return tda80xx_writereg(state, 0x20, 0); | ||
459 | default: | ||
460 | return -EINVAL; | ||
461 | } | ||
462 | } | ||
463 | |||
464 | static int tda80xx_set_tone(struct dvb_frontend* fe, fe_sec_tone_mode_t tone) | ||
465 | { | ||
466 | struct tda80xx_state* state = (struct tda80xx_state*) fe->demodulator_priv; | ||
467 | |||
468 | switch (tone) { | ||
469 | case SEC_TONE_OFF: | ||
470 | return tda80xx_writereg(state, 0x29, 0x00); | ||
471 | case SEC_TONE_ON: | ||
472 | return tda80xx_writereg(state, 0x29, 0x80); | ||
473 | default: | ||
474 | return -EINVAL; | ||
475 | } | ||
476 | } | ||
477 | |||
478 | static int tda80xx_send_diseqc_msg(struct dvb_frontend* fe, struct dvb_diseqc_master_cmd *cmd) | ||
479 | { | ||
480 | struct tda80xx_state* state = (struct tda80xx_state*) fe->demodulator_priv; | ||
481 | |||
482 | if (cmd->msg_len > 6) | ||
483 | return -EINVAL; | ||
484 | |||
485 | tda80xx_writereg(state, 0x29, 0x08 | (cmd->msg_len - 3)); | ||
486 | tda80xx_write(state, 0x23, cmd->msg, cmd->msg_len); | ||
487 | tda80xx_writereg(state, 0x29, 0x0c | (cmd->msg_len - 3)); | ||
488 | tda80xx_wait_diseqc_fifo(state); | ||
489 | |||
490 | return 0; | ||
491 | } | ||
492 | |||
493 | static int tda80xx_send_diseqc_burst(struct dvb_frontend* fe, fe_sec_mini_cmd_t cmd) | ||
494 | { | ||
495 | struct tda80xx_state* state = (struct tda80xx_state*) fe->demodulator_priv; | ||
496 | |||
497 | switch (cmd) { | ||
498 | case SEC_MINI_A: | ||
499 | tda80xx_writereg(state, 0x29, 0x14); | ||
500 | break; | ||
501 | case SEC_MINI_B: | ||
502 | tda80xx_writereg(state, 0x29, 0x1c); | ||
503 | break; | ||
504 | default: | ||
505 | return -EINVAL; | ||
506 | } | ||
507 | |||
508 | tda80xx_wait_diseqc_fifo(state); | ||
509 | |||
510 | return 0; | ||
511 | } | ||
512 | |||
513 | static int tda80xx_sleep(struct dvb_frontend* fe) | ||
514 | { | ||
515 | struct tda80xx_state* state = (struct tda80xx_state*) fe->demodulator_priv; | ||
516 | |||
517 | tda80xx_writereg(state, 0x00, 0x02); /* enter standby */ | ||
518 | |||
519 | return 0; | ||
520 | } | ||
521 | |||
522 | static int tda80xx_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p) | ||
523 | { | ||
524 | struct tda80xx_state* state = (struct tda80xx_state*) fe->demodulator_priv; | ||
525 | |||
526 | tda80xx_writereg(state, 0x1c, 0x80); | ||
527 | state->config->pll_set(fe, p); | ||
528 | tda80xx_writereg(state, 0x1c, 0x00); | ||
529 | |||
530 | tda80xx_set_parameters(state, p->inversion, p->u.qpsk.symbol_rate, p->u.qpsk.fec_inner); | ||
531 | tda80xx_set_clk(state); | ||
532 | //tda80xx_set_scpc_freq_offset(state); | ||
533 | state->afc_loop = 1; | ||
534 | |||
535 | return 0; | ||
536 | } | ||
537 | |||
538 | static int tda80xx_get_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p) | ||
539 | { | ||
540 | struct tda80xx_state* state = (struct tda80xx_state*) fe->demodulator_priv; | ||
541 | |||
542 | if (!state->config->irq) | ||
543 | tda80xx_read_status_int(state); | ||
544 | |||
545 | p->inversion = state->spectral_inversion; | ||
546 | p->u.qpsk.fec_inner = state->code_rate; | ||
547 | |||
548 | return 0; | ||
549 | } | ||
550 | |||
551 | static int tda80xx_read_status(struct dvb_frontend* fe, fe_status_t* status) | ||
552 | { | ||
553 | struct tda80xx_state* state = (struct tda80xx_state*) fe->demodulator_priv; | ||
554 | |||
555 | if (!state->config->irq) | ||
556 | tda80xx_read_status_int(state); | ||
557 | *status = state->status; | ||
558 | |||
559 | return 0; | ||
560 | } | ||
561 | |||
562 | static int tda80xx_read_ber(struct dvb_frontend* fe, u32* ber) | ||
563 | { | ||
564 | struct tda80xx_state* state = (struct tda80xx_state*) fe->demodulator_priv; | ||
565 | int ret; | ||
566 | u8 buf[3]; | ||
567 | |||
568 | if ((ret = tda80xx_read(state, 0x0b, buf, sizeof(buf)))) | ||
569 | return ret; | ||
570 | |||
571 | *ber = ((buf[0] & 0x1f) << 16) | (buf[1] << 8) | buf[2]; | ||
572 | |||
573 | return 0; | ||
574 | } | ||
575 | |||
576 | static int tda80xx_read_signal_strength(struct dvb_frontend* fe, u16* strength) | ||
577 | { | ||
578 | struct tda80xx_state* state = (struct tda80xx_state*) fe->demodulator_priv; | ||
579 | |||
580 | u8 gain = ~tda80xx_readreg(state, 0x01); | ||
581 | *strength = (gain << 8) | gain; | ||
582 | |||
583 | return 0; | ||
584 | } | ||
585 | |||
586 | static int tda80xx_read_snr(struct dvb_frontend* fe, u16* snr) | ||
587 | { | ||
588 | struct tda80xx_state* state = (struct tda80xx_state*) fe->demodulator_priv; | ||
589 | |||
590 | u8 quality = tda80xx_readreg(state, 0x08); | ||
591 | *snr = (quality << 8) | quality; | ||
592 | |||
593 | return 0; | ||
594 | } | ||
595 | |||
596 | static int tda80xx_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks) | ||
597 | { | ||
598 | struct tda80xx_state* state = (struct tda80xx_state*) fe->demodulator_priv; | ||
599 | |||
600 | *ucblocks = tda80xx_readreg(state, 0x0f); | ||
601 | if (*ucblocks == 0xff) | ||
602 | *ucblocks = 0xffffffff; | ||
603 | |||
604 | return 0; | ||
605 | } | ||
606 | |||
607 | static int tda80xx_init(struct dvb_frontend* fe) | ||
608 | { | ||
609 | struct tda80xx_state* state = (struct tda80xx_state*) fe->demodulator_priv; | ||
610 | |||
611 | switch(state->id) { | ||
612 | case ID_TDA8044: | ||
613 | return tda8044_init(fe); | ||
614 | |||
615 | case ID_TDA8083: | ||
616 | return tda8083_init(fe); | ||
617 | } | ||
618 | return 0; | ||
619 | } | ||
620 | |||
621 | static void tda80xx_release(struct dvb_frontend* fe) | ||
622 | { | ||
623 | struct tda80xx_state* state = (struct tda80xx_state*) fe->demodulator_priv; | ||
624 | |||
625 | if (state->config->irq) | ||
626 | free_irq(state->config->irq, &state->worklet); | ||
627 | |||
628 | kfree(state); | ||
629 | } | ||
630 | |||
631 | static struct dvb_frontend_ops tda80xx_ops; | ||
632 | |||
633 | struct dvb_frontend* tda80xx_attach(const struct tda80xx_config* config, | ||
634 | struct i2c_adapter* i2c) | ||
635 | { | ||
636 | struct tda80xx_state* state = NULL; | ||
637 | int ret; | ||
638 | |||
639 | /* allocate memory for the internal state */ | ||
640 | state = (struct tda80xx_state*) kmalloc(sizeof(struct tda80xx_state), GFP_KERNEL); | ||
641 | if (state == NULL) goto error; | ||
642 | |||
643 | /* setup the state */ | ||
644 | state->config = config; | ||
645 | state->i2c = i2c; | ||
646 | memcpy(&state->ops, &tda80xx_ops, sizeof(struct dvb_frontend_ops)); | ||
647 | state->spectral_inversion = INVERSION_AUTO; | ||
648 | state->code_rate = FEC_AUTO; | ||
649 | state->status = 0; | ||
650 | state->afc_loop = 0; | ||
651 | |||
652 | /* check if the demod is there */ | ||
653 | if (tda80xx_writereg(state, 0x89, 0x00) < 0) goto error; | ||
654 | state->id = tda80xx_readreg(state, 0x00); | ||
655 | |||
656 | switch (state->id) { | ||
657 | case ID_TDA8044: | ||
658 | state->clk = 96000000; | ||
659 | printk("tda80xx: Detected tda8044\n"); | ||
660 | break; | ||
661 | |||
662 | case ID_TDA8083: | ||
663 | state->clk = 64000000; | ||
664 | printk("tda80xx: Detected tda8083\n"); | ||
665 | break; | ||
666 | |||
667 | default: | ||
668 | goto error; | ||
669 | } | ||
670 | |||
671 | /* setup IRQ */ | ||
672 | if (state->config->irq) { | ||
673 | INIT_WORK(&state->worklet, tda80xx_worklet, state); | ||
674 | if ((ret = request_irq(state->config->irq, tda80xx_irq, SA_ONESHOT, "tda80xx", &state->worklet)) < 0) { | ||
675 | printk(KERN_ERR "tda80xx: request_irq failed (%d)\n", ret); | ||
676 | goto error; | ||
677 | } | ||
678 | } | ||
679 | |||
680 | /* create dvb_frontend */ | ||
681 | state->frontend.ops = &state->ops; | ||
682 | state->frontend.demodulator_priv = state; | ||
683 | return &state->frontend; | ||
684 | |||
685 | error: | ||
686 | kfree(state); | ||
687 | return NULL; | ||
688 | } | ||
689 | |||
690 | static struct dvb_frontend_ops tda80xx_ops = { | ||
691 | |||
692 | .info = { | ||
693 | .name = "Philips TDA80xx DVB-S", | ||
694 | .type = FE_QPSK, | ||
695 | .frequency_min = 500000, | ||
696 | .frequency_max = 2700000, | ||
697 | .frequency_stepsize = 125, | ||
698 | .symbol_rate_min = 4500000, | ||
699 | .symbol_rate_max = 45000000, | ||
700 | .caps = FE_CAN_INVERSION_AUTO | | ||
701 | FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | | ||
702 | FE_CAN_FEC_4_5 | FE_CAN_FEC_5_6 | FE_CAN_FEC_6_7 | | ||
703 | FE_CAN_FEC_7_8 | FE_CAN_FEC_8_9 | FE_CAN_FEC_AUTO | | ||
704 | FE_CAN_QPSK | | ||
705 | FE_CAN_MUTE_TS | ||
706 | }, | ||
707 | |||
708 | .release = tda80xx_release, | ||
709 | |||
710 | .init = tda80xx_init, | ||
711 | .sleep = tda80xx_sleep, | ||
712 | |||
713 | .set_frontend = tda80xx_set_frontend, | ||
714 | .get_frontend = tda80xx_get_frontend, | ||
715 | |||
716 | .read_status = tda80xx_read_status, | ||
717 | .read_ber = tda80xx_read_ber, | ||
718 | .read_signal_strength = tda80xx_read_signal_strength, | ||
719 | .read_snr = tda80xx_read_snr, | ||
720 | .read_ucblocks = tda80xx_read_ucblocks, | ||
721 | |||
722 | .diseqc_send_master_cmd = tda80xx_send_diseqc_msg, | ||
723 | .diseqc_send_burst = tda80xx_send_diseqc_burst, | ||
724 | .set_tone = tda80xx_set_tone, | ||
725 | .set_voltage = tda80xx_set_voltage, | ||
726 | }; | ||
727 | |||
728 | module_param(debug, int, 0644); | ||
729 | |||
730 | MODULE_DESCRIPTION("Philips TDA8044 / TDA8083 DVB-S Demodulator driver"); | ||
731 | MODULE_AUTHOR("Felix Domke, Andreas Oberritter"); | ||
732 | MODULE_LICENSE("GPL"); | ||
733 | |||
734 | EXPORT_SYMBOL(tda80xx_attach); | ||
diff --git a/drivers/media/dvb/frontends/tda80xx.h b/drivers/media/dvb/frontends/tda80xx.h new file mode 100644 index 000000000000..cd639a0aad55 --- /dev/null +++ b/drivers/media/dvb/frontends/tda80xx.h | |||
@@ -0,0 +1,51 @@ | |||
1 | /* | ||
2 | * tda80xx.c | ||
3 | * | ||
4 | * Philips TDA8044 / TDA8083 QPSK demodulator driver | ||
5 | * | ||
6 | * Copyright (C) 2001 Felix Domke <tmbinc@elitedvb.net> | ||
7 | * Copyright (C) 2002-2004 Andreas Oberritter <obi@linuxtv.org> | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or modify | ||
10 | * it under the terms of the GNU General Public License as published by | ||
11 | * the Free Software Foundation; either version 2 of the License, or | ||
12 | * (at your option) any later version. | ||
13 | * | ||
14 | * This program is distributed in the hope that it will be useful, | ||
15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
17 | * GNU General Public License for more details. | ||
18 | * | ||
19 | * You should have received a copy of the GNU General Public License | ||
20 | * along with this program; if not, write to the Free Software | ||
21 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
22 | */ | ||
23 | |||
24 | #ifndef TDA80XX_H | ||
25 | #define TDA80XX_H | ||
26 | |||
27 | #include <linux/dvb/frontend.h> | ||
28 | |||
29 | struct tda80xx_config | ||
30 | { | ||
31 | /* the demodulator's i2c address */ | ||
32 | u8 demod_address; | ||
33 | |||
34 | /* IRQ to use (0=>no IRQ used) */ | ||
35 | u32 irq; | ||
36 | |||
37 | /* Register setting to use for 13v */ | ||
38 | u8 volt13setting; | ||
39 | |||
40 | /* Register setting to use for 18v */ | ||
41 | u8 volt18setting; | ||
42 | |||
43 | /* PLL maintenance */ | ||
44 | int (*pll_init)(struct dvb_frontend* fe); | ||
45 | int (*pll_set)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params); | ||
46 | }; | ||
47 | |||
48 | extern struct dvb_frontend* tda80xx_attach(const struct tda80xx_config* config, | ||
49 | struct i2c_adapter* i2c); | ||
50 | |||
51 | #endif // TDA80XX_H | ||
diff --git a/drivers/media/dvb/frontends/ves1820.c b/drivers/media/dvb/frontends/ves1820.c new file mode 100644 index 000000000000..9c0d23e1d9e5 --- /dev/null +++ b/drivers/media/dvb/frontends/ves1820.c | |||
@@ -0,0 +1,450 @@ | |||
1 | /* | ||
2 | VES1820 - Single Chip Cable Channel Receiver driver module | ||
3 | |||
4 | Copyright (C) 1999 Convergence Integrated Media GmbH <ralph@convergence.de> | ||
5 | |||
6 | This program is free software; you can redistribute it and/or modify | ||
7 | it under the terms of the GNU General Public License as published by | ||
8 | the Free Software Foundation; either version 2 of the License, or | ||
9 | (at your option) any later version. | ||
10 | |||
11 | This program is distributed in the hope that it will be useful, | ||
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | GNU General Public License for more details. | ||
15 | |||
16 | You should have received a copy of the GNU General Public License | ||
17 | along with this program; if not, write to the Free Software | ||
18 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
19 | */ | ||
20 | |||
21 | #include <linux/config.h> | ||
22 | #include <linux/delay.h> | ||
23 | #include <linux/errno.h> | ||
24 | #include <linux/init.h> | ||
25 | #include <linux/kernel.h> | ||
26 | #include <linux/module.h> | ||
27 | #include <linux/string.h> | ||
28 | #include <linux/slab.h> | ||
29 | #include <asm/div64.h> | ||
30 | |||
31 | #include "dvb_frontend.h" | ||
32 | #include "ves1820.h" | ||
33 | |||
34 | |||
35 | |||
36 | struct ves1820_state { | ||
37 | struct i2c_adapter* i2c; | ||
38 | struct dvb_frontend_ops ops; | ||
39 | /* configuration settings */ | ||
40 | const struct ves1820_config* config; | ||
41 | struct dvb_frontend frontend; | ||
42 | |||
43 | /* private demodulator data */ | ||
44 | u8 reg0; | ||
45 | u8 pwm; | ||
46 | }; | ||
47 | |||
48 | |||
49 | static int verbose; | ||
50 | |||
51 | static u8 ves1820_inittab[] = { | ||
52 | 0x69, 0x6A, 0x93, 0x12, 0x12, 0x46, 0x26, 0x1A, | ||
53 | 0x43, 0x6A, 0xAA, 0xAA, 0x1E, 0x85, 0x43, 0x20, | ||
54 | 0xE0, 0x00, 0xA1, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
55 | 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, | ||
56 | 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
57 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
58 | 0x00, 0x00, 0x00, 0x00, 0x40 | ||
59 | }; | ||
60 | |||
61 | static int ves1820_writereg(struct ves1820_state *state, u8 reg, u8 data) | ||
62 | { | ||
63 | u8 buf[] = { 0x00, reg, data }; | ||
64 | struct i2c_msg msg = {.addr = state->config->demod_address,.flags = 0,.buf = buf,.len = 3 }; | ||
65 | int ret; | ||
66 | |||
67 | ret = i2c_transfer(state->i2c, &msg, 1); | ||
68 | |||
69 | if (ret != 1) | ||
70 | printk("ves1820: %s(): writereg error (reg == 0x%02x," | ||
71 | "val == 0x%02x, ret == %i)\n", __FUNCTION__, reg, data, ret); | ||
72 | |||
73 | msleep(10); | ||
74 | return (ret != 1) ? -EREMOTEIO : 0; | ||
75 | } | ||
76 | |||
77 | static u8 ves1820_readreg(struct ves1820_state *state, u8 reg) | ||
78 | { | ||
79 | u8 b0[] = { 0x00, reg }; | ||
80 | u8 b1[] = { 0 }; | ||
81 | struct i2c_msg msg[] = { | ||
82 | {.addr = state->config->demod_address,.flags = 0,.buf = b0,.len = 2}, | ||
83 | {.addr = state->config->demod_address,.flags = I2C_M_RD,.buf = b1,.len = 1} | ||
84 | }; | ||
85 | int ret; | ||
86 | |||
87 | ret = i2c_transfer(state->i2c, msg, 2); | ||
88 | |||
89 | if (ret != 2) | ||
90 | printk("ves1820: %s(): readreg error (reg == 0x%02x," | ||
91 | "ret == %i)\n", __FUNCTION__, reg, ret); | ||
92 | |||
93 | return b1[0]; | ||
94 | } | ||
95 | |||
96 | static int ves1820_setup_reg0(struct ves1820_state *state, u8 reg0, fe_spectral_inversion_t inversion) | ||
97 | { | ||
98 | reg0 |= state->reg0 & 0x62; | ||
99 | |||
100 | if (INVERSION_ON == inversion) { | ||
101 | if (!state->config->invert) reg0 |= 0x20; | ||
102 | else reg0 &= ~0x20; | ||
103 | } else if (INVERSION_OFF == inversion) { | ||
104 | if (!state->config->invert) reg0 &= ~0x20; | ||
105 | else reg0 |= 0x20; | ||
106 | } | ||
107 | |||
108 | ves1820_writereg(state, 0x00, reg0 & 0xfe); | ||
109 | ves1820_writereg(state, 0x00, reg0 | 0x01); | ||
110 | |||
111 | state->reg0 = reg0; | ||
112 | |||
113 | return 0; | ||
114 | } | ||
115 | |||
116 | static int ves1820_set_symbolrate(struct ves1820_state *state, u32 symbolrate) | ||
117 | { | ||
118 | s32 BDR; | ||
119 | s32 BDRI; | ||
120 | s16 SFIL = 0; | ||
121 | u16 NDEC = 0; | ||
122 | u32 ratio; | ||
123 | u32 fin; | ||
124 | u32 tmp; | ||
125 | u64 fptmp; | ||
126 | u64 fpxin; | ||
127 | |||
128 | if (symbolrate > state->config->xin / 2) | ||
129 | symbolrate = state->config->xin / 2; | ||
130 | |||
131 | if (symbolrate < 500000) | ||
132 | symbolrate = 500000; | ||
133 | |||
134 | if (symbolrate < state->config->xin / 16) | ||
135 | NDEC = 1; | ||
136 | if (symbolrate < state->config->xin / 32) | ||
137 | NDEC = 2; | ||
138 | if (symbolrate < state->config->xin / 64) | ||
139 | NDEC = 3; | ||
140 | |||
141 | /* yeuch! */ | ||
142 | fpxin = state->config->xin * 10; | ||
143 | fptmp = fpxin; do_div(fptmp, 123); | ||
144 | if (symbolrate < fptmp); | ||
145 | SFIL = 1; | ||
146 | fptmp = fpxin; do_div(fptmp, 160); | ||
147 | if (symbolrate < fptmp); | ||
148 | SFIL = 0; | ||
149 | fptmp = fpxin; do_div(fptmp, 246); | ||
150 | if (symbolrate < fptmp); | ||
151 | SFIL = 1; | ||
152 | fptmp = fpxin; do_div(fptmp, 320); | ||
153 | if (symbolrate < fptmp); | ||
154 | SFIL = 0; | ||
155 | fptmp = fpxin; do_div(fptmp, 492); | ||
156 | if (symbolrate < fptmp); | ||
157 | SFIL = 1; | ||
158 | fptmp = fpxin; do_div(fptmp, 640); | ||
159 | if (symbolrate < fptmp); | ||
160 | SFIL = 0; | ||
161 | fptmp = fpxin; do_div(fptmp, 984); | ||
162 | if (symbolrate < fptmp); | ||
163 | SFIL = 1; | ||
164 | |||
165 | fin = state->config->xin >> 4; | ||
166 | symbolrate <<= NDEC; | ||
167 | ratio = (symbolrate << 4) / fin; | ||
168 | tmp = ((symbolrate << 4) % fin) << 8; | ||
169 | ratio = (ratio << 8) + tmp / fin; | ||
170 | tmp = (tmp % fin) << 8; | ||
171 | ratio = (ratio << 8) + (tmp + fin / 2) / fin; | ||
172 | |||
173 | BDR = ratio; | ||
174 | BDRI = (((state->config->xin << 5) / symbolrate) + 1) / 2; | ||
175 | |||
176 | if (BDRI > 0xFF) | ||
177 | BDRI = 0xFF; | ||
178 | |||
179 | SFIL = (SFIL << 4) | ves1820_inittab[0x0E]; | ||
180 | |||
181 | NDEC = (NDEC << 6) | ves1820_inittab[0x03]; | ||
182 | |||
183 | ves1820_writereg(state, 0x03, NDEC); | ||
184 | ves1820_writereg(state, 0x0a, BDR & 0xff); | ||
185 | ves1820_writereg(state, 0x0b, (BDR >> 8) & 0xff); | ||
186 | ves1820_writereg(state, 0x0c, (BDR >> 16) & 0x3f); | ||
187 | |||
188 | ves1820_writereg(state, 0x0d, BDRI); | ||
189 | ves1820_writereg(state, 0x0e, SFIL); | ||
190 | |||
191 | return 0; | ||
192 | } | ||
193 | |||
194 | static int ves1820_init(struct dvb_frontend* fe) | ||
195 | { | ||
196 | struct ves1820_state* state = (struct ves1820_state*) fe->demodulator_priv; | ||
197 | int i; | ||
198 | int val; | ||
199 | |||
200 | ves1820_writereg(state, 0, 0); | ||
201 | |||
202 | for (i = 0; i < 53; i++) { | ||
203 | val = ves1820_inittab[i]; | ||
204 | if ((i == 2) && (state->config->selagc)) val |= 0x08; | ||
205 | ves1820_writereg(state, i, val); | ||
206 | } | ||
207 | |||
208 | ves1820_writereg(state, 0x34, state->pwm); | ||
209 | |||
210 | if (state->config->pll_init) state->config->pll_init(fe); | ||
211 | |||
212 | return 0; | ||
213 | } | ||
214 | |||
215 | static int ves1820_set_parameters(struct dvb_frontend* fe, struct dvb_frontend_parameters *p) | ||
216 | { | ||
217 | struct ves1820_state* state = (struct ves1820_state*) fe->demodulator_priv; | ||
218 | static const u8 reg0x00[] = { 0x00, 0x04, 0x08, 0x0c, 0x10 }; | ||
219 | static const u8 reg0x01[] = { 140, 140, 106, 100, 92 }; | ||
220 | static const u8 reg0x05[] = { 135, 100, 70, 54, 38 }; | ||
221 | static const u8 reg0x08[] = { 162, 116, 67, 52, 35 }; | ||
222 | static const u8 reg0x09[] = { 145, 150, 106, 126, 107 }; | ||
223 | int real_qam = p->u.qam.modulation - QAM_16; | ||
224 | |||
225 | if (real_qam < 0 || real_qam > 4) | ||
226 | return -EINVAL; | ||
227 | |||
228 | state->config->pll_set(fe, p); | ||
229 | ves1820_set_symbolrate(state, p->u.qam.symbol_rate); | ||
230 | ves1820_writereg(state, 0x34, state->pwm); | ||
231 | |||
232 | ves1820_writereg(state, 0x01, reg0x01[real_qam]); | ||
233 | ves1820_writereg(state, 0x05, reg0x05[real_qam]); | ||
234 | ves1820_writereg(state, 0x08, reg0x08[real_qam]); | ||
235 | ves1820_writereg(state, 0x09, reg0x09[real_qam]); | ||
236 | |||
237 | ves1820_setup_reg0(state, reg0x00[real_qam], p->inversion); | ||
238 | |||
239 | return 0; | ||
240 | } | ||
241 | |||
242 | static int ves1820_read_status(struct dvb_frontend* fe, fe_status_t* status) | ||
243 | { | ||
244 | struct ves1820_state* state = (struct ves1820_state*) fe->demodulator_priv; | ||
245 | int sync; | ||
246 | |||
247 | *status = 0; | ||
248 | sync = ves1820_readreg(state, 0x11); | ||
249 | |||
250 | if (sync & 1) | ||
251 | *status |= FE_HAS_SIGNAL; | ||
252 | |||
253 | if (sync & 2) | ||
254 | *status |= FE_HAS_CARRIER; | ||
255 | |||
256 | if (sync & 2) /* XXX FIXME! */ | ||
257 | *status |= FE_HAS_VITERBI; | ||
258 | |||
259 | if (sync & 4) | ||
260 | *status |= FE_HAS_SYNC; | ||
261 | |||
262 | if (sync & 8) | ||
263 | *status |= FE_HAS_LOCK; | ||
264 | |||
265 | return 0; | ||
266 | } | ||
267 | |||
268 | static int ves1820_read_ber(struct dvb_frontend* fe, u32* ber) | ||
269 | { | ||
270 | struct ves1820_state* state = (struct ves1820_state*) fe->demodulator_priv; | ||
271 | |||
272 | u32 _ber = ves1820_readreg(state, 0x14) | | ||
273 | (ves1820_readreg(state, 0x15) << 8) | | ||
274 | ((ves1820_readreg(state, 0x16) & 0x0f) << 16); | ||
275 | *ber = 10 * _ber; | ||
276 | |||
277 | return 0; | ||
278 | } | ||
279 | |||
280 | static int ves1820_read_signal_strength(struct dvb_frontend* fe, u16* strength) | ||
281 | { | ||
282 | struct ves1820_state* state = (struct ves1820_state*) fe->demodulator_priv; | ||
283 | |||
284 | u8 gain = ves1820_readreg(state, 0x17); | ||
285 | *strength = (gain << 8) | gain; | ||
286 | |||
287 | return 0; | ||
288 | } | ||
289 | |||
290 | static int ves1820_read_snr(struct dvb_frontend* fe, u16* snr) | ||
291 | { | ||
292 | struct ves1820_state* state = (struct ves1820_state*) fe->demodulator_priv; | ||
293 | |||
294 | u8 quality = ~ves1820_readreg(state, 0x18); | ||
295 | *snr = (quality << 8) | quality; | ||
296 | |||
297 | return 0; | ||
298 | } | ||
299 | |||
300 | static int ves1820_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks) | ||
301 | { | ||
302 | struct ves1820_state* state = (struct ves1820_state*) fe->demodulator_priv; | ||
303 | |||
304 | *ucblocks = ves1820_readreg(state, 0x13) & 0x7f; | ||
305 | if (*ucblocks == 0x7f) | ||
306 | *ucblocks = 0xffffffff; | ||
307 | |||
308 | /* reset uncorrected block counter */ | ||
309 | ves1820_writereg(state, 0x10, ves1820_inittab[0x10] & 0xdf); | ||
310 | ves1820_writereg(state, 0x10, ves1820_inittab[0x10]); | ||
311 | |||
312 | return 0; | ||
313 | } | ||
314 | |||
315 | static int ves1820_get_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p) | ||
316 | { | ||
317 | struct ves1820_state* state = (struct ves1820_state*) fe->demodulator_priv; | ||
318 | int sync; | ||
319 | s8 afc = 0; | ||
320 | |||
321 | sync = ves1820_readreg(state, 0x11); | ||
322 | afc = ves1820_readreg(state, 0x19); | ||
323 | if (verbose) { | ||
324 | /* AFC only valid when carrier has been recovered */ | ||
325 | printk(sync & 2 ? "ves1820: AFC (%d) %dHz\n" : | ||
326 | "ves1820: [AFC (%d) %dHz]\n", afc, -((s32) p->u.qam.symbol_rate * afc) >> 10); | ||
327 | } | ||
328 | |||
329 | if (!state->config->invert) { | ||
330 | p->inversion = (state->reg0 & 0x20) ? INVERSION_ON : INVERSION_OFF; | ||
331 | } else { | ||
332 | p->inversion = (!(state->reg0 & 0x20)) ? INVERSION_ON : INVERSION_OFF; | ||
333 | } | ||
334 | |||
335 | p->u.qam.modulation = ((state->reg0 >> 2) & 7) + QAM_16; | ||
336 | |||
337 | p->u.qam.fec_inner = FEC_NONE; | ||
338 | |||
339 | p->frequency = ((p->frequency + 31250) / 62500) * 62500; | ||
340 | if (sync & 2) | ||
341 | p->frequency -= ((s32) p->u.qam.symbol_rate * afc) >> 10; | ||
342 | |||
343 | return 0; | ||
344 | } | ||
345 | |||
346 | static int ves1820_sleep(struct dvb_frontend* fe) | ||
347 | { | ||
348 | struct ves1820_state* state = (struct ves1820_state*) fe->demodulator_priv; | ||
349 | |||
350 | ves1820_writereg(state, 0x1b, 0x02); /* pdown ADC */ | ||
351 | ves1820_writereg(state, 0x00, 0x80); /* standby */ | ||
352 | |||
353 | return 0; | ||
354 | } | ||
355 | |||
356 | static int ves1820_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings* fesettings) | ||
357 | { | ||
358 | |||
359 | fesettings->min_delay_ms = 200; | ||
360 | fesettings->step_size = 0; | ||
361 | fesettings->max_drift = 0; | ||
362 | return 0; | ||
363 | } | ||
364 | |||
365 | static void ves1820_release(struct dvb_frontend* fe) | ||
366 | { | ||
367 | struct ves1820_state* state = (struct ves1820_state*) fe->demodulator_priv; | ||
368 | kfree(state); | ||
369 | } | ||
370 | |||
371 | static struct dvb_frontend_ops ves1820_ops; | ||
372 | |||
373 | struct dvb_frontend* ves1820_attach(const struct ves1820_config* config, | ||
374 | struct i2c_adapter* i2c, | ||
375 | u8 pwm) | ||
376 | { | ||
377 | struct ves1820_state* state = NULL; | ||
378 | |||
379 | /* allocate memory for the internal state */ | ||
380 | state = (struct ves1820_state*) kmalloc(sizeof(struct ves1820_state), GFP_KERNEL); | ||
381 | if (state == NULL) | ||
382 | goto error; | ||
383 | |||
384 | /* setup the state */ | ||
385 | memcpy(&state->ops, &ves1820_ops, sizeof(struct dvb_frontend_ops)); | ||
386 | state->reg0 = ves1820_inittab[0]; | ||
387 | state->config = config; | ||
388 | state->i2c = i2c; | ||
389 | state->pwm = pwm; | ||
390 | |||
391 | /* check if the demod is there */ | ||
392 | if ((ves1820_readreg(state, 0x1a) & 0xf0) != 0x70) | ||
393 | goto error; | ||
394 | |||
395 | if (verbose) | ||
396 | printk("ves1820: pwm=0x%02x\n", state->pwm); | ||
397 | |||
398 | state->ops.info.symbol_rate_min = (state->config->xin / 2) / 64; /* SACLK/64 == (XIN/2)/64 */ | ||
399 | state->ops.info.symbol_rate_max = (state->config->xin / 2) / 4; /* SACLK/4 */ | ||
400 | |||
401 | /* create dvb_frontend */ | ||
402 | state->frontend.ops = &state->ops; | ||
403 | state->frontend.demodulator_priv = state; | ||
404 | return &state->frontend; | ||
405 | |||
406 | error: | ||
407 | kfree(state); | ||
408 | return NULL; | ||
409 | } | ||
410 | |||
411 | static struct dvb_frontend_ops ves1820_ops = { | ||
412 | |||
413 | .info = { | ||
414 | .name = "VLSI VES1820 DVB-C", | ||
415 | .type = FE_QAM, | ||
416 | .frequency_stepsize = 62500, | ||
417 | .frequency_min = 51000000, | ||
418 | .frequency_max = 858000000, | ||
419 | .caps = FE_CAN_QAM_16 | | ||
420 | FE_CAN_QAM_32 | | ||
421 | FE_CAN_QAM_64 | | ||
422 | FE_CAN_QAM_128 | | ||
423 | FE_CAN_QAM_256 | | ||
424 | FE_CAN_FEC_AUTO | ||
425 | }, | ||
426 | |||
427 | .release = ves1820_release, | ||
428 | |||
429 | .init = ves1820_init, | ||
430 | .sleep = ves1820_sleep, | ||
431 | |||
432 | .set_frontend = ves1820_set_parameters, | ||
433 | .get_frontend = ves1820_get_frontend, | ||
434 | .get_tune_settings = ves1820_get_tune_settings, | ||
435 | |||
436 | .read_status = ves1820_read_status, | ||
437 | .read_ber = ves1820_read_ber, | ||
438 | .read_signal_strength = ves1820_read_signal_strength, | ||
439 | .read_snr = ves1820_read_snr, | ||
440 | .read_ucblocks = ves1820_read_ucblocks, | ||
441 | }; | ||
442 | |||
443 | module_param(verbose, int, 0644); | ||
444 | MODULE_PARM_DESC(verbose, "print AFC offset after tuning for debugging the PWM setting"); | ||
445 | |||
446 | MODULE_DESCRIPTION("VLSI VES1820 DVB-C Demodulator driver"); | ||
447 | MODULE_AUTHOR("Ralph Metzler, Holger Waechtler"); | ||
448 | MODULE_LICENSE("GPL"); | ||
449 | |||
450 | EXPORT_SYMBOL(ves1820_attach); | ||
diff --git a/drivers/media/dvb/frontends/ves1820.h b/drivers/media/dvb/frontends/ves1820.h new file mode 100644 index 000000000000..355f130b1be8 --- /dev/null +++ b/drivers/media/dvb/frontends/ves1820.h | |||
@@ -0,0 +1,51 @@ | |||
1 | /* | ||
2 | VES1820 - Single Chip Cable Channel Receiver driver module | ||
3 | |||
4 | Copyright (C) 1999 Convergence Integrated Media GmbH <ralph@convergence.de> | ||
5 | |||
6 | This program is free software; you can redistribute it and/or modify | ||
7 | it under the terms of the GNU General Public License as published by | ||
8 | the Free Software Foundation; either version 2 of the License, or | ||
9 | (at your option) any later version. | ||
10 | |||
11 | This program is distributed in the hope that it will be useful, | ||
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | GNU General Public License for more details. | ||
15 | |||
16 | You should have received a copy of the GNU General Public License | ||
17 | along with this program; if not, write to the Free Software | ||
18 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
19 | */ | ||
20 | |||
21 | #ifndef VES1820_H | ||
22 | #define VES1820_H | ||
23 | |||
24 | #include <linux/dvb/frontend.h> | ||
25 | |||
26 | #define VES1820_SELAGC_PWM 0 | ||
27 | #define VES1820_SELAGC_SIGNAMPERR 1 | ||
28 | |||
29 | struct ves1820_config | ||
30 | { | ||
31 | /* the demodulator's i2c address */ | ||
32 | u8 demod_address; | ||
33 | |||
34 | /* value of XIN to use */ | ||
35 | u32 xin; | ||
36 | |||
37 | /* does inversion need inverted? */ | ||
38 | u8 invert:1; | ||
39 | |||
40 | /* SELAGC control */ | ||
41 | u8 selagc:1; | ||
42 | |||
43 | /* PLL maintenance */ | ||
44 | int (*pll_init)(struct dvb_frontend* fe); | ||
45 | int (*pll_set)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params); | ||
46 | }; | ||
47 | |||
48 | extern struct dvb_frontend* ves1820_attach(const struct ves1820_config* config, | ||
49 | struct i2c_adapter* i2c, u8 pwm); | ||
50 | |||
51 | #endif // VES1820_H | ||
diff --git a/drivers/media/dvb/frontends/ves1x93.c b/drivers/media/dvb/frontends/ves1x93.c new file mode 100644 index 000000000000..edcad283aa86 --- /dev/null +++ b/drivers/media/dvb/frontends/ves1x93.c | |||
@@ -0,0 +1,545 @@ | |||
1 | /* | ||
2 | Driver for VES1893 and VES1993 QPSK Demodulators | ||
3 | |||
4 | Copyright (C) 1999 Convergence Integrated Media GmbH <ralph@convergence.de> | ||
5 | Copyright (C) 2001 Ronny Strutz <3des@elitedvb.de> | ||
6 | Copyright (C) 2002 Dennis Noermann <dennis.noermann@noernet.de> | ||
7 | Copyright (C) 2002-2003 Andreas Oberritter <obi@linuxtv.org> | ||
8 | |||
9 | This program is free software; you can redistribute it and/or modify | ||
10 | it under the terms of the GNU General Public License as published by | ||
11 | the Free Software Foundation; either version 2 of the License, or | ||
12 | (at your option) any later version. | ||
13 | |||
14 | This program is distributed in the hope that it will be useful, | ||
15 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
16 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
17 | |||
18 | GNU General Public License for more details. | ||
19 | |||
20 | You should have received a copy of the GNU General Public License | ||
21 | along with this program; if not, write to the Free Software | ||
22 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
23 | |||
24 | */ | ||
25 | |||
26 | #include <linux/kernel.h> | ||
27 | #include <linux/module.h> | ||
28 | #include <linux/init.h> | ||
29 | #include <linux/string.h> | ||
30 | #include <linux/slab.h> | ||
31 | #include <linux/delay.h> | ||
32 | |||
33 | #include "dvb_frontend.h" | ||
34 | #include "ves1x93.h" | ||
35 | |||
36 | |||
37 | struct ves1x93_state { | ||
38 | struct i2c_adapter* i2c; | ||
39 | struct dvb_frontend_ops ops; | ||
40 | /* configuration settings */ | ||
41 | const struct ves1x93_config* config; | ||
42 | struct dvb_frontend frontend; | ||
43 | |||
44 | /* previous uncorrected block counter */ | ||
45 | fe_spectral_inversion_t inversion; | ||
46 | u8 *init_1x93_tab; | ||
47 | u8 *init_1x93_wtab; | ||
48 | u8 tab_size; | ||
49 | u8 demod_type; | ||
50 | }; | ||
51 | |||
52 | static int debug = 0; | ||
53 | #define dprintk if (debug) printk | ||
54 | |||
55 | #define DEMOD_VES1893 0 | ||
56 | #define DEMOD_VES1993 1 | ||
57 | |||
58 | static u8 init_1893_tab [] = { | ||
59 | 0x01, 0xa4, 0x35, 0x80, 0x2a, 0x0b, 0x55, 0xc4, | ||
60 | 0x09, 0x69, 0x00, 0x86, 0x4c, 0x28, 0x7f, 0x00, | ||
61 | 0x00, 0x81, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
62 | 0x80, 0x00, 0x21, 0xb0, 0x14, 0x00, 0xdc, 0x00, | ||
63 | 0x81, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
64 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
65 | 0x00, 0x55, 0x00, 0x00, 0x7f, 0x00 | ||
66 | }; | ||
67 | |||
68 | static u8 init_1993_tab [] = { | ||
69 | 0x00, 0x9c, 0x35, 0x80, 0x6a, 0x09, 0x72, 0x8c, | ||
70 | 0x09, 0x6b, 0x00, 0x00, 0x4c, 0x08, 0x00, 0x00, | ||
71 | 0x00, 0x81, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
72 | 0x80, 0x40, 0x21, 0xb0, 0x00, 0x00, 0x00, 0x10, | ||
73 | 0x81, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
74 | 0x00, 0x00, 0x80, 0x80, 0x00, 0x00, 0x00, 0x00, | ||
75 | 0x00, 0x55, 0x03, 0x00, 0x00, 0x00, 0x00, 0x03, | ||
76 | 0x00, 0x00, 0x0e, 0x80, 0x00 | ||
77 | }; | ||
78 | |||
79 | static u8 init_1893_wtab[] = | ||
80 | { | ||
81 | 1,1,1,1,1,1,1,1, 1,1,0,0,1,1,0,0, | ||
82 | 0,1,0,0,0,0,0,0, 1,0,1,1,0,0,0,1, | ||
83 | 1,1,1,0,0,0,0,0, 0,0,1,1,0,0,0,0, | ||
84 | 1,1,1,0,1,1 | ||
85 | }; | ||
86 | |||
87 | static u8 init_1993_wtab[] = | ||
88 | { | ||
89 | 1,1,1,1,1,1,1,1, 1,1,0,0,1,1,0,0, | ||
90 | 0,1,0,0,0,0,0,0, 1,1,1,1,0,0,0,1, | ||
91 | 1,1,1,0,0,0,0,0, 0,0,1,1,0,0,0,0, | ||
92 | 1,1,1,0,1,1,1,1, 1,1,1,1,1 | ||
93 | }; | ||
94 | |||
95 | static int ves1x93_writereg (struct ves1x93_state* state, u8 reg, u8 data) | ||
96 | { | ||
97 | u8 buf [] = { 0x00, reg, data }; | ||
98 | struct i2c_msg msg = { .addr = state->config->demod_address, .flags = 0, .buf = buf, .len = 3 }; | ||
99 | int err; | ||
100 | |||
101 | if ((err = i2c_transfer (state->i2c, &msg, 1)) != 1) { | ||
102 | dprintk ("%s: writereg error (err == %i, reg == 0x%02x, data == 0x%02x)\n", __FUNCTION__, err, reg, data); | ||
103 | return -EREMOTEIO; | ||
104 | } | ||
105 | |||
106 | return 0; | ||
107 | } | ||
108 | |||
109 | static u8 ves1x93_readreg (struct ves1x93_state* state, u8 reg) | ||
110 | { | ||
111 | int ret; | ||
112 | u8 b0 [] = { 0x00, reg }; | ||
113 | u8 b1 [] = { 0 }; | ||
114 | struct i2c_msg msg [] = { { .addr = state->config->demod_address, .flags = 0, .buf = b0, .len = 2 }, | ||
115 | { .addr = state->config->demod_address, .flags = I2C_M_RD, .buf = b1, .len = 1 } }; | ||
116 | |||
117 | ret = i2c_transfer (state->i2c, msg, 2); | ||
118 | |||
119 | if (ret != 2) return ret; | ||
120 | |||
121 | return b1[0]; | ||
122 | } | ||
123 | |||
124 | static int ves1x93_clr_bit (struct ves1x93_state* state) | ||
125 | { | ||
126 | msleep(10); | ||
127 | ves1x93_writereg (state, 0, state->init_1x93_tab[0] & 0xfe); | ||
128 | ves1x93_writereg (state, 0, state->init_1x93_tab[0]); | ||
129 | msleep(50); | ||
130 | return 0; | ||
131 | } | ||
132 | |||
133 | static int ves1x93_set_inversion (struct ves1x93_state* state, fe_spectral_inversion_t inversion) | ||
134 | { | ||
135 | u8 val; | ||
136 | |||
137 | /* | ||
138 | * inversion on/off are interchanged because i and q seem to | ||
139 | * be swapped on the hardware | ||
140 | */ | ||
141 | |||
142 | switch (inversion) { | ||
143 | case INVERSION_OFF: | ||
144 | val = 0xc0; | ||
145 | break; | ||
146 | case INVERSION_ON: | ||
147 | val = 0x80; | ||
148 | break; | ||
149 | case INVERSION_AUTO: | ||
150 | val = 0x00; | ||
151 | break; | ||
152 | default: | ||
153 | return -EINVAL; | ||
154 | } | ||
155 | |||
156 | return ves1x93_writereg (state, 0x0c, (state->init_1x93_tab[0x0c] & 0x3f) | val); | ||
157 | } | ||
158 | |||
159 | static int ves1x93_set_fec (struct ves1x93_state* state, fe_code_rate_t fec) | ||
160 | { | ||
161 | if (fec == FEC_AUTO) | ||
162 | return ves1x93_writereg (state, 0x0d, 0x08); | ||
163 | else if (fec < FEC_1_2 || fec > FEC_8_9) | ||
164 | return -EINVAL; | ||
165 | else | ||
166 | return ves1x93_writereg (state, 0x0d, fec - FEC_1_2); | ||
167 | } | ||
168 | |||
169 | static fe_code_rate_t ves1x93_get_fec (struct ves1x93_state* state) | ||
170 | { | ||
171 | return FEC_1_2 + ((ves1x93_readreg (state, 0x0d) >> 4) & 0x7); | ||
172 | } | ||
173 | |||
174 | static int ves1x93_set_symbolrate (struct ves1x93_state* state, u32 srate) | ||
175 | { | ||
176 | u32 BDR; | ||
177 | u32 ratio; | ||
178 | u8 ADCONF, FCONF, FNR, AGCR; | ||
179 | u32 BDRI; | ||
180 | u32 tmp; | ||
181 | u32 FIN; | ||
182 | |||
183 | dprintk("%s: srate == %d\n", __FUNCTION__, (unsigned int) srate); | ||
184 | |||
185 | if (srate > state->config->xin/2) | ||
186 | srate = state->config->xin/2; | ||
187 | |||
188 | if (srate < 500000) | ||
189 | srate = 500000; | ||
190 | |||
191 | #define MUL (1UL<<26) | ||
192 | |||
193 | FIN = (state->config->xin + 6000) >> 4; | ||
194 | |||
195 | tmp = srate << 6; | ||
196 | ratio = tmp / FIN; | ||
197 | |||
198 | tmp = (tmp % FIN) << 8; | ||
199 | ratio = (ratio << 8) + tmp / FIN; | ||
200 | |||
201 | tmp = (tmp % FIN) << 8; | ||
202 | ratio = (ratio << 8) + tmp / FIN; | ||
203 | |||
204 | FNR = 0xff; | ||
205 | |||
206 | if (ratio < MUL/3) FNR = 0; | ||
207 | if (ratio < (MUL*11)/50) FNR = 1; | ||
208 | if (ratio < MUL/6) FNR = 2; | ||
209 | if (ratio < MUL/9) FNR = 3; | ||
210 | if (ratio < MUL/12) FNR = 4; | ||
211 | if (ratio < (MUL*11)/200) FNR = 5; | ||
212 | if (ratio < MUL/24) FNR = 6; | ||
213 | if (ratio < (MUL*27)/1000) FNR = 7; | ||
214 | if (ratio < MUL/48) FNR = 8; | ||
215 | if (ratio < (MUL*137)/10000) FNR = 9; | ||
216 | |||
217 | if (FNR == 0xff) { | ||
218 | ADCONF = 0x89; | ||
219 | FCONF = 0x80; | ||
220 | FNR = 0; | ||
221 | } else { | ||
222 | ADCONF = 0x81; | ||
223 | FCONF = 0x88 | (FNR >> 1) | ((FNR & 0x01) << 5); | ||
224 | /*FCONF = 0x80 | ((FNR & 0x01) << 5) | (((FNR > 1) & 0x03) << 3) | ((FNR >> 1) & 0x07);*/ | ||
225 | } | ||
226 | |||
227 | BDR = (( (ratio << (FNR >> 1)) >> 4) + 1) >> 1; | ||
228 | BDRI = ( ((FIN << 8) / ((srate << (FNR >> 1)) >> 2)) + 1) >> 1; | ||
229 | |||
230 | dprintk("FNR= %d\n", FNR); | ||
231 | dprintk("ratio= %08x\n", (unsigned int) ratio); | ||
232 | dprintk("BDR= %08x\n", (unsigned int) BDR); | ||
233 | dprintk("BDRI= %02x\n", (unsigned int) BDRI); | ||
234 | |||
235 | if (BDRI > 0xff) | ||
236 | BDRI = 0xff; | ||
237 | |||
238 | ves1x93_writereg (state, 0x06, 0xff & BDR); | ||
239 | ves1x93_writereg (state, 0x07, 0xff & (BDR >> 8)); | ||
240 | ves1x93_writereg (state, 0x08, 0x0f & (BDR >> 16)); | ||
241 | |||
242 | ves1x93_writereg (state, 0x09, BDRI); | ||
243 | ves1x93_writereg (state, 0x20, ADCONF); | ||
244 | ves1x93_writereg (state, 0x21, FCONF); | ||
245 | |||
246 | AGCR = state->init_1x93_tab[0x05]; | ||
247 | if (state->config->invert_pwm) | ||
248 | AGCR |= 0x20; | ||
249 | |||
250 | if (srate < 6000000) | ||
251 | AGCR |= 0x80; | ||
252 | else | ||
253 | AGCR &= ~0x80; | ||
254 | |||
255 | ves1x93_writereg (state, 0x05, AGCR); | ||
256 | |||
257 | /* ves1993 hates this, will lose lock */ | ||
258 | if (state->demod_type != DEMOD_VES1993) | ||
259 | ves1x93_clr_bit (state); | ||
260 | |||
261 | return 0; | ||
262 | } | ||
263 | |||
264 | static int ves1x93_init (struct dvb_frontend* fe) | ||
265 | { | ||
266 | struct ves1x93_state* state = (struct ves1x93_state*) fe->demodulator_priv; | ||
267 | int i; | ||
268 | int val; | ||
269 | |||
270 | dprintk("%s: init chip\n", __FUNCTION__); | ||
271 | |||
272 | for (i = 0; i < state->tab_size; i++) { | ||
273 | if (state->init_1x93_wtab[i]) { | ||
274 | val = state->init_1x93_tab[i]; | ||
275 | |||
276 | if (state->config->invert_pwm && (i == 0x05)) val |= 0x20; /* invert PWM */ | ||
277 | ves1x93_writereg (state, i, val); | ||
278 | } | ||
279 | } | ||
280 | |||
281 | if (state->config->pll_init) { | ||
282 | ves1x93_writereg(state, 0x00, 0x11); | ||
283 | state->config->pll_init(fe); | ||
284 | ves1x93_writereg(state, 0x00, 0x01); | ||
285 | } | ||
286 | |||
287 | return 0; | ||
288 | } | ||
289 | |||
290 | static int ves1x93_set_voltage (struct dvb_frontend* fe, fe_sec_voltage_t voltage) | ||
291 | { | ||
292 | struct ves1x93_state* state = (struct ves1x93_state*) fe->demodulator_priv; | ||
293 | |||
294 | switch (voltage) { | ||
295 | case SEC_VOLTAGE_13: | ||
296 | return ves1x93_writereg (state, 0x1f, 0x20); | ||
297 | case SEC_VOLTAGE_18: | ||
298 | return ves1x93_writereg (state, 0x1f, 0x30); | ||
299 | case SEC_VOLTAGE_OFF: | ||
300 | return ves1x93_writereg (state, 0x1f, 0x00); | ||
301 | default: | ||
302 | return -EINVAL; | ||
303 | } | ||
304 | } | ||
305 | |||
306 | static int ves1x93_read_status(struct dvb_frontend* fe, fe_status_t* status) | ||
307 | { | ||
308 | struct ves1x93_state* state = (struct ves1x93_state*) fe->demodulator_priv; | ||
309 | |||
310 | u8 sync = ves1x93_readreg (state, 0x0e); | ||
311 | |||
312 | /* | ||
313 | * The ves1893 sometimes returns sync values that make no sense, | ||
314 | * because, e.g., the SIGNAL bit is 0, while some of the higher | ||
315 | * bits are 1 (and how can there be a CARRIER w/o a SIGNAL?). | ||
316 | * Tests showed that the the VITERBI and SYNC bits are returned | ||
317 | * reliably, while the SIGNAL and CARRIER bits ar sometimes wrong. | ||
318 | * If such a case occurs, we read the value again, until we get a | ||
319 | * valid value. | ||
320 | */ | ||
321 | int maxtry = 10; /* just for safety - let's not get stuck here */ | ||
322 | while ((sync & 0x03) != 0x03 && (sync & 0x0c) && maxtry--) { | ||
323 | msleep(10); | ||
324 | sync = ves1x93_readreg (state, 0x0e); | ||
325 | } | ||
326 | |||
327 | *status = 0; | ||
328 | |||
329 | if (sync & 1) | ||
330 | *status |= FE_HAS_SIGNAL; | ||
331 | |||
332 | if (sync & 2) | ||
333 | *status |= FE_HAS_CARRIER; | ||
334 | |||
335 | if (sync & 4) | ||
336 | *status |= FE_HAS_VITERBI; | ||
337 | |||
338 | if (sync & 8) | ||
339 | *status |= FE_HAS_SYNC; | ||
340 | |||
341 | if ((sync & 0x1f) == 0x1f) | ||
342 | *status |= FE_HAS_LOCK; | ||
343 | |||
344 | return 0; | ||
345 | } | ||
346 | |||
347 | static int ves1x93_read_ber(struct dvb_frontend* fe, u32* ber) | ||
348 | { | ||
349 | struct ves1x93_state* state = (struct ves1x93_state*) fe->demodulator_priv; | ||
350 | |||
351 | *ber = ves1x93_readreg (state, 0x15); | ||
352 | *ber |= (ves1x93_readreg (state, 0x16) << 8); | ||
353 | *ber |= ((ves1x93_readreg (state, 0x17) & 0x0F) << 16); | ||
354 | *ber *= 10; | ||
355 | |||
356 | return 0; | ||
357 | } | ||
358 | |||
359 | static int ves1x93_read_signal_strength(struct dvb_frontend* fe, u16* strength) | ||
360 | { | ||
361 | struct ves1x93_state* state = (struct ves1x93_state*) fe->demodulator_priv; | ||
362 | |||
363 | u8 signal = ~ves1x93_readreg (state, 0x0b); | ||
364 | *strength = (signal << 8) | signal; | ||
365 | |||
366 | return 0; | ||
367 | } | ||
368 | |||
369 | static int ves1x93_read_snr(struct dvb_frontend* fe, u16* snr) | ||
370 | { | ||
371 | struct ves1x93_state* state = (struct ves1x93_state*) fe->demodulator_priv; | ||
372 | |||
373 | u8 _snr = ~ves1x93_readreg (state, 0x1c); | ||
374 | *snr = (_snr << 8) | _snr; | ||
375 | |||
376 | return 0; | ||
377 | } | ||
378 | |||
379 | static int ves1x93_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks) | ||
380 | { | ||
381 | struct ves1x93_state* state = (struct ves1x93_state*) fe->demodulator_priv; | ||
382 | |||
383 | *ucblocks = ves1x93_readreg (state, 0x18) & 0x7f; | ||
384 | |||
385 | if (*ucblocks == 0x7f) | ||
386 | *ucblocks = 0xffffffff; /* counter overflow... */ | ||
387 | |||
388 | ves1x93_writereg (state, 0x18, 0x00); /* reset the counter */ | ||
389 | ves1x93_writereg (state, 0x18, 0x80); /* dto. */ | ||
390 | |||
391 | return 0; | ||
392 | } | ||
393 | |||
394 | static int ves1x93_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p) | ||
395 | { | ||
396 | struct ves1x93_state* state = (struct ves1x93_state*) fe->demodulator_priv; | ||
397 | |||
398 | ves1x93_writereg(state, 0x00, 0x11); | ||
399 | state->config->pll_set(fe, p); | ||
400 | ves1x93_writereg(state, 0x00, 0x01); | ||
401 | ves1x93_set_inversion (state, p->inversion); | ||
402 | ves1x93_set_fec (state, p->u.qpsk.fec_inner); | ||
403 | ves1x93_set_symbolrate (state, p->u.qpsk.symbol_rate); | ||
404 | state->inversion = p->inversion; | ||
405 | |||
406 | return 0; | ||
407 | } | ||
408 | |||
409 | static int ves1x93_get_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p) | ||
410 | { | ||
411 | struct ves1x93_state* state = (struct ves1x93_state*) fe->demodulator_priv; | ||
412 | int afc; | ||
413 | |||
414 | afc = ((int)((char)(ves1x93_readreg (state, 0x0a) << 1)))/2; | ||
415 | afc = (afc * (int)(p->u.qpsk.symbol_rate/1000/8))/16; | ||
416 | |||
417 | p->frequency -= afc; | ||
418 | |||
419 | /* | ||
420 | * inversion indicator is only valid | ||
421 | * if auto inversion was used | ||
422 | */ | ||
423 | if (state->inversion == INVERSION_AUTO) | ||
424 | p->inversion = (ves1x93_readreg (state, 0x0f) & 2) ? | ||
425 | INVERSION_OFF : INVERSION_ON; | ||
426 | p->u.qpsk.fec_inner = ves1x93_get_fec (state); | ||
427 | /* XXX FIXME: timing offset !! */ | ||
428 | |||
429 | return 0; | ||
430 | } | ||
431 | |||
432 | static int ves1x93_sleep(struct dvb_frontend* fe) | ||
433 | { | ||
434 | struct ves1x93_state* state = (struct ves1x93_state*) fe->demodulator_priv; | ||
435 | |||
436 | return ves1x93_writereg (state, 0x00, 0x08); | ||
437 | } | ||
438 | |||
439 | static void ves1x93_release(struct dvb_frontend* fe) | ||
440 | { | ||
441 | struct ves1x93_state* state = (struct ves1x93_state*) fe->demodulator_priv; | ||
442 | kfree(state); | ||
443 | } | ||
444 | |||
445 | static struct dvb_frontend_ops ves1x93_ops; | ||
446 | |||
447 | struct dvb_frontend* ves1x93_attach(const struct ves1x93_config* config, | ||
448 | struct i2c_adapter* i2c) | ||
449 | { | ||
450 | struct ves1x93_state* state = NULL; | ||
451 | u8 identity; | ||
452 | |||
453 | /* allocate memory for the internal state */ | ||
454 | state = (struct ves1x93_state*) kmalloc(sizeof(struct ves1x93_state), GFP_KERNEL); | ||
455 | if (state == NULL) goto error; | ||
456 | |||
457 | /* setup the state */ | ||
458 | state->config = config; | ||
459 | state->i2c = i2c; | ||
460 | memcpy(&state->ops, &ves1x93_ops, sizeof(struct dvb_frontend_ops)); | ||
461 | state->inversion = INVERSION_OFF; | ||
462 | |||
463 | /* check if the demod is there + identify it */ | ||
464 | identity = ves1x93_readreg(state, 0x1e); | ||
465 | switch (identity) { | ||
466 | case 0xdc: /* VES1893A rev1 */ | ||
467 | printk("ves1x93: Detected ves1893a rev1\n"); | ||
468 | state->demod_type = DEMOD_VES1893; | ||
469 | state->init_1x93_tab = init_1893_tab; | ||
470 | state->init_1x93_wtab = init_1893_wtab; | ||
471 | state->tab_size = sizeof(init_1893_tab); | ||
472 | break; | ||
473 | |||
474 | case 0xdd: /* VES1893A rev2 */ | ||
475 | printk("ves1x93: Detected ves1893a rev2\n"); | ||
476 | state->demod_type = DEMOD_VES1893; | ||
477 | state->init_1x93_tab = init_1893_tab; | ||
478 | state->init_1x93_wtab = init_1893_wtab; | ||
479 | state->tab_size = sizeof(init_1893_tab); | ||
480 | break; | ||
481 | |||
482 | case 0xde: /* VES1993 */ | ||
483 | printk("ves1x93: Detected ves1993\n"); | ||
484 | state->demod_type = DEMOD_VES1993; | ||
485 | state->init_1x93_tab = init_1993_tab; | ||
486 | state->init_1x93_wtab = init_1993_wtab; | ||
487 | state->tab_size = sizeof(init_1993_tab); | ||
488 | break; | ||
489 | |||
490 | default: | ||
491 | goto error; | ||
492 | } | ||
493 | |||
494 | /* create dvb_frontend */ | ||
495 | state->frontend.ops = &state->ops; | ||
496 | state->frontend.demodulator_priv = state; | ||
497 | return &state->frontend; | ||
498 | |||
499 | error: | ||
500 | kfree(state); | ||
501 | return NULL; | ||
502 | } | ||
503 | |||
504 | static struct dvb_frontend_ops ves1x93_ops = { | ||
505 | |||
506 | .info = { | ||
507 | .name = "VLSI VES1x93 DVB-S", | ||
508 | .type = FE_QPSK, | ||
509 | .frequency_min = 950000, | ||
510 | .frequency_max = 2150000, | ||
511 | .frequency_stepsize = 125, /* kHz for QPSK frontends */ | ||
512 | .frequency_tolerance = 29500, | ||
513 | .symbol_rate_min = 1000000, | ||
514 | .symbol_rate_max = 45000000, | ||
515 | /* .symbol_rate_tolerance = ???,*/ | ||
516 | .caps = FE_CAN_INVERSION_AUTO | | ||
517 | FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | | ||
518 | FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO | | ||
519 | FE_CAN_QPSK | ||
520 | }, | ||
521 | |||
522 | .release = ves1x93_release, | ||
523 | |||
524 | .init = ves1x93_init, | ||
525 | .sleep = ves1x93_sleep, | ||
526 | |||
527 | .set_frontend = ves1x93_set_frontend, | ||
528 | .get_frontend = ves1x93_get_frontend, | ||
529 | |||
530 | .read_status = ves1x93_read_status, | ||
531 | .read_ber = ves1x93_read_ber, | ||
532 | .read_signal_strength = ves1x93_read_signal_strength, | ||
533 | .read_snr = ves1x93_read_snr, | ||
534 | .read_ucblocks = ves1x93_read_ucblocks, | ||
535 | |||
536 | .set_voltage = ves1x93_set_voltage, | ||
537 | }; | ||
538 | |||
539 | module_param(debug, int, 0644); | ||
540 | |||
541 | MODULE_DESCRIPTION("VLSI VES1x93 DVB-S Demodulator driver"); | ||
542 | MODULE_AUTHOR("Ralph Metzler"); | ||
543 | MODULE_LICENSE("GPL"); | ||
544 | |||
545 | EXPORT_SYMBOL(ves1x93_attach); | ||
diff --git a/drivers/media/dvb/frontends/ves1x93.h b/drivers/media/dvb/frontends/ves1x93.h new file mode 100644 index 000000000000..1627e37c57a4 --- /dev/null +++ b/drivers/media/dvb/frontends/ves1x93.h | |||
@@ -0,0 +1,50 @@ | |||
1 | /* | ||
2 | Driver for VES1893 and VES1993 QPSK Demodulators | ||
3 | |||
4 | Copyright (C) 1999 Convergence Integrated Media GmbH <ralph@convergence.de> | ||
5 | Copyright (C) 2001 Ronny Strutz <3des@elitedvb.de> | ||
6 | Copyright (C) 2002 Dennis Noermann <dennis.noermann@noernet.de> | ||
7 | Copyright (C) 2002-2003 Andreas Oberritter <obi@linuxtv.org> | ||
8 | |||
9 | This program is free software; you can redistribute it and/or modify | ||
10 | it under the terms of the GNU General Public License as published by | ||
11 | the Free Software Foundation; either version 2 of the License, or | ||
12 | (at your option) any later version. | ||
13 | |||
14 | This program is distributed in the hope that it will be useful, | ||
15 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
16 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
17 | |||
18 | GNU General Public License for more details. | ||
19 | |||
20 | You should have received a copy of the GNU General Public License | ||
21 | along with this program; if not, write to the Free Software | ||
22 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
23 | |||
24 | */ | ||
25 | |||
26 | #ifndef VES1X93_H | ||
27 | #define VES1X93_H | ||
28 | |||
29 | #include <linux/dvb/frontend.h> | ||
30 | |||
31 | struct ves1x93_config | ||
32 | { | ||
33 | /* the demodulator's i2c address */ | ||
34 | u8 demod_address; | ||
35 | |||
36 | /* value of XIN to use */ | ||
37 | u32 xin; | ||
38 | |||
39 | /* should PWM be inverted? */ | ||
40 | u8 invert_pwm:1; | ||
41 | |||
42 | /* PLL maintenance */ | ||
43 | int (*pll_init)(struct dvb_frontend* fe); | ||
44 | int (*pll_set)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params); | ||
45 | }; | ||
46 | |||
47 | extern struct dvb_frontend* ves1x93_attach(const struct ves1x93_config* config, | ||
48 | struct i2c_adapter* i2c); | ||
49 | |||
50 | #endif // VES1X93_H | ||