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 			 &reg, 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, &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
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, &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
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, &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
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