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 |
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 |
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 |
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 |
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 |
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, ®, 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 | 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 |
815 | nxt2k_close(struct nxt2k *nxt) |
816 | { |
817 | kmem_free(nxt, sizeof(*nxt)); |
818 | } |
819 | |
820 | void |
821 | nxt2k_enable(struct nxt2k *nxt, bool enable) |
822 | { |
823 | if (enable == true) |
824 | nxt2k_init(nxt); |
825 | } |
826 | |
827 | int |
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 |
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 | |