diff options
author | Mauro Carvalho Chehab <mchehab@redhat.com> | 2012-01-09 15:16:36 -0500 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@redhat.com> | 2012-01-10 19:35:29 -0500 |
commit | 959a119f86d51085ba4e0ec5a68dee6a21c48dfe (patch) | |
tree | 5979a70ccefc685ebfc5535306874b7d7376a54e /drivers/media/dvb/frontends/mb86a20s.c | |
parent | 90bf3aab42937f760e5b645ab63df46d26b5e620 (diff) |
[media] mb86a20s: implement get_frontend()
Reports the auto-detected parameters to userspace.
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
Diffstat (limited to 'drivers/media/dvb/frontends/mb86a20s.c')
-rw-r--r-- | drivers/media/dvb/frontends/mb86a20s.c | 196 |
1 files changed, 193 insertions, 3 deletions
diff --git a/drivers/media/dvb/frontends/mb86a20s.c b/drivers/media/dvb/frontends/mb86a20s.c index 82d3301a1c18..38778a87702e 100644 --- a/drivers/media/dvb/frontends/mb86a20s.c +++ b/drivers/media/dvb/frontends/mb86a20s.c | |||
@@ -525,16 +525,206 @@ static int mb86a20s_set_frontend(struct dvb_frontend *fe) | |||
525 | return rc; | 525 | return rc; |
526 | } | 526 | } |
527 | 527 | ||
528 | static int mb86a20s_get_modulation(struct mb86a20s_state *state, | ||
529 | unsigned layer) | ||
530 | { | ||
531 | int rc; | ||
532 | static unsigned char reg[] = { | ||
533 | [0] = 0x86, /* Layer A */ | ||
534 | [1] = 0x8a, /* Layer B */ | ||
535 | [2] = 0x8e, /* Layer C */ | ||
536 | }; | ||
537 | |||
538 | if (layer > ARRAY_SIZE(reg)) | ||
539 | return -EINVAL; | ||
540 | rc = mb86a20s_writereg(state, 0x6d, reg[layer]); | ||
541 | if (rc < 0) | ||
542 | return rc; | ||
543 | rc = mb86a20s_readreg(state, 0x6e); | ||
544 | if (rc < 0) | ||
545 | return rc; | ||
546 | switch ((rc & 0x70) >> 4) { | ||
547 | case 0: | ||
548 | return DQPSK; | ||
549 | case 1: | ||
550 | return QPSK; | ||
551 | case 2: | ||
552 | return QAM_16; | ||
553 | case 3: | ||
554 | return QAM_64; | ||
555 | default: | ||
556 | return QAM_AUTO; | ||
557 | } | ||
558 | } | ||
559 | |||
560 | static int mb86a20s_get_fec(struct mb86a20s_state *state, | ||
561 | unsigned layer) | ||
562 | { | ||
563 | int rc; | ||
564 | |||
565 | static unsigned char reg[] = { | ||
566 | [0] = 0x87, /* Layer A */ | ||
567 | [1] = 0x8b, /* Layer B */ | ||
568 | [2] = 0x8f, /* Layer C */ | ||
569 | }; | ||
570 | |||
571 | if (layer > ARRAY_SIZE(reg)) | ||
572 | return -EINVAL; | ||
573 | rc = mb86a20s_writereg(state, 0x6d, reg[layer]); | ||
574 | if (rc < 0) | ||
575 | return rc; | ||
576 | rc = mb86a20s_readreg(state, 0x6e); | ||
577 | if (rc < 0) | ||
578 | return rc; | ||
579 | switch (rc) { | ||
580 | case 0: | ||
581 | return FEC_1_2; | ||
582 | case 1: | ||
583 | return FEC_2_3; | ||
584 | case 2: | ||
585 | return FEC_3_4; | ||
586 | case 3: | ||
587 | return FEC_5_6; | ||
588 | case 4: | ||
589 | return FEC_7_8; | ||
590 | default: | ||
591 | return FEC_AUTO; | ||
592 | } | ||
593 | } | ||
594 | |||
595 | static int mb86a20s_get_interleaving(struct mb86a20s_state *state, | ||
596 | unsigned layer) | ||
597 | { | ||
598 | int rc; | ||
599 | |||
600 | static unsigned char reg[] = { | ||
601 | [0] = 0x88, /* Layer A */ | ||
602 | [1] = 0x8c, /* Layer B */ | ||
603 | [2] = 0x90, /* Layer C */ | ||
604 | }; | ||
605 | |||
606 | if (layer > ARRAY_SIZE(reg)) | ||
607 | return -EINVAL; | ||
608 | rc = mb86a20s_writereg(state, 0x6d, reg[layer]); | ||
609 | if (rc < 0) | ||
610 | return rc; | ||
611 | rc = mb86a20s_readreg(state, 0x6e); | ||
612 | if (rc < 0) | ||
613 | return rc; | ||
614 | if (rc > 3) | ||
615 | return -EINVAL; /* Not used */ | ||
616 | return rc; | ||
617 | } | ||
618 | |||
619 | static int mb86a20s_get_segment_count(struct mb86a20s_state *state, | ||
620 | unsigned layer) | ||
621 | { | ||
622 | int rc, count; | ||
623 | |||
624 | static unsigned char reg[] = { | ||
625 | [0] = 0x89, /* Layer A */ | ||
626 | [1] = 0x8d, /* Layer B */ | ||
627 | [2] = 0x91, /* Layer C */ | ||
628 | }; | ||
629 | |||
630 | if (layer > ARRAY_SIZE(reg)) | ||
631 | return -EINVAL; | ||
632 | rc = mb86a20s_writereg(state, 0x6d, reg[layer]); | ||
633 | if (rc < 0) | ||
634 | return rc; | ||
635 | rc = mb86a20s_readreg(state, 0x6e); | ||
636 | if (rc < 0) | ||
637 | return rc; | ||
638 | count = (rc >> 4) & 0x0f; | ||
639 | |||
640 | return count; | ||
641 | } | ||
642 | |||
528 | static int mb86a20s_get_frontend(struct dvb_frontend *fe) | 643 | static int mb86a20s_get_frontend(struct dvb_frontend *fe) |
529 | { | 644 | { |
645 | struct mb86a20s_state *state = fe->demodulator_priv; | ||
530 | struct dtv_frontend_properties *p = &fe->dtv_property_cache; | 646 | struct dtv_frontend_properties *p = &fe->dtv_property_cache; |
647 | int i, rc; | ||
531 | 648 | ||
532 | /* FIXME: For now, it does nothing */ | 649 | /* Fixed parameters */ |
533 | 650 | p->delivery_system = SYS_ISDBT; | |
534 | p->bandwidth_hz = 6000000; | 651 | p->bandwidth_hz = 6000000; |
652 | |||
653 | if (fe->ops.i2c_gate_ctrl) | ||
654 | fe->ops.i2c_gate_ctrl(fe, 0); | ||
655 | |||
656 | /* Check for partial reception */ | ||
657 | rc = mb86a20s_writereg(state, 0x6d, 0x85); | ||
658 | if (rc >= 0) | ||
659 | rc = mb86a20s_readreg(state, 0x6e); | ||
660 | if (rc >= 0) | ||
661 | p->isdbt_partial_reception = (rc & 0x10) ? 1 : 0; | ||
662 | |||
663 | /* Get per-layer data */ | ||
664 | p->isdbt_layer_enabled = 0; | ||
665 | for (i = 0; i < 3; i++) { | ||
666 | rc = mb86a20s_get_segment_count(state, i); | ||
667 | if (rc >= 0 && rc < 14) | ||
668 | p->layer[i].segment_count = rc; | ||
669 | if (rc == 0x0f) | ||
670 | continue; | ||
671 | p->isdbt_layer_enabled |= 1 << i; | ||
672 | rc = mb86a20s_get_modulation(state, i); | ||
673 | if (rc >= 0) | ||
674 | p->layer[i].modulation = rc; | ||
675 | rc = mb86a20s_get_fec(state, i); | ||
676 | if (rc >= 0) | ||
677 | p->layer[i].fec = rc; | ||
678 | rc = mb86a20s_get_interleaving(state, i); | ||
679 | if (rc >= 0) | ||
680 | p->layer[i].interleaving = rc; | ||
681 | } | ||
682 | |||
683 | p->isdbt_sb_mode = 0; | ||
684 | rc = mb86a20s_writereg(state, 0x6d, 0x84); | ||
685 | if ((rc >= 0) && ((rc & 0x60) == 0x20)) { | ||
686 | p->isdbt_sb_mode = 1; | ||
687 | /* At least, one segment should exist */ | ||
688 | if (!p->isdbt_sb_segment_count) | ||
689 | p->isdbt_sb_segment_count = 1; | ||
690 | } else | ||
691 | p->isdbt_sb_segment_count = 0; | ||
692 | |||
693 | /* Get transmission mode and guard interval */ | ||
535 | p->transmission_mode = TRANSMISSION_MODE_AUTO; | 694 | p->transmission_mode = TRANSMISSION_MODE_AUTO; |
536 | p->guard_interval = GUARD_INTERVAL_AUTO; | 695 | p->guard_interval = GUARD_INTERVAL_AUTO; |
537 | p->isdbt_partial_reception = 0; | 696 | rc = mb86a20s_readreg(state, 0x07); |
697 | if (rc >= 0) { | ||
698 | if ((rc & 0x60) == 0x20) { | ||
699 | switch (rc & 0x0c >> 2) { | ||
700 | case 0: | ||
701 | p->transmission_mode = TRANSMISSION_MODE_2K; | ||
702 | break; | ||
703 | case 1: | ||
704 | p->transmission_mode = TRANSMISSION_MODE_4K; | ||
705 | break; | ||
706 | case 2: | ||
707 | p->transmission_mode = TRANSMISSION_MODE_8K; | ||
708 | break; | ||
709 | } | ||
710 | } | ||
711 | if (!(rc & 0x10)) { | ||
712 | switch (rc & 0x3) { | ||
713 | case 0: | ||
714 | p->guard_interval = GUARD_INTERVAL_1_4; | ||
715 | break; | ||
716 | case 1: | ||
717 | p->guard_interval = GUARD_INTERVAL_1_8; | ||
718 | break; | ||
719 | case 2: | ||
720 | p->guard_interval = GUARD_INTERVAL_1_16; | ||
721 | break; | ||
722 | } | ||
723 | } | ||
724 | } | ||
725 | |||
726 | if (fe->ops.i2c_gate_ctrl) | ||
727 | fe->ops.i2c_gate_ctrl(fe, 1); | ||
538 | 728 | ||
539 | return 0; | 729 | return 0; |
540 | } | 730 | } |