Home | History | Annotate | Line # | Download | only in i2c
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 			 &reg, 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, &reg, 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, &reg, 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, &reg, 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