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/tda1004x.c |
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/tda1004x.c')
-rw-r--r-- | drivers/media/dvb/frontends/tda1004x.c | 1206 |
1 files changed, 1206 insertions, 0 deletions
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); | ||