diff options
Diffstat (limited to 'drivers/media/dvb/frontends/rtl2830.c')
-rw-r--r-- | drivers/media/dvb/frontends/rtl2830.c | 201 |
1 files changed, 198 insertions, 3 deletions
diff --git a/drivers/media/dvb/frontends/rtl2830.c b/drivers/media/dvb/frontends/rtl2830.c index 45196c5b0736..93612ebac519 100644 --- a/drivers/media/dvb/frontends/rtl2830.c +++ b/drivers/media/dvb/frontends/rtl2830.c | |||
@@ -374,6 +374,118 @@ err: | |||
374 | return ret; | 374 | return ret; |
375 | } | 375 | } |
376 | 376 | ||
377 | static int rtl2830_get_frontend(struct dvb_frontend *fe) | ||
378 | { | ||
379 | struct rtl2830_priv *priv = fe->demodulator_priv; | ||
380 | struct dtv_frontend_properties *c = &fe->dtv_property_cache; | ||
381 | int ret; | ||
382 | u8 buf[3]; | ||
383 | |||
384 | if (priv->sleeping) | ||
385 | return 0; | ||
386 | |||
387 | ret = rtl2830_rd_regs(priv, 0x33c, buf, 2); | ||
388 | if (ret) | ||
389 | goto err; | ||
390 | |||
391 | ret = rtl2830_rd_reg(priv, 0x351, &buf[2]); | ||
392 | if (ret) | ||
393 | goto err; | ||
394 | |||
395 | dbg("%s: TPS=%02x %02x %02x", __func__, buf[0], buf[1], buf[2]); | ||
396 | |||
397 | switch ((buf[0] >> 2) & 3) { | ||
398 | case 0: | ||
399 | c->modulation = QPSK; | ||
400 | break; | ||
401 | case 1: | ||
402 | c->modulation = QAM_16; | ||
403 | break; | ||
404 | case 2: | ||
405 | c->modulation = QAM_64; | ||
406 | break; | ||
407 | } | ||
408 | |||
409 | switch ((buf[2] >> 2) & 1) { | ||
410 | case 0: | ||
411 | c->transmission_mode = TRANSMISSION_MODE_2K; | ||
412 | break; | ||
413 | case 1: | ||
414 | c->transmission_mode = TRANSMISSION_MODE_8K; | ||
415 | } | ||
416 | |||
417 | switch ((buf[2] >> 0) & 3) { | ||
418 | case 0: | ||
419 | c->guard_interval = GUARD_INTERVAL_1_32; | ||
420 | break; | ||
421 | case 1: | ||
422 | c->guard_interval = GUARD_INTERVAL_1_16; | ||
423 | break; | ||
424 | case 2: | ||
425 | c->guard_interval = GUARD_INTERVAL_1_8; | ||
426 | break; | ||
427 | case 3: | ||
428 | c->guard_interval = GUARD_INTERVAL_1_4; | ||
429 | break; | ||
430 | } | ||
431 | |||
432 | switch ((buf[0] >> 4) & 7) { | ||
433 | case 0: | ||
434 | c->hierarchy = HIERARCHY_NONE; | ||
435 | break; | ||
436 | case 1: | ||
437 | c->hierarchy = HIERARCHY_1; | ||
438 | break; | ||
439 | case 2: | ||
440 | c->hierarchy = HIERARCHY_2; | ||
441 | break; | ||
442 | case 3: | ||
443 | c->hierarchy = HIERARCHY_4; | ||
444 | break; | ||
445 | } | ||
446 | |||
447 | switch ((buf[1] >> 3) & 7) { | ||
448 | case 0: | ||
449 | c->code_rate_HP = FEC_1_2; | ||
450 | break; | ||
451 | case 1: | ||
452 | c->code_rate_HP = FEC_2_3; | ||
453 | break; | ||
454 | case 2: | ||
455 | c->code_rate_HP = FEC_3_4; | ||
456 | break; | ||
457 | case 3: | ||
458 | c->code_rate_HP = FEC_5_6; | ||
459 | break; | ||
460 | case 4: | ||
461 | c->code_rate_HP = FEC_7_8; | ||
462 | break; | ||
463 | } | ||
464 | |||
465 | switch ((buf[1] >> 0) & 7) { | ||
466 | case 0: | ||
467 | c->code_rate_LP = FEC_1_2; | ||
468 | break; | ||
469 | case 1: | ||
470 | c->code_rate_LP = FEC_2_3; | ||
471 | break; | ||
472 | case 2: | ||
473 | c->code_rate_LP = FEC_3_4; | ||
474 | break; | ||
475 | case 3: | ||
476 | c->code_rate_LP = FEC_5_6; | ||
477 | break; | ||
478 | case 4: | ||
479 | c->code_rate_LP = FEC_7_8; | ||
480 | break; | ||
481 | } | ||
482 | |||
483 | return 0; | ||
484 | err: | ||
485 | dbg("%s: failed=%d", __func__, ret); | ||
486 | return ret; | ||
487 | } | ||
488 | |||
377 | static int rtl2830_read_status(struct dvb_frontend *fe, fe_status_t *status) | 489 | static int rtl2830_read_status(struct dvb_frontend *fe, fe_status_t *status) |
378 | { | 490 | { |
379 | struct rtl2830_priv *priv = fe->demodulator_priv; | 491 | struct rtl2830_priv *priv = fe->demodulator_priv; |
@@ -404,14 +516,72 @@ err: | |||
404 | 516 | ||
405 | static int rtl2830_read_snr(struct dvb_frontend *fe, u16 *snr) | 517 | static int rtl2830_read_snr(struct dvb_frontend *fe, u16 *snr) |
406 | { | 518 | { |
407 | *snr = 0; | 519 | struct rtl2830_priv *priv = fe->demodulator_priv; |
520 | int ret, hierarchy, constellation; | ||
521 | u8 buf[2], tmp; | ||
522 | u16 tmp16; | ||
523 | #define CONSTELLATION_NUM 3 | ||
524 | #define HIERARCHY_NUM 4 | ||
525 | static const u32 snr_constant[CONSTELLATION_NUM][HIERARCHY_NUM] = { | ||
526 | { 70705899, 70705899, 70705899, 70705899 }, | ||
527 | { 82433173, 82433173, 87483115, 94445660 }, | ||
528 | { 92888734, 92888734, 95487525, 99770748 }, | ||
529 | }; | ||
530 | |||
531 | if (priv->sleeping) | ||
532 | return 0; | ||
533 | |||
534 | /* reports SNR in resolution of 0.1 dB */ | ||
535 | |||
536 | ret = rtl2830_rd_reg(priv, 0x33c, &tmp); | ||
537 | if (ret) | ||
538 | goto err; | ||
539 | |||
540 | constellation = (tmp >> 2) & 0x03; /* [3:2] */ | ||
541 | if (constellation > CONSTELLATION_NUM - 1) | ||
542 | goto err; | ||
543 | |||
544 | hierarchy = (tmp >> 4) & 0x07; /* [6:4] */ | ||
545 | if (hierarchy > HIERARCHY_NUM - 1) | ||
546 | goto err; | ||
547 | |||
548 | ret = rtl2830_rd_regs(priv, 0x40c, buf, 2); | ||
549 | if (ret) | ||
550 | goto err; | ||
551 | |||
552 | tmp16 = buf[0] << 8 | buf[1]; | ||
553 | |||
554 | if (tmp16) | ||
555 | *snr = (snr_constant[constellation][hierarchy] - | ||
556 | intlog10(tmp16)) / ((1 << 24) / 100); | ||
557 | else | ||
558 | *snr = 0; | ||
559 | |||
408 | return 0; | 560 | return 0; |
561 | err: | ||
562 | dbg("%s: failed=%d", __func__, ret); | ||
563 | return ret; | ||
409 | } | 564 | } |
410 | 565 | ||
411 | static int rtl2830_read_ber(struct dvb_frontend *fe, u32 *ber) | 566 | static int rtl2830_read_ber(struct dvb_frontend *fe, u32 *ber) |
412 | { | 567 | { |
413 | *ber = 0; | 568 | struct rtl2830_priv *priv = fe->demodulator_priv; |
569 | int ret; | ||
570 | u8 buf[2]; | ||
571 | |||
572 | if (priv->sleeping) | ||
573 | return 0; | ||
574 | |||
575 | ret = rtl2830_rd_regs(priv, 0x34e, buf, 2); | ||
576 | if (ret) | ||
577 | goto err; | ||
578 | |||
579 | *ber = buf[0] << 8 | buf[1]; | ||
580 | |||
414 | return 0; | 581 | return 0; |
582 | err: | ||
583 | dbg("%s: failed=%d", __func__, ret); | ||
584 | return ret; | ||
415 | } | 585 | } |
416 | 586 | ||
417 | static int rtl2830_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks) | 587 | static int rtl2830_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks) |
@@ -422,8 +592,32 @@ static int rtl2830_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks) | |||
422 | 592 | ||
423 | static int rtl2830_read_signal_strength(struct dvb_frontend *fe, u16 *strength) | 593 | static int rtl2830_read_signal_strength(struct dvb_frontend *fe, u16 *strength) |
424 | { | 594 | { |
425 | *strength = 0; | 595 | struct rtl2830_priv *priv = fe->demodulator_priv; |
596 | int ret; | ||
597 | u8 buf[2]; | ||
598 | u16 if_agc_raw, if_agc; | ||
599 | |||
600 | if (priv->sleeping) | ||
601 | return 0; | ||
602 | |||
603 | ret = rtl2830_rd_regs(priv, 0x359, buf, 2); | ||
604 | if (ret) | ||
605 | goto err; | ||
606 | |||
607 | if_agc_raw = (buf[0] << 8 | buf[1]) & 0x3fff; | ||
608 | |||
609 | if (if_agc_raw & (1 << 9)) | ||
610 | if_agc = -(~(if_agc_raw - 1) & 0x1ff); | ||
611 | else | ||
612 | if_agc = if_agc_raw; | ||
613 | |||
614 | *strength = (u8) (55 - if_agc / 182); | ||
615 | *strength |= *strength << 8; | ||
616 | |||
426 | return 0; | 617 | return 0; |
618 | err: | ||
619 | dbg("%s: failed=%d", __func__, ret); | ||
620 | return ret; | ||
427 | } | 621 | } |
428 | 622 | ||
429 | static struct dvb_frontend_ops rtl2830_ops; | 623 | static struct dvb_frontend_ops rtl2830_ops; |
@@ -549,6 +743,7 @@ static struct dvb_frontend_ops rtl2830_ops = { | |||
549 | .get_tune_settings = rtl2830_get_tune_settings, | 743 | .get_tune_settings = rtl2830_get_tune_settings, |
550 | 744 | ||
551 | .set_frontend = rtl2830_set_frontend, | 745 | .set_frontend = rtl2830_set_frontend, |
746 | .get_frontend = rtl2830_get_frontend, | ||
552 | 747 | ||
553 | .read_status = rtl2830_read_status, | 748 | .read_status = rtl2830_read_status, |
554 | .read_snr = rtl2830_read_snr, | 749 | .read_snr = rtl2830_read_snr, |