1 | // SPDX-License-Identifier: GPL-2.0-or-later |
2 | /* |
3 | * Support for LG2160 - ATSC/MH |
4 | * |
5 | * Copyright (C) 2010 Michael Krufky <mkrufky@linuxtv.org> |
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(adap: state->i2c_adap, msgs: &msg, num: 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(adap: state->i2c_adap, msgs: msg, num: 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 | |
115 | for (i = 0; i < len; i++) { |
116 | ret = lg216x_write_reg(state, reg: regs[i].reg, val: 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: &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, reg: 0x0000, bit: 0, onoff: enable ? 0 : 1); |
157 | |
158 | msleep(msecs: 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, reg: 0x0002, val: 0x00); |
170 | if (lg_fail(ret)) |
171 | goto fail; |
172 | |
173 | msleep(msecs: 20); |
174 | ret = lg216x_write_reg(state, reg: 0x0002, val: 0x01); |
175 | if (lg_fail(ret)) |
176 | goto fail; |
177 | |
178 | state->last_reset = jiffies_to_msecs(j: 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 | regs: lg2160_init, ARRAY_SIZE(lg2160_init)); |
216 | break; |
217 | case LG2161: |
218 | ret = lg216x_write_regs(state, |
219 | regs: 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, reg: 0x0132, val: &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, reg: 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, reg: 0x0100, val: &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, reg: 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, reg: 0x0100, val: &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, reg: 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, reg: 0x0008, val: &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, reg: 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, reg: 0x0132, val: &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, reg: 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, reg: 0x0007, val: &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, reg: 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, reg: 0x013e, val: 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: |
402 | default: |
403 | reg = 0x0500; |
404 | break; |
405 | } |
406 | |
407 | ret = lg216x_read_reg(state, reg, val: &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, reg: 0x0014, val: &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, reg: 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, reg: 0x0014, val: &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, reg: 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, reg: 0x0017, val: 0x23); |
461 | if (lg_fail(ret)) |
462 | goto fail; |
463 | |
464 | ret = lg216x_write_reg(state, reg: 0x0016, val: 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, reg: 0x0016, |
471 | val: 0xfc | ((onoff) ? 0x02 : 0x00)); |
472 | break; |
473 | case LG2161: |
474 | ret = lg216x_write_reg(state, reg: 0x0016, val: (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, reg: 0x0017, val: 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, reg: 0x0128, val: &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, reg: 0x0124, val: &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, reg: 0x0125, val: &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, reg: 0x0124, val: &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, reg: 0x0125, val: &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, reg: 0x0410, val: &val); |
603 | break; |
604 | case LG2161: |
605 | ret = lg216x_read_reg(state, reg: 0x0513, val: &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, reg: 0x0400, val: &val); |
643 | break; |
644 | case LG2161: |
645 | ret = lg216x_read_reg(state, reg: 0x0500, val: &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, reg: 0x0410, val: &val); |
669 | break; |
670 | case LG2161: |
671 | ret = lg216x_read_reg(state, reg: 0x0513, val: &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, reg: 0x0315, val: &val); |
694 | break; |
695 | case LG2161: |
696 | ret = lg216x_read_reg(state, reg: 0x0511, val: &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, reg: 0x0316, val: &val); |
731 | break; |
732 | case LG2161: |
733 | ret = lg216x_read_reg(state, reg: 0x0512, val: &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 | |
794 | #if 0 |
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 | } |
927 | #endif |
928 | |
929 | /* ------------------------------------------------------------------------ */ |
930 | |
931 | static int lg216x_get_frontend(struct dvb_frontend *fe, |
932 | struct dtv_frontend_properties *c) |
933 | { |
934 | struct lg216x_state *state = fe->demodulator_priv; |
935 | int ret; |
936 | |
937 | lg_dbg("\n" ); |
938 | |
939 | c->modulation = VSB_8; |
940 | c->frequency = state->current_frequency; |
941 | c->delivery_system = SYS_ATSCMH; |
942 | |
943 | ret = lg216x_get_fic_version(state, |
944 | ficver: &c->atscmh_fic_ver); |
945 | if (lg_fail(ret)) |
946 | goto fail; |
947 | if (state->fic_ver != c->atscmh_fic_ver) { |
948 | state->fic_ver = c->atscmh_fic_ver; |
949 | |
950 | #if 0 |
951 | ret = lg2160_get_parade_id(state, |
952 | &c->atscmh_parade_id); |
953 | if (lg_fail(ret)) |
954 | goto fail; |
955 | /* #else */ |
956 | c->atscmh_parade_id = state->parade_id; |
957 | #endif |
958 | ret = lg216x_get_nog(state, |
959 | nog: &c->atscmh_nog); |
960 | if (lg_fail(ret)) |
961 | goto fail; |
962 | ret = lg216x_get_tnog(state, |
963 | tnog: &c->atscmh_tnog); |
964 | if (lg_fail(ret)) |
965 | goto fail; |
966 | ret = lg216x_get_sgn(state, |
967 | sgn: &c->atscmh_sgn); |
968 | if (lg_fail(ret)) |
969 | goto fail; |
970 | ret = lg216x_get_prc(state, |
971 | prc: &c->atscmh_prc); |
972 | if (lg_fail(ret)) |
973 | goto fail; |
974 | |
975 | ret = lg216x_get_rs_frame_mode(state, |
976 | rs_framemode: (enum atscmh_rs_frame_mode *) |
977 | &c->atscmh_rs_frame_mode); |
978 | if (lg_fail(ret)) |
979 | goto fail; |
980 | ret = lg216x_get_rs_frame_ensemble(state, |
981 | rs_frame_ens: (enum atscmh_rs_frame_ensemble *) |
982 | &c->atscmh_rs_frame_ensemble); |
983 | if (lg_fail(ret)) |
984 | goto fail; |
985 | ret = lg216x_get_rs_code_mode(state, |
986 | rs_code_pri: (enum atscmh_rs_code_mode *) |
987 | &c->atscmh_rs_code_mode_pri, |
988 | rs_code_sec: (enum atscmh_rs_code_mode *) |
989 | &c->atscmh_rs_code_mode_sec); |
990 | if (lg_fail(ret)) |
991 | goto fail; |
992 | ret = lg216x_get_sccc_block_mode(state, |
993 | sccc_block: (enum atscmh_sccc_block_mode *) |
994 | &c->atscmh_sccc_block_mode); |
995 | if (lg_fail(ret)) |
996 | goto fail; |
997 | ret = lg216x_get_sccc_code_mode(state, |
998 | mode_a: (enum atscmh_sccc_code_mode *) |
999 | &c->atscmh_sccc_code_mode_a, |
1000 | mode_b: (enum atscmh_sccc_code_mode *) |
1001 | &c->atscmh_sccc_code_mode_b, |
1002 | mode_c: (enum atscmh_sccc_code_mode *) |
1003 | &c->atscmh_sccc_code_mode_c, |
1004 | mode_d: (enum atscmh_sccc_code_mode *) |
1005 | &c->atscmh_sccc_code_mode_d); |
1006 | if (lg_fail(ret)) |
1007 | goto fail; |
1008 | } |
1009 | #if 0 |
1010 | ret = lg216x_read_fic_err_count(state, |
1011 | (u8 *)&c->atscmh_fic_err); |
1012 | if (lg_fail(ret)) |
1013 | goto fail; |
1014 | ret = lg216x_read_crc_err_count(state, |
1015 | &c->atscmh_crc_err); |
1016 | if (lg_fail(ret)) |
1017 | goto fail; |
1018 | ret = lg216x_read_rs_err_count(state, |
1019 | &c->atscmh_rs_err); |
1020 | if (lg_fail(ret)) |
1021 | goto fail; |
1022 | |
1023 | switch (state->cfg->lg_chip) { |
1024 | case LG2160: |
1025 | if (((c->atscmh_rs_err >= 240) && |
1026 | (c->atscmh_crc_err >= 240)) && |
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); |
1036 | #endif |
1037 | fail: |
1038 | return ret; |
1039 | } |
1040 | |
1041 | static int lg2160_set_frontend(struct dvb_frontend *fe) |
1042 | { |
1043 | struct lg216x_state *state = fe->demodulator_priv; |
1044 | struct dtv_frontend_properties *c = &fe->dtv_property_cache; |
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, if_agc_fix: 0, rf_agc_fix: 0); |
1059 | if (lg_fail(ret)) |
1060 | goto fail; |
1061 | ret = lg2160_agc_polarity(state, if_agc_polarity: 0, rf_agc_polarity: 0); |
1062 | if (lg_fail(ret)) |
1063 | goto fail; |
1064 | ret = lg2160_tuner_pwr_save_polarity(state, polarity: 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, inverted: 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, onoff: 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, id: fe->dtv_property_cache.atscmh_parade_id); |
1097 | if (lg_fail(ret)) |
1098 | goto fail; |
1099 | |
1100 | ret = lg216x_set_ensemble(state, |
1101 | id: 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, onoff: 1); |
1110 | lg_fail(ret); |
1111 | |
1112 | lg216x_get_frontend(fe, c); |
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, reg: 0x011b, val: &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 | |
1186 | static int lg216x_read_status(struct dvb_frontend *fe, enum fe_status *status) |
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: &acq_lock, sync_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, reg: 0x0202, val: &snr1); |
1224 | if (lg_fail(ret)) |
1225 | goto fail; |
1226 | |
1227 | ret = lg216x_read_reg(state, reg: 0x0203, val: &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, reg: 0x0302, val: &snr1); |
1252 | if (lg_fail(ret)) |
1253 | goto fail; |
1254 | |
1255 | ret = lg216x_read_reg(state, reg: 0x0303, val: &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 | { |
1305 | #if 0 |
1306 | struct lg216x_state *state = fe->demodulator_priv; |
1307 | int ret; |
1308 | |
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; |
1315 | fail: |
1316 | #else |
1317 | *ucblocks = 0; |
1318 | #endif |
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(objp: state); |
1336 | } |
1337 | |
1338 | static const struct dvb_frontend_ops lg2160_ops = { |
1339 | .delsys = { SYS_ATSCMH }, |
1340 | .info = { |
1341 | .name = "LG Electronics LG2160 ATSC/MH Frontend" , |
1342 | .frequency_min_hz = 54 * MHz, |
1343 | .frequency_max_hz = 858 * MHz, |
1344 | .frequency_stepsize_hz = 62500, |
1345 | }, |
1346 | .i2c_gate_ctrl = lg216x_i2c_gate_ctrl, |
1347 | #if 0 |
1348 | .init = lg216x_init, |
1349 | .sleep = lg216x_sleep, |
1350 | #endif |
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 | |
1364 | static const struct dvb_frontend_ops lg2161_ops = { |
1365 | .delsys = { SYS_ATSCMH }, |
1366 | .info = { |
1367 | .name = "LG Electronics LG2161 ATSC/MH Frontend" , |
1368 | .frequency_min_hz = 54 * MHz, |
1369 | .frequency_max_hz = 858 * MHz, |
1370 | .frequency_stepsize_hz = 62500, |
1371 | }, |
1372 | .i2c_gate_ctrl = lg216x_i2c_gate_ctrl, |
1373 | #if 0 |
1374 | .init = lg216x_init, |
1375 | .sleep = lg216x_sleep, |
1376 | #endif |
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(size: sizeof(struct lg216x_state), GFP_KERNEL); |
1400 | if (!state) |
1401 | return NULL; |
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 | fallthrough; |
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; |
1428 | } |
1429 | EXPORT_SYMBOL_GPL(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" ); |
1435 | |