]>
Commit | Line | Data |
---|---|---|
c942fddf | 1 | // SPDX-License-Identifier: GPL-2.0-or-later |
e26f2ae4 MK |
2 | /* |
3 | * Support for LG2160 - ATSC/MH | |
4 | * | |
5 | * Copyright (C) 2010 Michael Krufky <mkrufky@linuxtv.org> | |
e26f2ae4 MK |
6 | */ |
7 | ||
8 | #include <linux/jiffies.h> | |
9 | #include <linux/dvb/frontend.h> | |
10 | #include "lg2160.h" | |
11 | ||
12 | static int debug; | |
13 | module_param(debug, int, 0644); | |
14 | MODULE_PARM_DESC(debug, "set debug level (info=1, reg=2 (or-able))"); | |
15 | ||
16 | #define DBG_INFO 1 | |
17 | #define DBG_REG 2 | |
18 | ||
19 | #define lg_printk(kern, fmt, arg...) \ | |
20 | printk(kern "%s: " fmt, __func__, ##arg) | |
21 | ||
22 | #define lg_info(fmt, arg...) printk(KERN_INFO "lg2160: " fmt, ##arg) | |
23 | #define lg_warn(fmt, arg...) lg_printk(KERN_WARNING, fmt, ##arg) | |
24 | #define lg_err(fmt, arg...) lg_printk(KERN_ERR, fmt, ##arg) | |
25 | #define lg_dbg(fmt, arg...) if (debug & DBG_INFO) \ | |
26 | lg_printk(KERN_DEBUG, fmt, ##arg) | |
27 | #define lg_reg(fmt, arg...) if (debug & DBG_REG) \ | |
28 | lg_printk(KERN_DEBUG, fmt, ##arg) | |
29 | ||
30 | #define lg_fail(ret) \ | |
31 | ({ \ | |
32 | int __ret; \ | |
33 | __ret = (ret < 0); \ | |
34 | if (__ret) \ | |
35 | lg_err("error %d on line %d\n", ret, __LINE__); \ | |
36 | __ret; \ | |
37 | }) | |
38 | ||
39 | struct lg216x_state { | |
40 | struct i2c_adapter *i2c_adap; | |
41 | const struct lg2160_config *cfg; | |
42 | ||
43 | struct dvb_frontend frontend; | |
44 | ||
45 | u32 current_frequency; | |
46 | u8 parade_id; | |
47 | u8 fic_ver; | |
48 | unsigned int last_reset; | |
49 | }; | |
50 | ||
51 | /* ------------------------------------------------------------------------ */ | |
52 | ||
53 | static int lg216x_write_reg(struct lg216x_state *state, u16 reg, u8 val) | |
54 | { | |
55 | int ret; | |
56 | u8 buf[] = { reg >> 8, reg & 0xff, val }; | |
57 | struct i2c_msg msg = { | |
58 | .addr = state->cfg->i2c_addr, .flags = 0, | |
59 | .buf = buf, .len = 3, | |
60 | }; | |
61 | ||
62 | lg_reg("reg: 0x%04x, val: 0x%02x\n", reg, val); | |
63 | ||
64 | ret = i2c_transfer(state->i2c_adap, &msg, 1); | |
65 | ||
66 | if (ret != 1) { | |
67 | lg_err("error (addr %02x %02x <- %02x, err = %i)\n", | |
68 | msg.buf[0], msg.buf[1], msg.buf[2], ret); | |
69 | if (ret < 0) | |
70 | return ret; | |
71 | else | |
72 | return -EREMOTEIO; | |
73 | } | |
74 | return 0; | |
75 | } | |
76 | ||
77 | static int lg216x_read_reg(struct lg216x_state *state, u16 reg, u8 *val) | |
78 | { | |
79 | int ret; | |
80 | u8 reg_buf[] = { reg >> 8, reg & 0xff }; | |
81 | struct i2c_msg msg[] = { | |
82 | { .addr = state->cfg->i2c_addr, | |
83 | .flags = 0, .buf = reg_buf, .len = 2 }, | |
84 | { .addr = state->cfg->i2c_addr, | |
85 | .flags = I2C_M_RD, .buf = val, .len = 1 }, | |
86 | }; | |
87 | ||
88 | lg_reg("reg: 0x%04x\n", reg); | |
89 | ||
90 | ret = i2c_transfer(state->i2c_adap, msg, 2); | |
91 | ||
92 | if (ret != 2) { | |
93 | lg_err("error (addr %02x reg %04x error (ret == %i)\n", | |
94 | state->cfg->i2c_addr, reg, ret); | |
95 | if (ret < 0) | |
96 | return ret; | |
97 | else | |
98 | return -EREMOTEIO; | |
99 | } | |
100 | return 0; | |
101 | } | |
102 | ||
103 | struct lg216x_reg { | |
104 | u16 reg; | |
105 | u8 val; | |
106 | }; | |
107 | ||
108 | static int lg216x_write_regs(struct lg216x_state *state, | |
109 | struct lg216x_reg *regs, int len) | |
110 | { | |
111 | int i, ret; | |
112 | ||
113 | lg_reg("writing %d registers...\n", len); | |
114 | ||
bffaecc7 | 115 | for (i = 0; i < len; i++) { |
e26f2ae4 MK |
116 | ret = lg216x_write_reg(state, regs[i].reg, regs[i].val); |
117 | if (lg_fail(ret)) | |
118 | return ret; | |
119 | } | |
120 | return 0; | |
121 | } | |
122 | ||
123 | static int lg216x_set_reg_bit(struct lg216x_state *state, | |
124 | u16 reg, int bit, int onoff) | |
125 | { | |
126 | u8 val; | |
127 | int ret; | |
128 | ||
129 | lg_reg("reg: 0x%04x, bit: %d, level: %d\n", reg, bit, onoff); | |
130 | ||
131 | ret = lg216x_read_reg(state, reg, &val); | |
132 | if (lg_fail(ret)) | |
133 | goto fail; | |
134 | ||
135 | val &= ~(1 << bit); | |
136 | val |= (onoff & 1) << bit; | |
137 | ||
138 | ret = lg216x_write_reg(state, reg, val); | |
139 | lg_fail(ret); | |
140 | fail: | |
141 | return ret; | |
142 | } | |
143 | ||
144 | /* ------------------------------------------------------------------------ */ | |
145 | ||
146 | static int lg216x_i2c_gate_ctrl(struct dvb_frontend *fe, int enable) | |
147 | { | |
148 | struct lg216x_state *state = fe->demodulator_priv; | |
149 | int ret; | |
150 | ||
151 | if (state->cfg->deny_i2c_rptr) | |
152 | return 0; | |
153 | ||
154 | lg_dbg("(%d)\n", enable); | |
155 | ||
156 | ret = lg216x_set_reg_bit(state, 0x0000, 0, enable ? 0 : 1); | |
157 | ||
158 | msleep(1); | |
159 | ||
160 | return ret; | |
161 | } | |
162 | ||
163 | static int lg216x_soft_reset(struct lg216x_state *state) | |
164 | { | |
165 | int ret; | |
166 | ||
167 | lg_dbg("\n"); | |
168 | ||
169 | ret = lg216x_write_reg(state, 0x0002, 0x00); | |
170 | if (lg_fail(ret)) | |
171 | goto fail; | |
172 | ||
173 | msleep(20); | |
174 | ret = lg216x_write_reg(state, 0x0002, 0x01); | |
175 | if (lg_fail(ret)) | |
176 | goto fail; | |
177 | ||
178 | state->last_reset = jiffies_to_msecs(jiffies); | |
179 | fail: | |
180 | return ret; | |
181 | } | |
182 | ||
183 | static int lg216x_initialize(struct lg216x_state *state) | |
184 | { | |
185 | int ret; | |
186 | ||
187 | static struct lg216x_reg lg2160_init[] = { | |
188 | #if 0 | |
189 | { .reg = 0x0015, .val = 0xe6 }, | |
190 | #else | |
191 | { .reg = 0x0015, .val = 0xf7 }, | |
192 | { .reg = 0x001b, .val = 0x52 }, | |
193 | { .reg = 0x0208, .val = 0x00 }, | |
194 | { .reg = 0x0209, .val = 0x82 }, | |
195 | { .reg = 0x0210, .val = 0xf9 }, | |
196 | { .reg = 0x020a, .val = 0x00 }, | |
197 | { .reg = 0x020b, .val = 0x82 }, | |
198 | { .reg = 0x020d, .val = 0x28 }, | |
199 | { .reg = 0x020f, .val = 0x14 }, | |
200 | #endif | |
201 | }; | |
202 | ||
203 | static struct lg216x_reg lg2161_init[] = { | |
204 | { .reg = 0x0000, .val = 0x41 }, | |
205 | { .reg = 0x0001, .val = 0xfb }, | |
206 | { .reg = 0x0216, .val = 0x00 }, | |
207 | { .reg = 0x0219, .val = 0x00 }, | |
208 | { .reg = 0x021b, .val = 0x55 }, | |
209 | { .reg = 0x0606, .val = 0x0a }, | |
210 | }; | |
211 | ||
212 | switch (state->cfg->lg_chip) { | |
213 | case LG2160: | |
214 | ret = lg216x_write_regs(state, | |
215 | lg2160_init, ARRAY_SIZE(lg2160_init)); | |
216 | break; | |
217 | case LG2161: | |
218 | ret = lg216x_write_regs(state, | |
219 | lg2161_init, ARRAY_SIZE(lg2161_init)); | |
220 | break; | |
221 | default: | |
222 | ret = -EINVAL; | |
223 | break; | |
224 | } | |
225 | if (lg_fail(ret)) | |
226 | goto fail; | |
227 | ||
228 | ret = lg216x_soft_reset(state); | |
229 | lg_fail(ret); | |
230 | fail: | |
231 | return ret; | |
232 | } | |
233 | ||
234 | /* ------------------------------------------------------------------------ */ | |
235 | ||
236 | static int lg216x_set_if(struct lg216x_state *state) | |
237 | { | |
238 | u8 val; | |
239 | int ret; | |
240 | ||
241 | lg_dbg("%d KHz\n", state->cfg->if_khz); | |
242 | ||
243 | ret = lg216x_read_reg(state, 0x0132, &val); | |
244 | if (lg_fail(ret)) | |
245 | goto fail; | |
246 | ||
247 | val &= 0xfb; | |
248 | val |= (0 == state->cfg->if_khz) ? 0x04 : 0x00; | |
249 | ||
250 | ret = lg216x_write_reg(state, 0x0132, val); | |
251 | lg_fail(ret); | |
252 | ||
253 | /* if NOT zero IF, 6 MHz is the default */ | |
254 | fail: | |
255 | return ret; | |
256 | } | |
257 | ||
258 | /* ------------------------------------------------------------------------ */ | |
259 | ||
260 | static int lg2160_agc_fix(struct lg216x_state *state, | |
261 | int if_agc_fix, int rf_agc_fix) | |
262 | { | |
263 | u8 val; | |
264 | int ret; | |
265 | ||
266 | ret = lg216x_read_reg(state, 0x0100, &val); | |
267 | if (lg_fail(ret)) | |
268 | goto fail; | |
269 | ||
270 | val &= 0xf3; | |
271 | val |= (if_agc_fix) ? 0x08 : 0x00; | |
272 | val |= (rf_agc_fix) ? 0x04 : 0x00; | |
273 | ||
274 | ret = lg216x_write_reg(state, 0x0100, val); | |
275 | lg_fail(ret); | |
276 | fail: | |
277 | return ret; | |
278 | } | |
279 | ||
280 | #if 0 | |
281 | static int lg2160_agc_freeze(struct lg216x_state *state, | |
282 | int if_agc_freeze, int rf_agc_freeze) | |
283 | { | |
284 | u8 val; | |
285 | int ret; | |
286 | ||
287 | ret = lg216x_read_reg(state, 0x0100, &val); | |
288 | if (lg_fail(ret)) | |
289 | goto fail; | |
290 | ||
291 | val &= 0xcf; | |
292 | val |= (if_agc_freeze) ? 0x20 : 0x00; | |
293 | val |= (rf_agc_freeze) ? 0x10 : 0x00; | |
294 | ||
295 | ret = lg216x_write_reg(state, 0x0100, val); | |
296 | lg_fail(ret); | |
297 | fail: | |
298 | return ret; | |
299 | } | |
300 | #endif | |
301 | ||
302 | static int lg2160_agc_polarity(struct lg216x_state *state, | |
303 | int if_agc_polarity, int rf_agc_polarity) | |
304 | { | |
305 | u8 val; | |
306 | int ret; | |
307 | ||
308 | ret = lg216x_read_reg(state, 0x0100, &val); | |
309 | if (lg_fail(ret)) | |
310 | goto fail; | |
311 | ||
312 | val &= 0xfc; | |
313 | val |= (if_agc_polarity) ? 0x02 : 0x00; | |
314 | val |= (rf_agc_polarity) ? 0x01 : 0x00; | |
315 | ||
316 | ret = lg216x_write_reg(state, 0x0100, val); | |
317 | lg_fail(ret); | |
318 | fail: | |
319 | return ret; | |
320 | } | |
321 | ||
322 | static int lg2160_tuner_pwr_save_polarity(struct lg216x_state *state, | |
323 | int polarity) | |
324 | { | |
325 | u8 val; | |
326 | int ret; | |
327 | ||
328 | ret = lg216x_read_reg(state, 0x0008, &val); | |
329 | if (lg_fail(ret)) | |
330 | goto fail; | |
331 | ||
332 | val &= 0xfe; | |
333 | val |= (polarity) ? 0x01 : 0x00; | |
334 | ||
335 | ret = lg216x_write_reg(state, 0x0008, val); | |
336 | lg_fail(ret); | |
337 | fail: | |
338 | return ret; | |
339 | } | |
340 | ||
341 | static int lg2160_spectrum_polarity(struct lg216x_state *state, | |
342 | int inverted) | |
343 | { | |
344 | u8 val; | |
345 | int ret; | |
346 | ||
347 | ret = lg216x_read_reg(state, 0x0132, &val); | |
348 | if (lg_fail(ret)) | |
349 | goto fail; | |
350 | ||
351 | val &= 0xfd; | |
352 | val |= (inverted) ? 0x02 : 0x00; | |
353 | ||
354 | ret = lg216x_write_reg(state, 0x0132, val); | |
355 | lg_fail(ret); | |
356 | fail: | |
357 | return lg216x_soft_reset(state); | |
358 | } | |
359 | ||
360 | static int lg2160_tuner_pwr_save(struct lg216x_state *state, int onoff) | |
361 | { | |
362 | u8 val; | |
363 | int ret; | |
364 | ||
365 | ret = lg216x_read_reg(state, 0x0007, &val); | |
366 | if (lg_fail(ret)) | |
367 | goto fail; | |
368 | ||
369 | val &= 0xbf; | |
370 | val |= (onoff) ? 0x40 : 0x00; | |
371 | ||
372 | ret = lg216x_write_reg(state, 0x0007, val); | |
373 | lg_fail(ret); | |
374 | fail: | |
375 | return ret; | |
376 | } | |
377 | ||
378 | static int lg216x_set_parade(struct lg216x_state *state, int id) | |
379 | { | |
380 | int ret; | |
381 | ||
382 | ret = lg216x_write_reg(state, 0x013e, id & 0x7f); | |
383 | if (lg_fail(ret)) | |
384 | goto fail; | |
385 | ||
386 | state->parade_id = id & 0x7f; | |
387 | fail: | |
388 | return ret; | |
389 | } | |
390 | ||
391 | static int lg216x_set_ensemble(struct lg216x_state *state, int id) | |
392 | { | |
393 | int ret; | |
394 | u16 reg; | |
395 | u8 val; | |
396 | ||
397 | switch (state->cfg->lg_chip) { | |
398 | case LG2160: | |
399 | reg = 0x0400; | |
400 | break; | |
401 | case LG2161: | |
5444a1b7 | 402 | default: |
e26f2ae4 MK |
403 | reg = 0x0500; |
404 | break; | |
405 | } | |
406 | ||
407 | ret = lg216x_read_reg(state, reg, &val); | |
408 | if (lg_fail(ret)) | |
409 | goto fail; | |
410 | ||
411 | val &= 0xfe; | |
412 | val |= (id) ? 0x01 : 0x00; | |
413 | ||
414 | ret = lg216x_write_reg(state, reg, val); | |
415 | lg_fail(ret); | |
416 | fail: | |
417 | return ret; | |
418 | } | |
419 | ||
420 | static int lg2160_set_spi_clock(struct lg216x_state *state) | |
421 | { | |
422 | u8 val; | |
423 | int ret; | |
424 | ||
425 | ret = lg216x_read_reg(state, 0x0014, &val); | |
426 | if (lg_fail(ret)) | |
427 | goto fail; | |
428 | ||
429 | val &= 0xf3; | |
430 | val |= (state->cfg->spi_clock << 2); | |
431 | ||
432 | ret = lg216x_write_reg(state, 0x0014, val); | |
433 | lg_fail(ret); | |
434 | fail: | |
435 | return ret; | |
436 | } | |
437 | ||
438 | static int lg2161_set_output_interface(struct lg216x_state *state) | |
439 | { | |
440 | u8 val; | |
441 | int ret; | |
442 | ||
443 | ret = lg216x_read_reg(state, 0x0014, &val); | |
444 | if (lg_fail(ret)) | |
445 | goto fail; | |
446 | ||
447 | val &= ~0x07; | |
448 | val |= state->cfg->output_if; /* FIXME: needs sanity check */ | |
449 | ||
450 | ret = lg216x_write_reg(state, 0x0014, val); | |
451 | lg_fail(ret); | |
452 | fail: | |
453 | return ret; | |
454 | } | |
455 | ||
456 | static int lg216x_enable_fic(struct lg216x_state *state, int onoff) | |
457 | { | |
458 | int ret; | |
459 | ||
460 | ret = lg216x_write_reg(state, 0x0017, 0x23); | |
461 | if (lg_fail(ret)) | |
462 | goto fail; | |
463 | ||
464 | ret = lg216x_write_reg(state, 0x0016, 0xfc); | |
465 | if (lg_fail(ret)) | |
466 | goto fail; | |
467 | ||
468 | switch (state->cfg->lg_chip) { | |
469 | case LG2160: | |
470 | ret = lg216x_write_reg(state, 0x0016, | |
471 | 0xfc | ((onoff) ? 0x02 : 0x00)); | |
472 | break; | |
473 | case LG2161: | |
474 | ret = lg216x_write_reg(state, 0x0016, (onoff) ? 0x10 : 0x00); | |
475 | break; | |
476 | } | |
477 | if (lg_fail(ret)) | |
478 | goto fail; | |
479 | ||
480 | ret = lg216x_initialize(state); | |
481 | if (lg_fail(ret)) | |
482 | goto fail; | |
483 | ||
484 | if (onoff) { | |
485 | ret = lg216x_write_reg(state, 0x0017, 0x03); | |
486 | lg_fail(ret); | |
487 | } | |
488 | fail: | |
489 | return ret; | |
490 | } | |
491 | ||
492 | /* ------------------------------------------------------------------------ */ | |
493 | ||
494 | static int lg216x_get_fic_version(struct lg216x_state *state, u8 *ficver) | |
495 | { | |
496 | u8 val; | |
497 | int ret; | |
498 | ||
499 | *ficver = 0xff; /* invalid value */ | |
500 | ||
501 | ret = lg216x_read_reg(state, 0x0128, &val); | |
502 | if (lg_fail(ret)) | |
503 | goto fail; | |
504 | ||
505 | *ficver = (val >> 3) & 0x1f; | |
506 | fail: | |
507 | return ret; | |
508 | } | |
509 | ||
510 | #if 0 | |
511 | static int lg2160_get_parade_id(struct lg216x_state *state, u8 *id) | |
512 | { | |
513 | u8 val; | |
514 | int ret; | |
515 | ||
516 | *id = 0xff; /* invalid value */ | |
517 | ||
518 | ret = lg216x_read_reg(state, 0x0123, &val); | |
519 | if (lg_fail(ret)) | |
520 | goto fail; | |
521 | ||
522 | *id = val & 0x7f; | |
523 | fail: | |
524 | return ret; | |
525 | } | |
526 | #endif | |
527 | ||
528 | static int lg216x_get_nog(struct lg216x_state *state, u8 *nog) | |
529 | { | |
530 | u8 val; | |
531 | int ret; | |
532 | ||
533 | *nog = 0xff; /* invalid value */ | |
534 | ||
535 | ret = lg216x_read_reg(state, 0x0124, &val); | |
536 | if (lg_fail(ret)) | |
537 | goto fail; | |
538 | ||
539 | *nog = ((val >> 4) & 0x07) + 1; | |
540 | fail: | |
541 | return ret; | |
542 | } | |
543 | ||
544 | static int lg216x_get_tnog(struct lg216x_state *state, u8 *tnog) | |
545 | { | |
546 | u8 val; | |
547 | int ret; | |
548 | ||
549 | *tnog = 0xff; /* invalid value */ | |
550 | ||
551 | ret = lg216x_read_reg(state, 0x0125, &val); | |
552 | if (lg_fail(ret)) | |
553 | goto fail; | |
554 | ||
555 | *tnog = val & 0x1f; | |
556 | fail: | |
557 | return ret; | |
558 | } | |
559 | ||
560 | static int lg216x_get_sgn(struct lg216x_state *state, u8 *sgn) | |
561 | { | |
562 | u8 val; | |
563 | int ret; | |
564 | ||
565 | *sgn = 0xff; /* invalid value */ | |
566 | ||
567 | ret = lg216x_read_reg(state, 0x0124, &val); | |
568 | if (lg_fail(ret)) | |
569 | goto fail; | |
570 | ||
571 | *sgn = val & 0x0f; | |
572 | fail: | |
573 | return ret; | |
574 | } | |
575 | ||
576 | static int lg216x_get_prc(struct lg216x_state *state, u8 *prc) | |
577 | { | |
578 | u8 val; | |
579 | int ret; | |
580 | ||
581 | *prc = 0xff; /* invalid value */ | |
582 | ||
583 | ret = lg216x_read_reg(state, 0x0125, &val); | |
584 | if (lg_fail(ret)) | |
585 | goto fail; | |
586 | ||
587 | *prc = ((val >> 5) & 0x07) + 1; | |
588 | fail: | |
589 | return ret; | |
590 | } | |
591 | ||
592 | /* ------------------------------------------------------------------------ */ | |
593 | ||
594 | static int lg216x_get_rs_frame_mode(struct lg216x_state *state, | |
595 | enum atscmh_rs_frame_mode *rs_framemode) | |
596 | { | |
597 | u8 val; | |
598 | int ret; | |
599 | ||
600 | switch (state->cfg->lg_chip) { | |
601 | case LG2160: | |
602 | ret = lg216x_read_reg(state, 0x0410, &val); | |
603 | break; | |
604 | case LG2161: | |
605 | ret = lg216x_read_reg(state, 0x0513, &val); | |
606 | break; | |
607 | default: | |
608 | ret = -EINVAL; | |
609 | } | |
610 | if (lg_fail(ret)) | |
611 | goto fail; | |
612 | ||
613 | switch ((val >> 4) & 0x03) { | |
614 | #if 1 | |
615 | default: | |
616 | #endif | |
617 | case 0x00: | |
618 | *rs_framemode = ATSCMH_RSFRAME_PRI_ONLY; | |
619 | break; | |
620 | case 0x01: | |
621 | *rs_framemode = ATSCMH_RSFRAME_PRI_SEC; | |
622 | break; | |
623 | #if 0 | |
624 | default: | |
625 | *rs_framemode = ATSCMH_RSFRAME_RES; | |
626 | break; | |
627 | #endif | |
628 | } | |
629 | fail: | |
630 | return ret; | |
631 | } | |
632 | ||
633 | static | |
634 | int lg216x_get_rs_frame_ensemble(struct lg216x_state *state, | |
635 | enum atscmh_rs_frame_ensemble *rs_frame_ens) | |
636 | { | |
637 | u8 val; | |
638 | int ret; | |
639 | ||
640 | switch (state->cfg->lg_chip) { | |
641 | case LG2160: | |
642 | ret = lg216x_read_reg(state, 0x0400, &val); | |
643 | break; | |
644 | case LG2161: | |
645 | ret = lg216x_read_reg(state, 0x0500, &val); | |
646 | break; | |
647 | default: | |
648 | ret = -EINVAL; | |
649 | } | |
650 | if (lg_fail(ret)) | |
651 | goto fail; | |
652 | ||
653 | val &= 0x01; | |
654 | *rs_frame_ens = (enum atscmh_rs_frame_ensemble) val; | |
655 | fail: | |
656 | return ret; | |
657 | } | |
658 | ||
659 | static int lg216x_get_rs_code_mode(struct lg216x_state *state, | |
660 | enum atscmh_rs_code_mode *rs_code_pri, | |
661 | enum atscmh_rs_code_mode *rs_code_sec) | |
662 | { | |
663 | u8 val; | |
664 | int ret; | |
665 | ||
666 | switch (state->cfg->lg_chip) { | |
667 | case LG2160: | |
668 | ret = lg216x_read_reg(state, 0x0410, &val); | |
669 | break; | |
670 | case LG2161: | |
671 | ret = lg216x_read_reg(state, 0x0513, &val); | |
672 | break; | |
673 | default: | |
674 | ret = -EINVAL; | |
675 | } | |
676 | if (lg_fail(ret)) | |
677 | goto fail; | |
678 | ||
679 | *rs_code_pri = (enum atscmh_rs_code_mode) ((val >> 2) & 0x03); | |
680 | *rs_code_sec = (enum atscmh_rs_code_mode) (val & 0x03); | |
681 | fail: | |
682 | return ret; | |
683 | } | |
684 | ||
685 | static int lg216x_get_sccc_block_mode(struct lg216x_state *state, | |
686 | enum atscmh_sccc_block_mode *sccc_block) | |
687 | { | |
688 | u8 val; | |
689 | int ret; | |
690 | ||
691 | switch (state->cfg->lg_chip) { | |
692 | case LG2160: | |
693 | ret = lg216x_read_reg(state, 0x0315, &val); | |
694 | break; | |
695 | case LG2161: | |
696 | ret = lg216x_read_reg(state, 0x0511, &val); | |
697 | break; | |
698 | default: | |
699 | ret = -EINVAL; | |
700 | } | |
701 | if (lg_fail(ret)) | |
702 | goto fail; | |
703 | ||
704 | switch (val & 0x03) { | |
705 | case 0x00: | |
706 | *sccc_block = ATSCMH_SCCC_BLK_SEP; | |
707 | break; | |
708 | case 0x01: | |
709 | *sccc_block = ATSCMH_SCCC_BLK_COMB; | |
710 | break; | |
711 | default: | |
712 | *sccc_block = ATSCMH_SCCC_BLK_RES; | |
713 | break; | |
714 | } | |
715 | fail: | |
716 | return ret; | |
717 | } | |
718 | ||
719 | static int lg216x_get_sccc_code_mode(struct lg216x_state *state, | |
720 | enum atscmh_sccc_code_mode *mode_a, | |
721 | enum atscmh_sccc_code_mode *mode_b, | |
722 | enum atscmh_sccc_code_mode *mode_c, | |
723 | enum atscmh_sccc_code_mode *mode_d) | |
724 | { | |
725 | u8 val; | |
726 | int ret; | |
727 | ||
728 | switch (state->cfg->lg_chip) { | |
729 | case LG2160: | |
730 | ret = lg216x_read_reg(state, 0x0316, &val); | |
731 | break; | |
732 | case LG2161: | |
733 | ret = lg216x_read_reg(state, 0x0512, &val); | |
734 | break; | |
735 | default: | |
736 | ret = -EINVAL; | |
737 | } | |
738 | if (lg_fail(ret)) | |
739 | goto fail; | |
740 | ||
741 | switch ((val >> 6) & 0x03) { | |
742 | case 0x00: | |
743 | *mode_a = ATSCMH_SCCC_CODE_HLF; | |
744 | break; | |
745 | case 0x01: | |
746 | *mode_a = ATSCMH_SCCC_CODE_QTR; | |
747 | break; | |
748 | default: | |
749 | *mode_a = ATSCMH_SCCC_CODE_RES; | |
750 | break; | |
751 | } | |
752 | ||
753 | switch ((val >> 4) & 0x03) { | |
754 | case 0x00: | |
755 | *mode_b = ATSCMH_SCCC_CODE_HLF; | |
756 | break; | |
757 | case 0x01: | |
758 | *mode_b = ATSCMH_SCCC_CODE_QTR; | |
759 | break; | |
760 | default: | |
761 | *mode_b = ATSCMH_SCCC_CODE_RES; | |
762 | break; | |
763 | } | |
764 | ||
765 | switch ((val >> 2) & 0x03) { | |
766 | case 0x00: | |
767 | *mode_c = ATSCMH_SCCC_CODE_HLF; | |
768 | break; | |
769 | case 0x01: | |
770 | *mode_c = ATSCMH_SCCC_CODE_QTR; | |
771 | break; | |
772 | default: | |
773 | *mode_c = ATSCMH_SCCC_CODE_RES; | |
774 | break; | |
775 | } | |
776 | ||
777 | switch (val & 0x03) { | |
778 | case 0x00: | |
779 | *mode_d = ATSCMH_SCCC_CODE_HLF; | |
780 | break; | |
781 | case 0x01: | |
782 | *mode_d = ATSCMH_SCCC_CODE_QTR; | |
783 | break; | |
784 | default: | |
785 | *mode_d = ATSCMH_SCCC_CODE_RES; | |
786 | break; | |
787 | } | |
788 | fail: | |
789 | return ret; | |
790 | } | |
791 | ||
792 | /* ------------------------------------------------------------------------ */ | |
793 | ||
10d67371 | 794 | #if 0 |
e26f2ae4 MK |
795 | static int lg216x_read_fic_err_count(struct lg216x_state *state, u8 *err) |
796 | { | |
797 | u8 fic_err; | |
798 | int ret; | |
799 | ||
800 | *err = 0; | |
801 | ||
802 | switch (state->cfg->lg_chip) { | |
803 | case LG2160: | |
804 | ret = lg216x_read_reg(state, 0x0012, &fic_err); | |
805 | break; | |
806 | case LG2161: | |
807 | ret = lg216x_read_reg(state, 0x001e, &fic_err); | |
808 | break; | |
809 | } | |
810 | if (lg_fail(ret)) | |
811 | goto fail; | |
812 | ||
813 | *err = fic_err; | |
814 | fail: | |
815 | return ret; | |
816 | } | |
817 | ||
818 | static int lg2160_read_crc_err_count(struct lg216x_state *state, u16 *err) | |
819 | { | |
820 | u8 crc_err1, crc_err2; | |
821 | int ret; | |
822 | ||
823 | *err = 0; | |
824 | ||
825 | ret = lg216x_read_reg(state, 0x0411, &crc_err1); | |
826 | if (lg_fail(ret)) | |
827 | goto fail; | |
828 | ||
829 | ret = lg216x_read_reg(state, 0x0412, &crc_err2); | |
830 | if (lg_fail(ret)) | |
831 | goto fail; | |
832 | ||
833 | *err = (u16)(((crc_err2 & 0x0f) << 8) | crc_err1); | |
834 | fail: | |
835 | return ret; | |
836 | } | |
837 | ||
838 | static int lg2161_read_crc_err_count(struct lg216x_state *state, u16 *err) | |
839 | { | |
840 | u8 crc_err; | |
841 | int ret; | |
842 | ||
843 | *err = 0; | |
844 | ||
845 | ret = lg216x_read_reg(state, 0x0612, &crc_err); | |
846 | if (lg_fail(ret)) | |
847 | goto fail; | |
848 | ||
849 | *err = (u16)crc_err; | |
850 | fail: | |
851 | return ret; | |
852 | } | |
853 | ||
854 | static int lg216x_read_crc_err_count(struct lg216x_state *state, u16 *err) | |
855 | { | |
856 | int ret; | |
857 | switch (state->cfg->lg_chip) { | |
858 | case LG2160: | |
859 | ret = lg2160_read_crc_err_count(state, err); | |
860 | break; | |
861 | case LG2161: | |
862 | ret = lg2161_read_crc_err_count(state, err); | |
863 | break; | |
864 | default: | |
865 | ret = -EINVAL; | |
866 | break; | |
867 | } | |
868 | return ret; | |
869 | } | |
870 | ||
871 | static int lg2160_read_rs_err_count(struct lg216x_state *state, u16 *err) | |
872 | { | |
873 | u8 rs_err1, rs_err2; | |
874 | int ret; | |
875 | ||
876 | *err = 0; | |
877 | ||
878 | ret = lg216x_read_reg(state, 0x0413, &rs_err1); | |
879 | if (lg_fail(ret)) | |
880 | goto fail; | |
881 | ||
882 | ret = lg216x_read_reg(state, 0x0414, &rs_err2); | |
883 | if (lg_fail(ret)) | |
884 | goto fail; | |
885 | ||
886 | *err = (u16)(((rs_err2 & 0x0f) << 8) | rs_err1); | |
887 | fail: | |
888 | return ret; | |
889 | } | |
890 | ||
891 | static int lg2161_read_rs_err_count(struct lg216x_state *state, u16 *err) | |
892 | { | |
893 | u8 rs_err1, rs_err2; | |
894 | int ret; | |
895 | ||
896 | *err = 0; | |
897 | ||
898 | ret = lg216x_read_reg(state, 0x0613, &rs_err1); | |
899 | if (lg_fail(ret)) | |
900 | goto fail; | |
901 | ||
902 | ret = lg216x_read_reg(state, 0x0614, &rs_err2); | |
903 | if (lg_fail(ret)) | |
904 | goto fail; | |
905 | ||
906 | *err = (u16)((rs_err1 << 8) | rs_err2); | |
907 | fail: | |
908 | return ret; | |
909 | } | |
910 | ||
911 | static int lg216x_read_rs_err_count(struct lg216x_state *state, u16 *err) | |
912 | { | |
913 | int ret; | |
914 | switch (state->cfg->lg_chip) { | |
915 | case LG2160: | |
916 | ret = lg2160_read_rs_err_count(state, err); | |
917 | break; | |
918 | case LG2161: | |
919 | ret = lg2161_read_rs_err_count(state, err); | |
920 | break; | |
921 | default: | |
922 | ret = -EINVAL; | |
923 | break; | |
924 | } | |
925 | return ret; | |
926 | } | |
10d67371 | 927 | #endif |
e26f2ae4 MK |
928 | |
929 | /* ------------------------------------------------------------------------ */ | |
930 | ||
7e3e68bc MCC |
931 | static int lg216x_get_frontend(struct dvb_frontend *fe, |
932 | struct dtv_frontend_properties *c) | |
e26f2ae4 MK |
933 | { |
934 | struct lg216x_state *state = fe->demodulator_priv; | |
935 | int ret; | |
936 | ||
937 | lg_dbg("\n"); | |
938 | ||
7e3e68bc MCC |
939 | c->modulation = VSB_8; |
940 | c->frequency = state->current_frequency; | |
941 | c->delivery_system = SYS_ATSCMH; | |
e26f2ae4 MK |
942 | |
943 | ret = lg216x_get_fic_version(state, | |
7e3e68bc | 944 | &c->atscmh_fic_ver); |
e26f2ae4 MK |
945 | if (lg_fail(ret)) |
946 | goto fail; | |
7e3e68bc MCC |
947 | if (state->fic_ver != c->atscmh_fic_ver) { |
948 | state->fic_ver = c->atscmh_fic_ver; | |
e26f2ae4 MK |
949 | |
950 | #if 0 | |
951 | ret = lg2160_get_parade_id(state, | |
7e3e68bc | 952 | &c->atscmh_parade_id); |
e26f2ae4 MK |
953 | if (lg_fail(ret)) |
954 | goto fail; | |
955 | /* #else */ | |
7e3e68bc | 956 | c->atscmh_parade_id = state->parade_id; |
e26f2ae4 MK |
957 | #endif |
958 | ret = lg216x_get_nog(state, | |
7e3e68bc | 959 | &c->atscmh_nog); |
e26f2ae4 MK |
960 | if (lg_fail(ret)) |
961 | goto fail; | |
962 | ret = lg216x_get_tnog(state, | |
7e3e68bc | 963 | &c->atscmh_tnog); |
e26f2ae4 MK |
964 | if (lg_fail(ret)) |
965 | goto fail; | |
966 | ret = lg216x_get_sgn(state, | |
7e3e68bc | 967 | &c->atscmh_sgn); |
e26f2ae4 MK |
968 | if (lg_fail(ret)) |
969 | goto fail; | |
970 | ret = lg216x_get_prc(state, | |
7e3e68bc | 971 | &c->atscmh_prc); |
e26f2ae4 MK |
972 | if (lg_fail(ret)) |
973 | goto fail; | |
974 | ||
975 | ret = lg216x_get_rs_frame_mode(state, | |
976 | (enum atscmh_rs_frame_mode *) | |
7e3e68bc | 977 | &c->atscmh_rs_frame_mode); |
e26f2ae4 MK |
978 | if (lg_fail(ret)) |
979 | goto fail; | |
980 | ret = lg216x_get_rs_frame_ensemble(state, | |
981 | (enum atscmh_rs_frame_ensemble *) | |
7e3e68bc | 982 | &c->atscmh_rs_frame_ensemble); |
e26f2ae4 MK |
983 | if (lg_fail(ret)) |
984 | goto fail; | |
985 | ret = lg216x_get_rs_code_mode(state, | |
986 | (enum atscmh_rs_code_mode *) | |
7e3e68bc | 987 | &c->atscmh_rs_code_mode_pri, |
e26f2ae4 | 988 | (enum atscmh_rs_code_mode *) |
7e3e68bc | 989 | &c->atscmh_rs_code_mode_sec); |
e26f2ae4 MK |
990 | if (lg_fail(ret)) |
991 | goto fail; | |
992 | ret = lg216x_get_sccc_block_mode(state, | |
993 | (enum atscmh_sccc_block_mode *) | |
7e3e68bc | 994 | &c->atscmh_sccc_block_mode); |
e26f2ae4 MK |
995 | if (lg_fail(ret)) |
996 | goto fail; | |
997 | ret = lg216x_get_sccc_code_mode(state, | |
998 | (enum atscmh_sccc_code_mode *) | |
7e3e68bc | 999 | &c->atscmh_sccc_code_mode_a, |
e26f2ae4 | 1000 | (enum atscmh_sccc_code_mode *) |
7e3e68bc | 1001 | &c->atscmh_sccc_code_mode_b, |
e26f2ae4 | 1002 | (enum atscmh_sccc_code_mode *) |
7e3e68bc | 1003 | &c->atscmh_sccc_code_mode_c, |
e26f2ae4 | 1004 | (enum atscmh_sccc_code_mode *) |
7e3e68bc | 1005 | &c->atscmh_sccc_code_mode_d); |
e26f2ae4 MK |
1006 | if (lg_fail(ret)) |
1007 | goto fail; | |
1008 | } | |
10d67371 | 1009 | #if 0 |
e26f2ae4 | 1010 | ret = lg216x_read_fic_err_count(state, |
7e3e68bc | 1011 | (u8 *)&c->atscmh_fic_err); |
e26f2ae4 MK |
1012 | if (lg_fail(ret)) |
1013 | goto fail; | |
1014 | ret = lg216x_read_crc_err_count(state, | |
7e3e68bc | 1015 | &c->atscmh_crc_err); |
e26f2ae4 MK |
1016 | if (lg_fail(ret)) |
1017 | goto fail; | |
1018 | ret = lg216x_read_rs_err_count(state, | |
7e3e68bc | 1019 | &c->atscmh_rs_err); |
e26f2ae4 MK |
1020 | if (lg_fail(ret)) |
1021 | goto fail; | |
1022 | ||
1023 | switch (state->cfg->lg_chip) { | |
1024 | case LG2160: | |
7e3e68bc MCC |
1025 | if (((c->atscmh_rs_err >= 240) && |
1026 | (c->atscmh_crc_err >= 240)) && | |
e26f2ae4 MK |
1027 | ((jiffies_to_msecs(jiffies) - state->last_reset) > 6000)) |
1028 | ret = lg216x_soft_reset(state); | |
1029 | break; | |
1030 | case LG2161: | |
1031 | /* no fix needed here (as far as we know) */ | |
1032 | ret = 0; | |
1033 | break; | |
1034 | } | |
1035 | lg_fail(ret); | |
10d67371 | 1036 | #endif |
e26f2ae4 MK |
1037 | fail: |
1038 | return ret; | |
1039 | } | |
1040 | ||
e26f2ae4 MK |
1041 | static int lg2160_set_frontend(struct dvb_frontend *fe) |
1042 | { | |
1043 | struct lg216x_state *state = fe->demodulator_priv; | |
7e3e68bc | 1044 | struct dtv_frontend_properties *c = &fe->dtv_property_cache; |
e26f2ae4 MK |
1045 | int ret; |
1046 | ||
1047 | lg_dbg("(%d)\n", fe->dtv_property_cache.frequency); | |
1048 | ||
1049 | if (fe->ops.tuner_ops.set_params) { | |
1050 | ret = fe->ops.tuner_ops.set_params(fe); | |
1051 | if (fe->ops.i2c_gate_ctrl) | |
1052 | fe->ops.i2c_gate_ctrl(fe, 0); | |
1053 | if (lg_fail(ret)) | |
1054 | goto fail; | |
1055 | state->current_frequency = fe->dtv_property_cache.frequency; | |
1056 | } | |
1057 | ||
1058 | ret = lg2160_agc_fix(state, 0, 0); | |
1059 | if (lg_fail(ret)) | |
1060 | goto fail; | |
1061 | ret = lg2160_agc_polarity(state, 0, 0); | |
1062 | if (lg_fail(ret)) | |
1063 | goto fail; | |
1064 | ret = lg2160_tuner_pwr_save_polarity(state, 1); | |
1065 | if (lg_fail(ret)) | |
1066 | goto fail; | |
1067 | ret = lg216x_set_if(state); | |
1068 | if (lg_fail(ret)) | |
1069 | goto fail; | |
1070 | ret = lg2160_spectrum_polarity(state, state->cfg->spectral_inversion); | |
1071 | if (lg_fail(ret)) | |
1072 | goto fail; | |
1073 | ||
1074 | /* be tuned before this point */ | |
1075 | ret = lg216x_soft_reset(state); | |
1076 | if (lg_fail(ret)) | |
1077 | goto fail; | |
1078 | ||
1079 | ret = lg2160_tuner_pwr_save(state, 0); | |
1080 | if (lg_fail(ret)) | |
1081 | goto fail; | |
1082 | ||
1083 | switch (state->cfg->lg_chip) { | |
1084 | case LG2160: | |
1085 | ret = lg2160_set_spi_clock(state); | |
1086 | if (lg_fail(ret)) | |
1087 | goto fail; | |
1088 | break; | |
1089 | case LG2161: | |
1090 | ret = lg2161_set_output_interface(state); | |
1091 | if (lg_fail(ret)) | |
1092 | goto fail; | |
1093 | break; | |
1094 | } | |
1095 | ||
1096 | ret = lg216x_set_parade(state, fe->dtv_property_cache.atscmh_parade_id); | |
1097 | if (lg_fail(ret)) | |
1098 | goto fail; | |
1099 | ||
1100 | ret = lg216x_set_ensemble(state, | |
1101 | fe->dtv_property_cache.atscmh_rs_frame_ensemble); | |
1102 | if (lg_fail(ret)) | |
1103 | goto fail; | |
1104 | ||
1105 | ret = lg216x_initialize(state); | |
1106 | if (lg_fail(ret)) | |
1107 | goto fail; | |
1108 | ||
1109 | ret = lg216x_enable_fic(state, 1); | |
1110 | lg_fail(ret); | |
1111 | ||
7e3e68bc | 1112 | lg216x_get_frontend(fe, c); |
e26f2ae4 MK |
1113 | fail: |
1114 | return ret; | |
1115 | } | |
1116 | ||
1117 | /* ------------------------------------------------------------------------ */ | |
1118 | ||
1119 | static int lg2160_read_lock_status(struct lg216x_state *state, | |
1120 | int *acq_lock, int *sync_lock) | |
1121 | { | |
1122 | u8 val; | |
1123 | int ret; | |
1124 | ||
1125 | *acq_lock = 0; | |
1126 | *sync_lock = 0; | |
1127 | ||
1128 | ret = lg216x_read_reg(state, 0x011b, &val); | |
1129 | if (lg_fail(ret)) | |
1130 | goto fail; | |
1131 | ||
1132 | *sync_lock = (val & 0x20) ? 0 : 1; | |
1133 | *acq_lock = (val & 0x40) ? 0 : 1; | |
1134 | fail: | |
1135 | return ret; | |
1136 | } | |
1137 | ||
1138 | #ifdef USE_LG2161_LOCK_BITS | |
1139 | static int lg2161_read_lock_status(struct lg216x_state *state, | |
1140 | int *acq_lock, int *sync_lock) | |
1141 | { | |
1142 | u8 val; | |
1143 | int ret; | |
1144 | ||
1145 | *acq_lock = 0; | |
1146 | *sync_lock = 0; | |
1147 | ||
1148 | ret = lg216x_read_reg(state, 0x0304, &val); | |
1149 | if (lg_fail(ret)) | |
1150 | goto fail; | |
1151 | ||
1152 | *sync_lock = (val & 0x80) ? 0 : 1; | |
1153 | ||
1154 | ret = lg216x_read_reg(state, 0x011b, &val); | |
1155 | if (lg_fail(ret)) | |
1156 | goto fail; | |
1157 | ||
1158 | *acq_lock = (val & 0x40) ? 0 : 1; | |
1159 | fail: | |
1160 | return ret; | |
1161 | } | |
1162 | #endif | |
1163 | ||
1164 | static int lg216x_read_lock_status(struct lg216x_state *state, | |
1165 | int *acq_lock, int *sync_lock) | |
1166 | { | |
1167 | #ifdef USE_LG2161_LOCK_BITS | |
1168 | int ret; | |
1169 | switch (state->cfg->lg_chip) { | |
1170 | case LG2160: | |
1171 | ret = lg2160_read_lock_status(state, acq_lock, sync_lock); | |
1172 | break; | |
1173 | case LG2161: | |
1174 | ret = lg2161_read_lock_status(state, acq_lock, sync_lock); | |
1175 | break; | |
1176 | default: | |
1177 | ret = -EINVAL; | |
1178 | break; | |
1179 | } | |
1180 | return ret; | |
1181 | #else | |
1182 | return lg2160_read_lock_status(state, acq_lock, sync_lock); | |
1183 | #endif | |
1184 | } | |
1185 | ||
0df289a2 | 1186 | static int lg216x_read_status(struct dvb_frontend *fe, enum fe_status *status) |
e26f2ae4 MK |
1187 | { |
1188 | struct lg216x_state *state = fe->demodulator_priv; | |
1189 | int ret, acq_lock, sync_lock; | |
1190 | ||
1191 | *status = 0; | |
1192 | ||
1193 | ret = lg216x_read_lock_status(state, &acq_lock, &sync_lock); | |
1194 | if (lg_fail(ret)) | |
1195 | goto fail; | |
1196 | ||
1197 | lg_dbg("%s%s\n", | |
1198 | acq_lock ? "SIGNALEXIST " : "", | |
1199 | sync_lock ? "SYNCLOCK" : ""); | |
1200 | ||
1201 | if (acq_lock) | |
1202 | *status |= FE_HAS_SIGNAL; | |
1203 | if (sync_lock) | |
1204 | *status |= FE_HAS_SYNC; | |
1205 | ||
1206 | if (*status) | |
1207 | *status |= FE_HAS_CARRIER | FE_HAS_VITERBI | FE_HAS_LOCK; | |
1208 | ||
1209 | fail: | |
1210 | return ret; | |
1211 | } | |
1212 | ||
1213 | /* ------------------------------------------------------------------------ */ | |
1214 | ||
1215 | static int lg2160_read_snr(struct dvb_frontend *fe, u16 *snr) | |
1216 | { | |
1217 | struct lg216x_state *state = fe->demodulator_priv; | |
1218 | u8 snr1, snr2; | |
1219 | int ret; | |
1220 | ||
1221 | *snr = 0; | |
1222 | ||
1223 | ret = lg216x_read_reg(state, 0x0202, &snr1); | |
1224 | if (lg_fail(ret)) | |
1225 | goto fail; | |
1226 | ||
1227 | ret = lg216x_read_reg(state, 0x0203, &snr2); | |
1228 | if (lg_fail(ret)) | |
1229 | goto fail; | |
1230 | ||
1231 | if ((snr1 == 0xba) || (snr2 == 0xdf)) | |
1232 | *snr = 0; | |
1233 | else | |
1234 | #if 1 | |
1235 | *snr = ((snr1 >> 4) * 100) + ((snr1 & 0x0f) * 10) + (snr2 >> 4); | |
1236 | #else /* BCD */ | |
1237 | *snr = (snr2 | (snr1 << 8)); | |
1238 | #endif | |
1239 | fail: | |
1240 | return ret; | |
1241 | } | |
1242 | ||
1243 | static int lg2161_read_snr(struct dvb_frontend *fe, u16 *snr) | |
1244 | { | |
1245 | struct lg216x_state *state = fe->demodulator_priv; | |
1246 | u8 snr1, snr2; | |
1247 | int ret; | |
1248 | ||
1249 | *snr = 0; | |
1250 | ||
1251 | ret = lg216x_read_reg(state, 0x0302, &snr1); | |
1252 | if (lg_fail(ret)) | |
1253 | goto fail; | |
1254 | ||
1255 | ret = lg216x_read_reg(state, 0x0303, &snr2); | |
1256 | if (lg_fail(ret)) | |
1257 | goto fail; | |
1258 | ||
1259 | if ((snr1 == 0xba) || (snr2 == 0xfd)) | |
1260 | *snr = 0; | |
1261 | else | |
1262 | ||
1263 | *snr = ((snr1 >> 4) * 100) + ((snr1 & 0x0f) * 10) + (snr2 & 0x0f); | |
1264 | fail: | |
1265 | return ret; | |
1266 | } | |
1267 | ||
1268 | static int lg216x_read_signal_strength(struct dvb_frontend *fe, | |
1269 | u16 *strength) | |
1270 | { | |
1271 | #if 0 | |
1272 | /* borrowed from lgdt330x.c | |
1273 | * | |
1274 | * Calculate strength from SNR up to 35dB | |
1275 | * Even though the SNR can go higher than 35dB, | |
1276 | * there is some comfort factor in having a range of | |
1277 | * strong signals that can show at 100% | |
1278 | */ | |
1279 | struct lg216x_state *state = fe->demodulator_priv; | |
1280 | u16 snr; | |
1281 | int ret; | |
1282 | #endif | |
1283 | *strength = 0; | |
1284 | #if 0 | |
1285 | ret = fe->ops.read_snr(fe, &snr); | |
1286 | if (lg_fail(ret)) | |
1287 | goto fail; | |
1288 | /* Rather than use the 8.8 value snr, use state->snr which is 8.24 */ | |
1289 | /* scale the range 0 - 35*2^24 into 0 - 65535 */ | |
1290 | if (state->snr >= 8960 * 0x10000) | |
1291 | *strength = 0xffff; | |
1292 | else | |
1293 | *strength = state->snr / 8960; | |
1294 | fail: | |
1295 | return ret; | |
1296 | #else | |
1297 | return 0; | |
1298 | #endif | |
1299 | } | |
1300 | ||
1301 | /* ------------------------------------------------------------------------ */ | |
1302 | ||
1303 | static int lg216x_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks) | |
1304 | { | |
5444a1b7 | 1305 | #if 0 |
e26f2ae4 MK |
1306 | struct lg216x_state *state = fe->demodulator_priv; |
1307 | int ret; | |
5444a1b7 | 1308 | |
e26f2ae4 MK |
1309 | ret = lg216x_read_rs_err_count(state, |
1310 | &fe->dtv_property_cache.atscmh_rs_err); | |
1311 | if (lg_fail(ret)) | |
1312 | goto fail; | |
1313 | ||
1314 | *ucblocks = fe->dtv_property_cache.atscmh_rs_err; | |
5444a1b7 | 1315 | fail: |
10d67371 MK |
1316 | #else |
1317 | *ucblocks = 0; | |
1318 | #endif | |
e26f2ae4 MK |
1319 | return 0; |
1320 | } | |
1321 | ||
1322 | static int lg216x_get_tune_settings(struct dvb_frontend *fe, | |
1323 | struct dvb_frontend_tune_settings | |
1324 | *fe_tune_settings) | |
1325 | { | |
1326 | fe_tune_settings->min_delay_ms = 500; | |
1327 | lg_dbg("\n"); | |
1328 | return 0; | |
1329 | } | |
1330 | ||
1331 | static void lg216x_release(struct dvb_frontend *fe) | |
1332 | { | |
1333 | struct lg216x_state *state = fe->demodulator_priv; | |
1334 | lg_dbg("\n"); | |
1335 | kfree(state); | |
1336 | } | |
1337 | ||
bd336e63 | 1338 | static const struct dvb_frontend_ops lg2160_ops = { |
e26f2ae4 MK |
1339 | .delsys = { SYS_ATSCMH }, |
1340 | .info = { | |
1341 | .name = "LG Electronics LG2160 ATSC/MH Frontend", | |
f1b1eabf MCC |
1342 | .frequency_min_hz = 54 * MHz, |
1343 | .frequency_max_hz = 858 * MHz, | |
1344 | .frequency_stepsize_hz = 62500, | |
e26f2ae4 MK |
1345 | }, |
1346 | .i2c_gate_ctrl = lg216x_i2c_gate_ctrl, | |
1347 | #if 0 | |
1348 | .init = lg216x_init, | |
1349 | .sleep = lg216x_sleep, | |
1350 | #endif | |
e26f2ae4 MK |
1351 | .set_frontend = lg2160_set_frontend, |
1352 | .get_frontend = lg216x_get_frontend, | |
1353 | .get_tune_settings = lg216x_get_tune_settings, | |
1354 | .read_status = lg216x_read_status, | |
1355 | #if 0 | |
1356 | .read_ber = lg216x_read_ber, | |
1357 | #endif | |
1358 | .read_signal_strength = lg216x_read_signal_strength, | |
1359 | .read_snr = lg2160_read_snr, | |
1360 | .read_ucblocks = lg216x_read_ucblocks, | |
1361 | .release = lg216x_release, | |
1362 | }; | |
1363 | ||
bd336e63 | 1364 | static const struct dvb_frontend_ops lg2161_ops = { |
e26f2ae4 MK |
1365 | .delsys = { SYS_ATSCMH }, |
1366 | .info = { | |
1367 | .name = "LG Electronics LG2161 ATSC/MH Frontend", | |
f1b1eabf MCC |
1368 | .frequency_min_hz = 54 * MHz, |
1369 | .frequency_max_hz = 858 * MHz, | |
1370 | .frequency_stepsize_hz = 62500, | |
e26f2ae4 MK |
1371 | }, |
1372 | .i2c_gate_ctrl = lg216x_i2c_gate_ctrl, | |
1373 | #if 0 | |
1374 | .init = lg216x_init, | |
1375 | .sleep = lg216x_sleep, | |
1376 | #endif | |
e26f2ae4 MK |
1377 | .set_frontend = lg2160_set_frontend, |
1378 | .get_frontend = lg216x_get_frontend, | |
1379 | .get_tune_settings = lg216x_get_tune_settings, | |
1380 | .read_status = lg216x_read_status, | |
1381 | #if 0 | |
1382 | .read_ber = lg216x_read_ber, | |
1383 | #endif | |
1384 | .read_signal_strength = lg216x_read_signal_strength, | |
1385 | .read_snr = lg2161_read_snr, | |
1386 | .read_ucblocks = lg216x_read_ucblocks, | |
1387 | .release = lg216x_release, | |
1388 | }; | |
1389 | ||
1390 | struct dvb_frontend *lg2160_attach(const struct lg2160_config *config, | |
1391 | struct i2c_adapter *i2c_adap) | |
1392 | { | |
1393 | struct lg216x_state *state = NULL; | |
1394 | ||
1395 | lg_dbg("(%d-%04x)\n", | |
1396 | i2c_adap ? i2c_adapter_id(i2c_adap) : 0, | |
1397 | config ? config->i2c_addr : 0); | |
1398 | ||
1399 | state = kzalloc(sizeof(struct lg216x_state), GFP_KERNEL); | |
1a5d2da1 PST |
1400 | if (!state) |
1401 | return NULL; | |
e26f2ae4 MK |
1402 | |
1403 | state->cfg = config; | |
1404 | state->i2c_adap = i2c_adap; | |
1405 | state->fic_ver = 0xff; | |
1406 | state->parade_id = 0xff; | |
1407 | ||
1408 | switch (config->lg_chip) { | |
1409 | default: | |
1410 | lg_warn("invalid chip requested, defaulting to LG2160"); | |
1411 | /* fall-thru */ | |
1412 | case LG2160: | |
1413 | memcpy(&state->frontend.ops, &lg2160_ops, | |
1414 | sizeof(struct dvb_frontend_ops)); | |
1415 | break; | |
1416 | case LG2161: | |
1417 | memcpy(&state->frontend.ops, &lg2161_ops, | |
1418 | sizeof(struct dvb_frontend_ops)); | |
1419 | break; | |
1420 | } | |
1421 | ||
1422 | state->frontend.demodulator_priv = state; | |
1423 | state->current_frequency = -1; | |
1424 | /* parade 1 by default */ | |
1425 | state->frontend.dtv_property_cache.atscmh_parade_id = 1; | |
1426 | ||
1427 | return &state->frontend; | |
e26f2ae4 MK |
1428 | } |
1429 | EXPORT_SYMBOL(lg2160_attach); | |
1430 | ||
1431 | MODULE_DESCRIPTION("LG Electronics LG216x ATSC/MH Demodulator Driver"); | |
1432 | MODULE_AUTHOR("Michael Krufky <mkrufky@linuxtv.org>"); | |
1433 | MODULE_LICENSE("GPL"); | |
1434 | MODULE_VERSION("0.3"); |