Home | History | Annotate | Line # | Download | only in i2c
      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 
     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
     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 ((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 
     91 static int
     92 nxt2k_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 			 &reg, 1, data, len, 0);
    101 
    102 	iic_release_bus(nxt->tag, 0);
    103 
    104 	return error;
    105 }
    106 
    107 static int
    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, &reg, 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
    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, &reg, 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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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, &reg, 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
    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
    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
    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
    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 *
    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 	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 
    811 void
    812 nxt2k_close(struct nxt2k *nxt)
    813 {
    814 	kmem_free(nxt, sizeof(*nxt));
    815 }
    816 
    817 void
    818 nxt2k_enable(struct nxt2k *nxt, bool enable)
    819 {
    820 	if (enable == true)
    821 		nxt2k_init(nxt);
    822 }
    823 
    824 int
    825 nxt2k_set_modulation(struct nxt2k *nxt, fe_modulation_t modulation)
    826 {
    827 	return nxt2k_fe_set_frontend(nxt, modulation);
    828 }
    829 
    830 MODULE(MODULE_CLASS_DRIVER, nxt2k, "i2cexec");
    831 
    832 static int
    833 nxt2k_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