nxt2k.c revision 1.1 1 /* $NetBSD: nxt2k.c,v 1.1 2011/07/11 00:30:23 jakllsch Exp $ */
2
3 /*
4 * Copyright (c) 2008, 2011 Jonathan A. Kollasch
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
18 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
20 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
21 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
22 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
23 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
24 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
25 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
26 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29 #include <sys/cdefs.h>
30 __KERNEL_RCSID(0, "$NetBSD: nxt2k.c,v 1.1 2011/07/11 00:30:23 jakllsch Exp $");
31
32 #include <sys/param.h>
33 #include <sys/kernel.h>
34 #include <sys/systm.h>
35 #include <sys/device.h>
36 #include <sys/kmem.h>
37 #include <sys/condvar.h>
38 #include <sys/mutex.h>
39
40 #include <dev/firmload.h>
41
42 #include <dev/i2c/nxt2kvar.h>
43
44 struct nxt2k {
45 device_t parent;
46 i2c_tag_t tag;
47 i2c_addr_t addr;
48 kcondvar_t cv;
49 kmutex_t mtx;
50 bool loaded; /* firmware is loaded? */
51 };
52
53 static int nxt2k_init(struct nxt2k *);
54
55 static int nxt2k_writedata(struct nxt2k *, uint8_t, uint8_t *, size_t);
56 static int nxt2k_readdata(struct nxt2k *, uint8_t, uint8_t *, size_t);
57 static int nxt2k_writereg(struct nxt2k *, uint8_t, uint8_t *, size_t);
58 static int nxt2k_readreg(struct nxt2k*, uint8_t, uint8_t *, size_t);
59
60 static int nxt2k4_init(struct nxt2k *);
61 static bool nxt2k4_load_firmware(struct nxt2k *);
62 static void nxt2k4_mc_init(struct nxt2k *);
63 static void nxt2k_mc_start(struct nxt2k *);
64 static void nxt2k_mc_stop(struct nxt2k *);
65 static void nxt2k_agc_reset(struct nxt2k *);
66 static uint16_t nxt2k_crc_ccit(uint16_t, uint8_t);
67
68 static int
69 nxt2k_writedata(struct nxt2k *nxt, uint8_t reg, uint8_t *data, size_t len)
70 {
71 uint8_t buffer[384];
72 int error;
73
74 KASSERT((len + 1) <= 384);
75
76 if (iic_acquire_bus(nxt->tag, I2C_F_POLL) != 0)
77 return false;
78
79 buffer[0] = reg;
80 memcpy(&buffer[1], data, len);
81
82 error = iic_exec(nxt->tag, I2C_OP_WRITE_WITH_STOP, nxt->addr,
83 buffer, len + 1, NULL, 0, I2C_F_POLL);
84
85 iic_release_bus(nxt->tag, I2C_F_POLL);
86
87 return error;
88 }
89
90 static int
91 nxt2k_readdata(struct nxt2k *nxt, uint8_t reg, uint8_t *data, size_t len)
92 {
93 int error;
94
95 if (iic_acquire_bus(nxt->tag, I2C_F_POLL) != 0)
96 return false;
97
98 error = iic_exec(nxt->tag, I2C_OP_READ_WITH_STOP, nxt->addr,
99 ®, 1, data, len, I2C_F_POLL);
100
101 iic_release_bus(nxt->tag, I2C_F_POLL);
102
103 return error;
104 }
105
106 static int
107 nxt2k_writereg(struct nxt2k *nxt, uint8_t reg, uint8_t *data, size_t len)
108 {
109 uint8_t attr, len2, buf;
110
111 nxt2k_writedata(nxt, 0x35, ®, 1);
112
113 nxt2k_writedata(nxt, 0x36, data, len);
114
115 attr = 0x02;
116 if (reg & 0x80) {
117 attr = attr << 1;
118 if (reg & 0x04)
119 attr = attr >> 1;
120 }
121 len2 = ((attr << 4) | 0x10) | len;
122 buf = 0x80;
123
124 nxt2k_writedata(nxt, 0x34, &len2, 1);
125
126 nxt2k_writedata(nxt, 0x21, &buf, 1);
127
128 nxt2k_readdata(nxt, 0x21, &buf, 1);
129
130 if (buf == 0)
131 return 0;
132
133 return -1;
134 }
135
136 static int
137 nxt2k_readreg(struct nxt2k *nxt, uint8_t reg, uint8_t *data, size_t len)
138 {
139 uint8_t buf, len2, attr;
140 int i;
141
142 nxt2k_writedata(nxt, 0x35, ®, 1);
143
144 attr = 0x02;
145 if (reg & 0x80) {
146 attr = attr << 1;
147 if (reg & 0x04)
148 attr = attr >> 1;
149 }
150
151 len2 = (attr << 4) | len;
152 nxt2k_writedata(nxt, 0x34, &len2, 1);
153
154 buf = 0x80;
155 nxt2k_writedata(nxt, 0x21, &buf, 1);
156
157 for(i = 0; i < len; i++) {
158 nxt2k_readdata(nxt, 0x36+i, &data[i], 1);
159 }
160
161 return 0;
162 }
163
164 static void
165 nxt2k_agc_reset(struct nxt2k *nxt)
166 {
167 uint8_t byte;
168 nxt2k_readreg(nxt, 0x08, &byte, 1);
169 byte = 0x08;
170 nxt2k_writereg(nxt, 0x08, &byte, 1);
171 byte = 0x00;
172 nxt2k_writereg(nxt, 0x08, &byte, 1);
173 return;
174 }
175
176 static void
177 nxt2k_mc_stop(struct nxt2k *nxt)
178 {
179 int counter;
180 uint8_t stopval, buf;
181
182 /* 2k4 */
183 stopval = 0x10;
184
185 buf = 0x80;
186 nxt2k_writedata(nxt, 0x22, &buf, 1);
187
188 for(counter = 0; counter < 20; counter++) {
189 nxt2k_readdata(nxt, 0x31, &buf, 1);
190 if (buf & stopval)
191 return;
192 mutex_enter(&nxt->mtx);
193 cv_timedwait(&nxt->cv, &nxt->mtx, mstohz(10));
194 mutex_exit(&nxt->mtx);
195 }
196
197 printf("%s timeout\n", __func__);
198
199 return;
200 }
201
202 static void
203 nxt2k_mc_start(struct nxt2k *nxt)
204 {
205 uint8_t buf;
206
207 buf = 0x00;
208 nxt2k_writedata(nxt, 0x22, &buf, 1);
209 }
210
211 static void
212 nxt2k4_mc_init(struct nxt2k *nxt)
213 {
214 uint8_t byte;
215 uint8_t data[] = {0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF, 0xC0};
216 int counter;
217
218 byte = 0x00;
219 nxt2k_writedata(nxt, 0x2b, &byte, 1);
220 byte = 0x70;
221 nxt2k_writedata(nxt, 0x34, &byte, 1);
222 byte = 0x04;
223 nxt2k_writedata(nxt, 0x35, &byte, 1);
224
225 nxt2k_writedata(nxt, 0x36, data, 9);
226
227 byte = 0x80;
228 nxt2k_writedata(nxt, 0x21, &byte, 1);
229
230 for(counter = 0; counter < 20; counter++) {
231 nxt2k_readdata(nxt, 0x21, &byte, 1);
232 if ( byte == 0 )
233 return;
234 mutex_enter(&nxt->mtx);
235 cv_timedwait(&nxt->cv, &nxt->mtx, mstohz(25));
236 mutex_exit(&nxt->mtx);
237 }
238
239 printf("%s timeout\n", __func__);
240
241 return;
242 }
243
244 /* CRC-CCIT */
245 static uint16_t
246 nxt2k_crc_ccit(uint16_t crc, uint8_t byte)
247 {
248 int i;
249 uint16_t input;
250
251 input = byte << 8;
252
253 for(i = 0; i < 8; i++) {
254 if ((crc ^ input) & 0x8000)
255 crc = (crc << 1) ^ 0x1021;
256 else
257 crc = (crc << 1);
258 input = input << 1;
259 }
260 return crc;
261 }
262
263 static bool
264 nxt2k4_load_firmware(struct nxt2k *nxt)
265 {
266 firmware_handle_t fh;
267 uint8_t *blob;
268 size_t fwsize;
269 size_t position;
270 int error;
271 uint16_t crc;
272
273 error = firmware_open("nxt2k", "dvb-fe-nxt2004.fw", &fh);
274 if (error != 0) {
275 printf("nxt2k firmware_open fail %d\n", error);
276 return 0;
277 }
278
279 fwsize = firmware_get_size(fh);
280 printf("fwsize %zd\n", fwsize);
281 blob = firmware_malloc(fwsize);
282 if ( blob == NULL ) {
283 printf("nxt2k firmware_malloc fail\n");
284 firmware_close(fh);
285 return -1;
286 }
287
288 error = firmware_read(fh, 0, blob, fwsize);
289 if (error != 0) {
290 printf("nxt2k firmware_read fail %d\n", error);
291 firmware_free(blob, fwsize);
292 firmware_close(fh);
293 return -1;
294 }
295
296 /* calculate CRC */
297 crc = 0;
298 for(position = 0; position < fwsize; position++) {
299 crc = nxt2k_crc_ccit(crc, blob[position]);
300 }
301 printf("nxt2k firmware crc is %02x\n", crc);
302
303 uint16_t rambase;
304 uint8_t buf[3];
305
306 rambase = 0x1000;
307
308 /* hold the micro in reset while loading firmware */
309 buf[0] = 0x80;
310 nxt2k_writedata(nxt, 0x2b, buf, 1);
311
312 buf[0] = rambase >> 8;
313 buf[1] = rambase & 0xFF;
314 buf[2] = 0x81;
315 /* write starting address */
316 nxt2k_writedata(nxt, 0x29, buf, 3);
317
318 position = 0;
319
320 size_t xfercnt;
321
322 while ( position < fwsize ) {
323 xfercnt = fwsize - position > 255 ? 255 : fwsize - position;
324 nxt2k_writedata(nxt, 0x2c, &blob[position], xfercnt);
325 position += xfercnt;
326 }
327
328 /* write crc */
329 buf[0] = crc >> 8;
330 buf[1] = crc & 0xFF;
331 nxt2k_writedata(nxt, 0x2c, buf, 2);
332
333 /* do a read to stop things */
334 nxt2k_readdata(nxt, 0x2c, buf, 1);
335
336 /* set transfer mode to complete */
337 buf[0] = 0x80;
338 nxt2k_writedata(nxt, 0x2b, buf, 1);
339
340 firmware_free(blob, fwsize);
341 firmware_close(fh);
342
343 return 1;
344 }
345
346 static int
347 nxt2k4_init(struct nxt2k *nxt)
348 {
349 int success;
350 uint8_t buf[3];
351
352 buf[0] = 0x00;
353 nxt2k_writedata(nxt, 0x1e, buf, 1);
354
355 /* try to load firmware */
356 nxt->loaded = nxt2k4_load_firmware(nxt);
357 if (nxt->loaded == false)
358 return ECANCELED;
359
360 /* ensure transfer is complete */
361 buf[0] = 0x01;
362 nxt2k_writedata(nxt, 0x19, buf, 1);
363
364 nxt2k4_mc_init(nxt);
365 nxt2k_mc_stop(nxt);
366 nxt2k_mc_stop(nxt);
367 nxt2k4_mc_init(nxt);
368 nxt2k_mc_stop(nxt);
369
370 buf[0] = 0xff;
371 nxt2k_writereg(nxt, 0x08, buf, 1);
372 buf[0] = 0x00;
373 nxt2k_writereg(nxt, 0x08, buf, 1);
374
375 buf[0] = 0xD7;
376 nxt2k_writedata(nxt, 0xd7, buf, 1);
377
378 buf[0] = 0x07;
379 buf[1] = 0xfe;
380 nxt2k_writedata(nxt, 0x35, buf, 2);
381 buf[0] = 0x12;
382 nxt2k_writedata(nxt, 0x34, buf, 1);
383 buf[0] = 0x80;
384 nxt2k_writedata(nxt, 0x21, buf, 1);
385
386 buf[0] = 0x21;
387 nxt2k_writedata(nxt, 0x0a, buf, 1);
388
389 buf[0] = 0x01;
390 nxt2k_writereg(nxt, 0x80, buf, 1);
391
392 /* fec mpeg mode */
393 buf[0] = 0x7E;
394 buf[1] = 0x00;
395 nxt2k_writedata(nxt, 0xe9, buf, 2);
396
397 /* mux selection */
398 buf[0] = 0x00;
399 nxt2k_writedata(nxt, 0xcc, buf, 1);
400
401 /* */
402 nxt2k_readreg(nxt, 0x80, buf, 1);
403 buf[0] = 0x00;
404 nxt2k_writereg(nxt, 0x80, buf, 1);
405
406 /* soft reset? */
407 nxt2k_readreg(nxt, 0x08, buf, 1);
408 buf[0] = 0x10;
409 nxt2k_writereg(nxt, 0x08, buf, 1);
410 nxt2k_readreg(nxt, 0x08, buf, 1);
411 buf[0] = 0x00;
412 nxt2k_writereg(nxt, 0x08, buf, 1);
413
414 /* */
415 nxt2k_readreg(nxt, 0x80, buf, 1);
416 buf[0] = 0x01;
417 nxt2k_writereg(nxt, 0x80, buf, 1);
418 buf[0] = 0x70;
419 nxt2k_writereg(nxt, 0x81, buf, 1);
420 buf[0] = 0x31; buf[1] = 0x5E; buf[2] = 0x66;
421 nxt2k_writereg(nxt, 0x82, buf, 3);
422
423 nxt2k_readreg(nxt, 0x88, buf, 1);
424 buf[0] = 0x11;
425 nxt2k_writereg(nxt, 0x88, buf, 1);
426 nxt2k_readreg(nxt, 0x80, buf, 1);
427 buf[0] = 0x40;
428 nxt2k_writereg(nxt, 0x80, buf, 1);
429
430 nxt2k_readdata(nxt, 0x10, buf, 1);
431 buf[0] = 0x10;
432 nxt2k_writedata(nxt, 0x10, buf, 1);
433 nxt2k_readdata(nxt, 0x0a, buf, 1);
434 buf[0] = 0x21;
435 nxt2k_writedata(nxt, 0x0a, buf, 1);
436
437 nxt2k4_mc_init(nxt);
438
439 buf[0] = 0x21;
440 nxt2k_writedata(nxt, 0x0a, buf, 1);
441 buf[0] = 0x7e;
442 nxt2k_writedata(nxt, 0xe9, buf, 1);
443 buf[0] = 0x00;
444 nxt2k_writedata(nxt, 0xea, buf, 1);
445
446 nxt2k_readreg(nxt, 0x80, buf, 1);
447 buf[0] = 0x00;
448 nxt2k_writereg(nxt, 0x80, buf, 1);
449 nxt2k_readreg(nxt, 0x80, buf, 1);
450 buf[0] = 0x00;
451 nxt2k_writereg(nxt, 0x80, buf, 1);
452
453 nxt2k_readreg(nxt, 0x08, buf, 1);
454 buf[0] = 0x10;
455 nxt2k_writereg(nxt, 0x08, buf, 1);
456 nxt2k_readreg(nxt, 0x08, buf, 1);
457 buf[0] = 0x00;
458 nxt2k_writereg(nxt, 0x08, buf, 1);
459
460 nxt2k_readreg(nxt, 0x80, buf, 1);
461 buf[0] = 0x04;
462 nxt2k_writereg(nxt, 0x80, buf, 1);
463 buf[0] = 0x00;
464 nxt2k_writereg(nxt, 0x81, buf, 1);
465 buf[0] = 0x80; buf[1] = 0x00; buf[2] = 0x00;
466 nxt2k_writereg(nxt, 0x82, buf, 3);
467
468 nxt2k_readreg(nxt, 0x88, buf, 1);
469 buf[0] = 0x11;
470 nxt2k_writereg(nxt, 0x88, buf, 1);
471
472 nxt2k_readreg(nxt, 0x80, buf, 1);
473 buf[0] = 0x44;
474 nxt2k_writereg(nxt, 0x80, buf, 1);
475
476 /* init tuner */
477 nxt2k_readdata(nxt, 0x10, buf, 1);
478 buf[0] = 0x12;
479 nxt2k_writedata(nxt, 0x10, buf,1);
480 buf[0] = 0x04;
481 nxt2k_writedata(nxt, 0x13, buf,1);
482 buf[0] = 0x00;
483 nxt2k_writedata(nxt, 0x16, buf,1);
484 buf[0] = 0x04;
485 nxt2k_writedata(nxt, 0x14, buf,1);
486 buf[0] = 0x00;
487 nxt2k_writedata(nxt, 0x14, buf,1);
488 nxt2k_writedata(nxt, 0x17, buf,1);
489 nxt2k_writedata(nxt, 0x14, buf,1);
490 nxt2k_writedata(nxt, 0x17, buf,1);
491
492 success = 1;
493 return success;
494 }
495
496 uint16_t
497 nxt2k_get_signal(struct nxt2k *nxt)
498 {
499 uint16_t temp;
500 uint8_t b[2];
501
502 b[0] = 0x00;
503 nxt2k_writedata(nxt, 0xa1, b, 1);
504
505 nxt2k_readreg(nxt, 0xa6, b, 2);
506
507 temp = (b[0] << 8) | b[1];
508
509 printf("a6: %04hx\n", temp);
510
511 return 0x7fff - temp * 16;
512 }
513
514 uint16_t
515 nxt2k_get_snr(struct nxt2k *nxt)
516 {
517 uint32_t tsnr;
518 uint16_t temp, temp2;
519 uint8_t b[2];
520
521 b[0] = 0x00;
522 nxt2k_writedata(nxt, 0xa1, b, 1);
523
524 nxt2k_readreg(nxt, 0xa6, b, 2);
525
526 temp = (b[0] << 8) | b[1];
527
528 temp2 = 0x7fff - temp;
529
530 printf("snr temp2: %04hx\n", temp2);
531
532 if (temp2 > 0x7f00)
533 tsnr = 1000*24+(1000*(30-24)*(temp2-0x7f00)/(0x7fff-0x7f00));
534 else if ( temp2 > 0x7ec0)
535 tsnr = 1000*18+(1000*(24-18)*(temp2-0x7ec0)/(0x7f00-0x7ec0));
536 else if ( temp2 > 0x7c00)
537 tsnr = 1000*12+(1000*(18-12)*(temp2-0x7c00)/(0x7ec0-0x7c00));
538 else
539 tsnr = 1000*0+(1000*(12-0)*(temp2-0)/(0x7c00-0));
540
541 printf("snr tsnr: %08x\n", tsnr);
542
543 return ((tsnr * 0xffff)/32000);
544 }
545
546 fe_status_t
547 nxt2k_get_dtv_status(struct nxt2k *nxt)
548 {
549 uint8_t reg;
550 fe_status_t status = 0;
551
552 nxt2k_readdata(nxt, 0x31, ®, 1);
553 if (reg & 0x20) {
554 status = FE_HAS_SIGNAL | FE_HAS_CARRIER | FE_HAS_VITERBI |
555 FE_HAS_SYNC | FE_HAS_LOCK;
556 }
557
558 return status;
559 }
560
561 #if notyet
562 int
563 nxt2k_fe_read_ucblocks(struct nxt2k *nxt, uint32_t *ucblk)
564 {
565 uint8_t reg[3];
566
567 nxt2k_readreg(nxt, 0xe6, reg, 3);
568 *ucblk = reg[2];
569
570 return 0;
571 }
572
573 int
574 nxt2k_fe_read_ber(struct nxt2k *nxt, uint32_t *ber)
575 {
576 uint8_t reg[3];
577
578 nxt2k_readreg(nxt, 0xe6, reg, 3);
579
580 *ber = ((reg[0] << 8) + reg[1]) * 8;
581
582 return 0;
583 }
584 #endif
585
586 static int
587 nxt2k_fe_set_frontend(struct nxt2k *nxt, fe_modulation_t modulation)
588 {
589 uint8_t buf[5];
590
591 if (nxt->loaded != true)
592 nxt2k4_init(nxt);
593
594 nxt2k_mc_stop(nxt);
595
596 { /* 2k4 */
597 /* make sure demod is set to digital */
598 buf[0] = 0x04;
599 nxt2k_writedata(nxt, 0x14, buf, 1);
600 buf[0] = 0x00;
601 nxt2k_writedata(nxt, 0x17, buf, 1);
602 }
603
604 /* QAM/VSB punctured/non-punctured goes here */
605
606 /* tune in */
607 /* maybe ensure tuner managed to tune in? */
608
609 /* tuning done, reset agc */
610 nxt2k_agc_reset(nxt);
611
612 /* set target power level */
613 switch (modulation) {
614 case VSB_8:
615 buf[0] = 0x70;
616 break;
617 case QAM_256:
618 case QAM_64:
619 buf[0] = 0x74;
620 break;
621 default:
622 return EINVAL;
623 /* NOTREACHED */
624 }
625 nxt2k_writedata(nxt, 0x42, buf, 1);
626
627 /* configure sdm */
628 buf[0] = 0x07; /* 2k4 */
629 nxt2k_writedata(nxt, 0x57, buf, 1);
630
631 /* write sdm1 input */
632 buf[0] = 0x10;
633 buf[1] = 0x00;
634 nxt2k_writedata(nxt, 0x58, buf, 2); /* 2k4 */
635
636 /* write sdmx input */
637 switch (modulation) {
638 case VSB_8:
639 buf[0] = 0x60;
640 break;
641 case QAM_256:
642 buf[0] = 0x64;
643 break;
644 case QAM_64:
645 buf[0] = 0x68;
646 break;
647 default:
648 return EINVAL;
649 /* NOTREACHED */
650 }
651 buf[1] = 0x00;
652 nxt2k_writedata(nxt, 0x5c, buf, 2); /* 2k4 */
653
654 /* write adc power lpf fc */
655 buf[0] = 0x05;
656 nxt2k_writedata(nxt, 0x43, buf, 1);
657
658 { /* 2k4 */
659 buf[0] = 0x00;
660 buf[1] = 0x00;
661 nxt2k_writedata(nxt, 0x46, buf, 2);
662 }
663
664 /* write accumulator2 input */
665 buf[0] = 0x80;
666 buf[1] = 0x00;
667 nxt2k_writedata(nxt, 0x4b, buf, 2); /* 2k4 */
668
669 /* write kg1 */
670 buf[0] = 0x00;
671 nxt2k_writedata(nxt, 0x4d, buf, 1);
672
673 /* write sdm12 lpf fc */
674 buf[0] = 0x44;
675 nxt2k_writedata(nxt, 0x55, buf, 1);
676
677 /* write agc control reg */
678 buf[0] = 0x04;
679 nxt2k_writedata(nxt, 0x41, buf, 1);
680
681 { /* 2k4 */
682 nxt2k_readreg(nxt, 0x80, buf, 1);
683 buf[0] = 0x24;
684 nxt2k_writereg(nxt, 0x80, buf, 1);
685
686 /* soft reset? */
687 nxt2k_readreg(nxt, 0x08, buf, 1);
688 buf[0] = 0x10;
689 nxt2k_writereg(nxt, 0x08, buf, 1);
690 nxt2k_readreg(nxt, 0x08, buf, 1);
691 buf[0] = 0x00;
692 nxt2k_writereg(nxt, 0x08, buf, 1);
693
694 nxt2k_readreg(nxt, 0x80, buf, 1);
695 buf[0] = 0x04;
696 nxt2k_writereg(nxt, 0x80, buf, 1);
697
698 buf[0] = 0x00;
699 nxt2k_writereg(nxt, 0x81, buf, 1);
700
701 buf[0] = 0x80; buf[1] = 0x00; buf[2] = 0x00;
702 nxt2k_writereg(nxt, 0x82, buf, 3);
703
704 nxt2k_readreg(nxt, 0x88, buf, 1);
705 buf[0] = 0x11;
706 nxt2k_writereg(nxt, 0x88, buf, 1);
707
708 nxt2k_readreg(nxt, 0x80, buf, 1);
709 buf[0] = 0x44;
710 nxt2k_writereg(nxt, 0x80, buf, 1);
711 }
712
713 /* write agc ucgp0 */
714 switch (modulation) {
715 case VSB_8:
716 buf[0] = 0x00;
717 break;
718 case QAM_64:
719 buf[0] = 0x02;
720 break;
721 case QAM_256:
722 buf[0] = 0x03;
723 break;
724 default:
725 return EINVAL;
726 /* NOTREACHED */
727 }
728 nxt2k_writedata(nxt, 0x30, buf, 1);
729
730 /* write agc control reg */
731 buf[0] = 0x00;
732 nxt2k_writedata(nxt, 0x41, buf, 1);
733
734 /* write accumulator2 input */
735 buf[0] = 0x80;
736 buf[1] = 0x00;
737 { /* 2k4 */
738 nxt2k_writedata(nxt, 0x49, buf, 2);
739 nxt2k_writedata(nxt, 0x4b, buf, 2);
740 }
741
742 /* write agc control reg */
743 buf[0] = 0x04;
744 nxt2k_writedata(nxt, 0x41, buf, 1);
745
746 nxt2k_mc_start(nxt);
747
748 { /* 2k4 */
749 nxt2k4_mc_init(nxt);
750 buf[0] = 0xf0;
751 buf[1] = 0x00;
752 nxt2k_writedata(nxt, 0x5c, buf, 2);
753 }
754
755 /* "adjacent channel detection" code would go here */
756
757 return 0;
758 }
759
760 static int
761 nxt2k_init(struct nxt2k *nxt)
762 {
763 int ret = 0;
764
765 printf("%s\n", __func__);
766
767 if (nxt->loaded != 1)
768 ret = nxt2k4_init(nxt);
769
770 return ret;
771 }
772
773
774 struct nxt2k *
775 nxt2k_open(device_t parent, i2c_tag_t tag, i2c_addr_t addr, unsigned int if_freq)
776 {
777 struct nxt2k *nxt;
778 int e;
779 uint8_t b[5];
780
781 nxt = kmem_alloc(sizeof(*nxt), KM_SLEEP);
782 if (nxt == NULL)
783 return NULL;
784
785 nxt->parent = parent;
786 nxt->tag = tag;
787 nxt->addr = addr;
788
789 /* read chip ids */
790 e = nxt2k_readdata(nxt, 0x00, b, 5);
791
792 if (e) {
793 printf("%s read failed %d\n", __func__, e);
794 kmem_free(nxt, sizeof(*nxt));
795 return NULL;
796 }
797
798 if (b[0] != 0x05) {
799 printf("%s unsupported %02x %02x %02x %02x %02x\n",
800 __func__, b[0], b[1], b[2], b[3], b[4]);
801 kmem_free(nxt, sizeof(*nxt));
802 return NULL;
803 }
804
805 mutex_init(&nxt->mtx, MUTEX_DEFAULT, IPL_NONE);
806 cv_init(&nxt->cv, "nxtpl");
807
808 nxt->loaded = false;
809
810 return nxt;
811 }
812
813 void
814 nxt2k_close(struct nxt2k *nxt)
815 {
816 kmem_free(nxt, sizeof(*nxt));
817 }
818
819 void
820 nxt2k_enable(struct nxt2k *nxt, bool enable)
821 {
822 if (enable == true)
823 nxt2k_init(nxt);
824 }
825
826 int
827 nxt2k_set_modulation(struct nxt2k *nxt, fe_modulation_t modulation)
828 {
829 return nxt2k_fe_set_frontend(nxt, modulation);
830 }
831