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