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