diff options
-rw-r--r-- | drivers/media/dvb/frontends/lgdt330x.c | 243 | ||||
-rw-r--r-- | drivers/media/dvb/frontends/lgdt330x_priv.h | 15 |
2 files changed, 132 insertions, 126 deletions
diff --git a/drivers/media/dvb/frontends/lgdt330x.c b/drivers/media/dvb/frontends/lgdt330x.c index 9a354708bd20..db3ef58dafba 100644 --- a/drivers/media/dvb/frontends/lgdt330x.c +++ b/drivers/media/dvb/frontends/lgdt330x.c | |||
@@ -31,9 +31,6 @@ | |||
31 | * Air2PC/AirStar 2 ATSC 3rd generation (HD5000) | 31 | * Air2PC/AirStar 2 ATSC 3rd generation (HD5000) |
32 | * pcHDTV HD5500 | 32 | * pcHDTV HD5500 |
33 | * | 33 | * |
34 | * TODO: | ||
35 | * signal strength always returns 0. | ||
36 | * | ||
37 | */ | 34 | */ |
38 | 35 | ||
39 | #include <linux/kernel.h> | 36 | #include <linux/kernel.h> |
@@ -46,9 +43,13 @@ | |||
46 | #include <asm/byteorder.h> | 43 | #include <asm/byteorder.h> |
47 | 44 | ||
48 | #include "dvb_frontend.h" | 45 | #include "dvb_frontend.h" |
46 | #include "dvb_math.h" | ||
49 | #include "lgdt330x_priv.h" | 47 | #include "lgdt330x_priv.h" |
50 | #include "lgdt330x.h" | 48 | #include "lgdt330x.h" |
51 | 49 | ||
50 | /* Use Equalizer Mean Squared Error instead of Phaser Tracker MSE */ | ||
51 | /* #define USE_EQMSE */ | ||
52 | |||
52 | static int debug = 0; | 53 | static int debug = 0; |
53 | module_param(debug, int, 0644); | 54 | module_param(debug, int, 0644); |
54 | MODULE_PARM_DESC(debug,"Turn on/off lgdt330x frontend debugging (default:off)."); | 55 | MODULE_PARM_DESC(debug,"Turn on/off lgdt330x frontend debugging (default:off)."); |
@@ -68,6 +69,7 @@ struct lgdt330x_state | |||
68 | 69 | ||
69 | /* Demodulator private data */ | 70 | /* Demodulator private data */ |
70 | fe_modulation_t current_modulation; | 71 | fe_modulation_t current_modulation; |
72 | u32 snr; /* Result of last SNR calculation */ | ||
71 | 73 | ||
72 | /* Tuner private data */ | 74 | /* Tuner private data */ |
73 | u32 current_frequency; | 75 | u32 current_frequency; |
@@ -543,151 +545,150 @@ static int lgdt3303_read_status(struct dvb_frontend* fe, fe_status_t* status) | |||
543 | return 0; | 545 | return 0; |
544 | } | 546 | } |
545 | 547 | ||
546 | static int lgdt330x_read_signal_strength(struct dvb_frontend* fe, u16* strength) | 548 | /* Calculate SNR estimation (scaled by 2^24) |
549 | |||
550 | 8-VSB SNR equations from LGDT3302 and LGDT3303 datasheets, QAM | ||
551 | equations from LGDT3303 datasheet. VSB is the same between the '02 | ||
552 | and '03, so maybe QAM is too? Perhaps someone with a newer datasheet | ||
553 | that has QAM information could verify? | ||
554 | |||
555 | For 8-VSB: (two ways, take your pick) | ||
556 | LGDT3302: | ||
557 | SNR_EQ = 10 * log10(25 * 24^2 / EQ_MSE) | ||
558 | LGDT3303: | ||
559 | SNR_EQ = 10 * log10(25 * 32^2 / EQ_MSE) | ||
560 | LGDT3302 & LGDT3303: | ||
561 | SNR_PT = 10 * log10(25 * 32^2 / PT_MSE) (we use this one) | ||
562 | For 64-QAM: | ||
563 | SNR = 10 * log10( 688128 / MSEQAM) | ||
564 | For 256-QAM: | ||
565 | SNR = 10 * log10( 696320 / MSEQAM) | ||
566 | |||
567 | We re-write the snr equation as: | ||
568 | SNR * 2^24 = 10*(c - intlog10(MSE)) | ||
569 | Where for 256-QAM, c = log10(696320) * 2^24, and so on. */ | ||
570 | |||
571 | static u32 calculate_snr(u32 mse, u32 c) | ||
547 | { | 572 | { |
548 | /* not directly available. */ | 573 | if (mse == 0) /* No signal */ |
549 | *strength = 0; | 574 | return 0; |
550 | return 0; | 575 | |
576 | mse = intlog10(mse); | ||
577 | if (mse > c) { | ||
578 | /* Negative SNR, which is possible, but realisticly the | ||
579 | demod will lose lock before the signal gets this bad. The | ||
580 | API only allows for unsigned values, so just return 0 */ | ||
581 | return 0; | ||
582 | } | ||
583 | return 10*(c - mse); | ||
551 | } | 584 | } |
552 | 585 | ||
553 | static int lgdt3302_read_snr(struct dvb_frontend* fe, u16* snr) | 586 | static int lgdt3302_read_snr(struct dvb_frontend* fe, u16* snr) |
554 | { | 587 | { |
555 | #ifdef SNR_IN_DB | ||
556 | /* | ||
557 | * Spec sheet shows formula for SNR_EQ = 10 log10(25 * 24**2 / noise) | ||
558 | * and SNR_PH = 10 log10(25 * 32**2 / noise) for equalizer and phase tracker | ||
559 | * respectively. The following tables are built on these formulas. | ||
560 | * The usual definition is SNR = 20 log10(signal/noise) | ||
561 | * If the specification is wrong the value retuned is 1/2 the actual SNR in db. | ||
562 | * | ||
563 | * This table is a an ordered list of noise values computed by the | ||
564 | * formula from the spec sheet such that the index into the table | ||
565 | * starting at 43 or 45 is the SNR value in db. There are duplicate noise | ||
566 | * value entries at the beginning because the SNR varies more than | ||
567 | * 1 db for a change of 1 digit in noise at very small values of noise. | ||
568 | * | ||
569 | * Examples from SNR_EQ table: | ||
570 | * noise SNR | ||
571 | * 0 43 | ||
572 | * 1 42 | ||
573 | * 2 39 | ||
574 | * 3 37 | ||
575 | * 4 36 | ||
576 | * 5 35 | ||
577 | * 6 34 | ||
578 | * 7 33 | ||
579 | * 8 33 | ||
580 | * 9 32 | ||
581 | * 10 32 | ||
582 | * 11 31 | ||
583 | * 12 31 | ||
584 | * 13 30 | ||
585 | */ | ||
586 | |||
587 | static const u32 SNR_EQ[] = | ||
588 | { 1, 2, 2, 2, 3, 3, 4, 4, 5, 7, | ||
589 | 9, 11, 13, 17, 21, 26, 33, 41, 52, 65, | ||
590 | 81, 102, 129, 162, 204, 257, 323, 406, 511, 644, | ||
591 | 810, 1020, 1284, 1616, 2035, 2561, 3224, 4059, 5110, 6433, | ||
592 | 8098, 10195, 12835, 16158, 20341, 25608, 32238, 40585, 51094, 64323, | ||
593 | 80978, 101945, 128341, 161571, 203406, 256073, 0x40000 | ||
594 | }; | ||
595 | |||
596 | static const u32 SNR_PH[] = | ||
597 | { 1, 2, 2, 2, 3, 3, 4, 5, 6, 8, | ||
598 | 10, 12, 15, 19, 23, 29, 37, 46, 58, 73, | ||
599 | 91, 115, 144, 182, 229, 288, 362, 456, 574, 722, | ||
600 | 909, 1144, 1440, 1813, 2282, 2873, 3617, 4553, 5732, 7216, | ||
601 | 9084, 11436, 14396, 18124, 22817, 28724, 36161, 45524, 57312, 72151, | ||
602 | 90833, 114351, 143960, 181235, 228161, 0x080000 | ||
603 | }; | ||
604 | |||
605 | static u8 buf[5];/* read data buffer */ | ||
606 | static u32 noise; /* noise value */ | ||
607 | static u32 snr_db; /* index into SNR_EQ[] */ | ||
608 | struct lgdt330x_state* state = (struct lgdt330x_state*) fe->demodulator_priv; | 588 | struct lgdt330x_state* state = (struct lgdt330x_state*) fe->demodulator_priv; |
589 | u8 buf[5]; /* read data buffer */ | ||
590 | u32 noise; /* noise value */ | ||
591 | u32 c; /* per-modulation SNR calculation constant */ | ||
609 | 592 | ||
610 | /* read both equalizer and phase tracker noise data */ | 593 | switch(state->current_modulation) { |
611 | i2c_read_demod_bytes(state, EQPH_ERR0, buf, sizeof(buf)); | 594 | case VSB_8: |
612 | 595 | i2c_read_demod_bytes(state, LGDT3302_EQPH_ERR0, buf, 5); | |
613 | if (state->current_modulation == VSB_8) { | 596 | #ifdef USE_EQMSE |
614 | /* Equalizer Mean-Square Error Register for VSB */ | 597 | /* Use Equalizer Mean-Square Error Register */ |
598 | /* SNR for ranges from -15.61 to +41.58 */ | ||
615 | noise = ((buf[0] & 7) << 16) | (buf[1] << 8) | buf[2]; | 599 | noise = ((buf[0] & 7) << 16) | (buf[1] << 8) | buf[2]; |
616 | 600 | c = 69765745; /* log10(25*24^2)*2^24 */ | |
617 | /* | ||
618 | * Look up noise value in table. | ||
619 | * A better search algorithm could be used... | ||
620 | * watch out there are duplicate entries. | ||
621 | */ | ||
622 | for (snr_db = 0; snr_db < sizeof(SNR_EQ); snr_db++) { | ||
623 | if (noise < SNR_EQ[snr_db]) { | ||
624 | *snr = 43 - snr_db; | ||
625 | break; | ||
626 | } | ||
627 | } | ||
628 | } else { | ||
629 | /* Phase Tracker Mean-Square Error Register for QAM */ | ||
630 | noise = ((buf[0] & 7<<3) << 13) | (buf[3] << 8) | buf[4]; | ||
631 | |||
632 | /* Look up noise value in table. */ | ||
633 | for (snr_db = 0; snr_db < sizeof(SNR_PH); snr_db++) { | ||
634 | if (noise < SNR_PH[snr_db]) { | ||
635 | *snr = 45 - snr_db; | ||
636 | break; | ||
637 | } | ||
638 | } | ||
639 | } | ||
640 | #else | 601 | #else |
641 | /* Return the raw noise value */ | 602 | /* Use Phase Tracker Mean-Square Error Register */ |
642 | static u8 buf[5];/* read data buffer */ | 603 | /* SNR for ranges from -13.11 to +44.08 */ |
643 | static u32 noise; /* noise value */ | ||
644 | struct lgdt330x_state* state = (struct lgdt330x_state*) fe->demodulator_priv; | ||
645 | |||
646 | /* read both equalizer and pase tracker noise data */ | ||
647 | i2c_read_demod_bytes(state, EQPH_ERR0, buf, sizeof(buf)); | ||
648 | |||
649 | if (state->current_modulation == VSB_8) { | ||
650 | /* Phase Tracker Mean-Square Error Register for VSB */ | ||
651 | noise = ((buf[0] & 7<<3) << 13) | (buf[3] << 8) | buf[4]; | 604 | noise = ((buf[0] & 7<<3) << 13) | (buf[3] << 8) | buf[4]; |
652 | } else { | 605 | c = 73957994; /* log10(25*32^2)*2^24 */ |
653 | 606 | #endif | |
654 | /* Carrier Recovery Mean-Square Error for QAM */ | 607 | break; |
655 | i2c_read_demod_bytes(state, 0x1a, buf, 2); | 608 | case QAM_64: |
609 | case QAM_256: | ||
610 | i2c_read_demod_bytes(state, CARRIER_MSEQAM1, buf, 2); | ||
656 | noise = ((buf[0] & 3) << 8) | buf[1]; | 611 | noise = ((buf[0] & 3) << 8) | buf[1]; |
612 | c = state->current_modulation == QAM_64 ? 97939837 : 98026066; | ||
613 | /* log10(688128)*2^24 and log10(696320)*2^24 */ | ||
614 | break; | ||
615 | default: | ||
616 | printk(KERN_ERR "lgdt330x: %s: Modulation set to unsupported value\n", | ||
617 | __FUNCTION__); | ||
618 | return -EREMOTEIO; /* return -EDRIVER_IS_GIBBERED; */ | ||
657 | } | 619 | } |
658 | 620 | ||
659 | /* Small values for noise mean signal is better so invert noise */ | 621 | state->snr = calculate_snr(noise, c); |
660 | *snr = ~noise; | 622 | *snr = (state->snr) >> 16; /* Convert from 8.24 fixed-point to 8.8 */ |
661 | #endif | ||
662 | 623 | ||
663 | dprintk("%s: noise = 0x%05x, snr = %idb\n",__FUNCTION__, noise, *snr); | 624 | dprintk("%s: noise = 0x%08x, snr = %d.%02d dB\n", __FUNCTION__, noise, |
625 | state->snr >> 24, (((state->snr>>8) & 0xffff) * 100) >> 16); | ||
664 | 626 | ||
665 | return 0; | 627 | return 0; |
666 | } | 628 | } |
667 | 629 | ||
668 | static int lgdt3303_read_snr(struct dvb_frontend* fe, u16* snr) | 630 | static int lgdt3303_read_snr(struct dvb_frontend* fe, u16* snr) |
669 | { | 631 | { |
670 | /* Return the raw noise value */ | ||
671 | static u8 buf[5];/* read data buffer */ | ||
672 | static u32 noise; /* noise value */ | ||
673 | struct lgdt330x_state* state = (struct lgdt330x_state*) fe->demodulator_priv; | 632 | struct lgdt330x_state* state = (struct lgdt330x_state*) fe->demodulator_priv; |
633 | u8 buf[5]; /* read data buffer */ | ||
634 | u32 noise; /* noise value */ | ||
635 | u32 c; /* per-modulation SNR calculation constant */ | ||
674 | 636 | ||
675 | if (state->current_modulation == VSB_8) { | 637 | switch(state->current_modulation) { |
676 | 638 | case VSB_8: | |
677 | i2c_read_demod_bytes(state, 0x6e, buf, 5); | 639 | i2c_read_demod_bytes(state, LGDT3303_EQPH_ERR0, buf, 5); |
678 | /* Phase Tracker Mean-Square Error Register for VSB */ | 640 | #ifdef USE_EQMSE |
641 | /* Use Equalizer Mean-Square Error Register */ | ||
642 | /* SNR for ranges from -16.12 to +44.08 */ | ||
643 | noise = ((buf[0] & 0x78) << 13) | (buf[1] << 8) | buf[2]; | ||
644 | c = 73957994; /* log10(25*32^2)*2^24 */ | ||
645 | #else | ||
646 | /* Use Phase Tracker Mean-Square Error Register */ | ||
647 | /* SNR for ranges from -13.11 to +44.08 */ | ||
679 | noise = ((buf[0] & 7) << 16) | (buf[3] << 8) | buf[4]; | 648 | noise = ((buf[0] & 7) << 16) | (buf[3] << 8) | buf[4]; |
680 | } else { | 649 | c = 73957994; /* log10(25*32^2)*2^24 */ |
681 | 650 | #endif | |
682 | /* Carrier Recovery Mean-Square Error for QAM */ | 651 | break; |
683 | i2c_read_demod_bytes(state, 0x1a, buf, 2); | 652 | case QAM_64: |
653 | case QAM_256: | ||
654 | i2c_read_demod_bytes(state, CARRIER_MSEQAM1, buf, 2); | ||
684 | noise = (buf[0] << 8) | buf[1]; | 655 | noise = (buf[0] << 8) | buf[1]; |
656 | c = state->current_modulation == QAM_64 ? 97939837 : 98026066; | ||
657 | /* log10(688128)*2^24 and log10(696320)*2^24 */ | ||
658 | break; | ||
659 | default: | ||
660 | printk(KERN_ERR "lgdt330x: %s: Modulation set to unsupported value\n", | ||
661 | __FUNCTION__); | ||
662 | return -EREMOTEIO; /* return -EDRIVER_IS_GIBBERED; */ | ||
685 | } | 663 | } |
686 | 664 | ||
687 | /* Small values for noise mean signal is better so invert noise */ | 665 | state->snr = calculate_snr(noise, c); |
688 | *snr = ~noise; | 666 | *snr = (state->snr) >> 16; /* Convert from 8.24 fixed-point to 8.8 */ |
667 | |||
668 | dprintk("%s: noise = 0x%08x, snr = %d.%02d dB\n", __FUNCTION__, noise, | ||
669 | state->snr >> 24, (((state->snr >> 8) & 0xffff) * 100) >> 16); | ||
670 | |||
671 | return 0; | ||
672 | } | ||
673 | |||
674 | static int lgdt330x_read_signal_strength(struct dvb_frontend* fe, u16* strength) | ||
675 | { | ||
676 | /* Calculate Strength from SNR up to 35dB */ | ||
677 | /* Even though the SNR can go higher than 35dB, there is some comfort */ | ||
678 | /* factor in having a range of strong signals that can show at 100% */ | ||
679 | struct lgdt330x_state* state = (struct lgdt330x_state*) fe->demodulator_priv; | ||
680 | u16 snr; | ||
681 | int ret; | ||
689 | 682 | ||
690 | dprintk("%s: noise = 0x%05x, snr = %idb\n",__FUNCTION__, noise, *snr); | 683 | ret = fe->ops.read_snr(fe, &snr); |
684 | if (ret != 0) | ||
685 | return ret; | ||
686 | /* Rather than use the 8.8 value snr, use state->snr which is 8.24 */ | ||
687 | /* scale the range 0 - 35*2^24 into 0 - 65535 */ | ||
688 | if (state->snr >= 8960 * 0x10000) | ||
689 | *strength = 0xffff; | ||
690 | else | ||
691 | *strength = state->snr / 8960; | ||
691 | 692 | ||
692 | return 0; | 693 | return 0; |
693 | } | 694 | } |
diff --git a/drivers/media/dvb/frontends/lgdt330x_priv.h b/drivers/media/dvb/frontends/lgdt330x_priv.h index 59b7c5b9012d..38c76695abfe 100644 --- a/drivers/media/dvb/frontends/lgdt330x_priv.h +++ b/drivers/media/dvb/frontends/lgdt330x_priv.h | |||
@@ -51,14 +51,19 @@ enum I2C_REG { | |||
51 | AGC_RFIF_ACC2= 0x3b, | 51 | AGC_RFIF_ACC2= 0x3b, |
52 | AGC_STATUS= 0x3f, | 52 | AGC_STATUS= 0x3f, |
53 | SYNC_STATUS_VSB= 0x43, | 53 | SYNC_STATUS_VSB= 0x43, |
54 | EQPH_ERR0= 0x47, | ||
55 | EQ_ERR1= 0x48, | ||
56 | EQ_ERR2= 0x49, | ||
57 | PH_ERR1= 0x4a, | ||
58 | PH_ERR2= 0x4b, | ||
59 | DEMUX_CONTROL= 0x66, | 54 | DEMUX_CONTROL= 0x66, |
55 | LGDT3302_EQPH_ERR0= 0x47, | ||
56 | LGDT3302_EQ_ERR1= 0x48, | ||
57 | LGDT3302_EQ_ERR2= 0x49, | ||
58 | LGDT3302_PH_ERR1= 0x4a, | ||
59 | LGDT3302_PH_ERR2= 0x4b, | ||
60 | LGDT3302_PACKET_ERR_COUNTER1= 0x6a, | 60 | LGDT3302_PACKET_ERR_COUNTER1= 0x6a, |
61 | LGDT3302_PACKET_ERR_COUNTER2= 0x6b, | 61 | LGDT3302_PACKET_ERR_COUNTER2= 0x6b, |
62 | LGDT3303_EQPH_ERR0= 0x6e, | ||
63 | LGDT3303_EQ_ERR1= 0x6f, | ||
64 | LGDT3303_EQ_ERR2= 0x70, | ||
65 | LGDT3303_PH_ERR1= 0x71, | ||
66 | LGDT3303_PH_ERR2= 0x72, | ||
62 | LGDT3303_PACKET_ERR_COUNTER1= 0x8b, | 67 | LGDT3303_PACKET_ERR_COUNTER1= 0x8b, |
63 | LGDT3303_PACKET_ERR_COUNTER2= 0x8c, | 68 | LGDT3303_PACKET_ERR_COUNTER2= 0x8c, |
64 | }; | 69 | }; |