1/* $NetBSD: nxt2k.c,v 1.7 2019/12/31 14:27:50 thorpej 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.7 2019/12/31 14:27:50 thorpej 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 45struct 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 54static int nxt2k_init(struct nxt2k *); 55 56static int nxt2k_writedata(struct nxt2k *, uint8_t, uint8_t *, size_t); 57static int nxt2k_readdata(struct nxt2k *, uint8_t, uint8_t *, size_t); 58static int nxt2k_writereg(struct nxt2k *, uint8_t, uint8_t *, size_t); 59static int nxt2k_readreg(struct nxt2k*, uint8_t, uint8_t *, size_t); 60 61static int nxt2k4_init(struct nxt2k *); 62static bool nxt2k4_load_firmware(struct nxt2k *); 63static void nxt2k4_mc_init(struct nxt2k *); 64static void nxt2k_mc_start(struct nxt2k *); 65static void nxt2k_mc_stop(struct nxt2k *); 66static void nxt2k_agc_reset(struct nxt2k *); 67static uint16_t nxt2k_crc_ccit(uint16_t, uint8_t); 68 69static int 70nxt2k_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 ((error = iic_acquire_bus(nxt->tag, 0)) != 0) 78 return error; 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, 0); 85 86 iic_release_bus(nxt->tag, 0); 87 88 return error; 89} 90 91static int 92nxt2k_readdata(struct nxt2k *nxt, uint8_t reg, uint8_t *data, size_t len) 93{ 94 int error; 95 96 if ((error = iic_acquire_bus(nxt->tag, 0)) != 0) 97 return error; 98 99 error = iic_exec(nxt->tag, I2C_OP_READ_WITH_STOP, nxt->addr, 100 ®, 1, data, len, 0); 101 102 iic_release_bus(nxt->tag, 0); 103 104 return error; 105} 106 107static int 108nxt2k_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 137static int 138nxt2k_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 165static void 166nxt2k_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 177static void 178nxt2k_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 203static void 204nxt2k_mc_start(struct nxt2k *nxt) 205{ 206 uint8_t buf; 207 208 buf = 0x00; 209 nxt2k_writedata(nxt, 0x22, &buf, 1); 210} 211 212static void 213nxt2k4_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 */ 246static uint16_t 247nxt2k_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 264static bool 265nxt2k4_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 347static int 348nxt2k4_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 497uint16_t 498nxt2k_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 515uint16_t 516nxt2k_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 547fe_status_t 548nxt2k_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 563int 564nxt2k_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 574int 575nxt2k_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 587static int 588nxt2k_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 761static int 762nxt2k_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 775struct nxt2k * 776nxt2k_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 nxt->parent = parent; 784 nxt->tag = tag; 785 nxt->addr = addr; 786 787 /* read chip ids */ 788 e = nxt2k_readdata(nxt, 0x00, b, 5); 789 790 if (e) { 791 printf("%s read failed %d\n", __func__, e); 792 kmem_free(nxt, sizeof(*nxt)); 793 return NULL; 794 } 795 796 if (b[0] != 0x05) { 797 printf("%s unsupported %02x %02x %02x %02x %02x\n", 798 __func__, b[0], b[1], b[2], b[3], b[4]); 799 kmem_free(nxt, sizeof(*nxt)); 800 return NULL; 801 } 802 803 mutex_init(&nxt->mtx, MUTEX_DEFAULT, IPL_NONE); 804 cv_init(&nxt->cv, "nxtpl"); 805 806 nxt->loaded = false; 807 808 return nxt; 809} 810 811void 812nxt2k_close(struct nxt2k *nxt) 813{ 814 kmem_free(nxt, sizeof(*nxt)); 815} 816 817void 818nxt2k_enable(struct nxt2k *nxt, bool enable) 819{ 820 if (enable == true) 821 nxt2k_init(nxt); 822} 823 824int 825nxt2k_set_modulation(struct nxt2k *nxt, fe_modulation_t modulation) 826{ 827 return nxt2k_fe_set_frontend(nxt, modulation); 828} 829 830MODULE(MODULE_CLASS_DRIVER, nxt2k, "i2cexec"); 831 832static int 833nxt2k_modcmd(modcmd_t cmd, void *opaque) 834{ 835 if (cmd == MODULE_CMD_INIT || cmd == MODULE_CMD_FINI) 836 return 0; 837 return ENOTTY; 838} 839