diff options
author | Rusty Scott <rustys@ieee.org> | 2006-12-04 16:04:15 -0500 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@infradead.org> | 2006-12-10 06:22:53 -0500 |
commit | b2fb7f55a1837e39a9f74e2fd7be990ccba90eb4 (patch) | |
tree | 1529361a3f105a364c24b2ac54b54064b9351649 /drivers/media/dvb | |
parent | 1c5ee876d697a9d1b70117e4277eaa445d14a728 (diff) |
V4L/DVB (4939): Or51132: Changed SNR and signal strength reporting
Removes embedded log functions and makes use of the DVB math functions
to provide SNR in dB. The changes are modeled after recent changes made
to the LGDT330x frontends in lgdt330x.c
Signed-off-by: Rusty Scott <rustys@ieee.org>
Signed-off-by: Trent Piepho <xyzzy@speakeasy.org>
Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>
Diffstat (limited to 'drivers/media/dvb')
-rw-r--r-- | drivers/media/dvb/frontends/or51132.c | 176 |
1 files changed, 91 insertions, 85 deletions
diff --git a/drivers/media/dvb/frontends/or51132.c b/drivers/media/dvb/frontends/or51132.c index d20ab30c1e83..5a3a6e53cda2 100644 --- a/drivers/media/dvb/frontends/or51132.c +++ b/drivers/media/dvb/frontends/or51132.c | |||
@@ -40,6 +40,7 @@ | |||
40 | #include <linux/slab.h> | 40 | #include <linux/slab.h> |
41 | #include <asm/byteorder.h> | 41 | #include <asm/byteorder.h> |
42 | 42 | ||
43 | #include "dvb_math.h" | ||
43 | #include "dvb_frontend.h" | 44 | #include "dvb_frontend.h" |
44 | #include "dvb-pll.h" | 45 | #include "dvb-pll.h" |
45 | #include "or51132.h" | 46 | #include "or51132.h" |
@@ -62,6 +63,7 @@ struct or51132_state | |||
62 | 63 | ||
63 | /* Demodulator private data */ | 64 | /* Demodulator private data */ |
64 | fe_modulation_t current_modulation; | 65 | fe_modulation_t current_modulation; |
66 | u32 snr; /* Result of last SNR calculation */ | ||
65 | 67 | ||
66 | /* Tuner private data */ | 68 | /* Tuner private data */ |
67 | u32 current_frequency; | 69 | u32 current_frequency; |
@@ -465,124 +467,128 @@ static int or51132_read_status(struct dvb_frontend* fe, fe_status_t* status) | |||
465 | return 0; | 467 | return 0; |
466 | } | 468 | } |
467 | 469 | ||
468 | /* log10-1 table at .5 increments from 1 to 100.5 */ | 470 | /* Calculate SNR estimation (scaled by 2^24) |
469 | static unsigned int i100x20log10[] = { | ||
470 | 0, 352, 602, 795, 954, 1088, 1204, 1306, 1397, 1480, | ||
471 | 1556, 1625, 1690, 1750, 1806, 1858, 1908, 1955, 2000, 2042, | ||
472 | 2082, 2121, 2158, 2193, 2227, 2260, 2292, 2322, 2352, 2380, | ||
473 | 2408, 2434, 2460, 2486, 2510, 2534, 2557, 2580, 2602, 2623, | ||
474 | 2644, 2664, 2684, 2704, 2723, 2742, 2760, 2778, 2795, 2813, | ||
475 | 2829, 2846, 2862, 2878, 2894, 2909, 2924, 2939, 2954, 2968, | ||
476 | 2982, 2996, 3010, 3023, 3037, 3050, 3062, 3075, 3088, 3100, | ||
477 | 3112, 3124, 3136, 3148, 3159, 3170, 3182, 3193, 3204, 3214, | ||
478 | 3225, 3236, 3246, 3256, 3266, 3276, 3286, 3296, 3306, 3316, | ||
479 | 3325, 3334, 3344, 3353, 3362, 3371, 3380, 3389, 3397, 3406, | ||
480 | 3415, 3423, 3432, 3440, 3448, 3456, 3464, 3472, 3480, 3488, | ||
481 | 3496, 3504, 3511, 3519, 3526, 3534, 3541, 3549, 3556, 3563, | ||
482 | 3570, 3577, 3584, 3591, 3598, 3605, 3612, 3619, 3625, 3632, | ||
483 | 3639, 3645, 3652, 3658, 3665, 3671, 3677, 3683, 3690, 3696, | ||
484 | 3702, 3708, 3714, 3720, 3726, 3732, 3738, 3744, 3750, 3755, | ||
485 | 3761, 3767, 3772, 3778, 3784, 3789, 3795, 3800, 3806, 3811, | ||
486 | 3816, 3822, 3827, 3832, 3838, 3843, 3848, 3853, 3858, 3863, | ||
487 | 3868, 3874, 3879, 3884, 3888, 3893, 3898, 3903, 3908, 3913, | ||
488 | 3918, 3922, 3927, 3932, 3936, 3941, 3946, 3950, 3955, 3960, | ||
489 | 3964, 3969, 3973, 3978, 3982, 3986, 3991, 3995, 4000, 4004, | ||
490 | }; | ||
491 | 471 | ||
492 | static unsigned int denom[] = {1,1,100,1000,10000,100000,1000000,10000000,100000000}; | 472 | 8-VSB SNR and QAM equations from Oren datasheets |
493 | 473 | ||
494 | static unsigned int i20Log10(unsigned short val) | 474 | For 8-VSB: |
495 | { | 475 | SNR[dB] = 10 * log10(897152044.8282 / MSE^2 ) - K |
496 | unsigned int rntval = 100; | 476 | |
497 | unsigned int tmp = val; | 477 | Where K = 0 if NTSC rejection filter is OFF; and |
498 | unsigned int exp = 1; | 478 | K = 3 if NTSC rejection filter is ON |
479 | |||
480 | For QAM64: | ||
481 | SNR[dB] = 10 * log10(897152044.8282 / MSE^2 ) | ||
499 | 482 | ||
500 | while(tmp > 100) {tmp /= 100; exp++;} | 483 | For QAM256: |
484 | SNR[dB] = 10 * log10(907832426.314266 / MSE^2 ) | ||
501 | 485 | ||
502 | val = (2 * val)/denom[exp]; | 486 | We re-write the snr equation as: |
503 | if (exp > 1) rntval = 2000*exp; | 487 | SNR * 2^24 = 10*(c - 2*intlog10(MSE)) |
488 | Where for QAM256, c = log10(907832426.314266) * 2^24 | ||
489 | and for 8-VSB and QAM64, c = log10(897152044.8282) * 2^24 */ | ||
504 | 490 | ||
505 | rntval += i100x20log10[val]; | 491 | static u32 calculate_snr(u32 mse, u32 c) |
506 | return rntval; | 492 | { |
493 | if (mse == 0) /* No signal */ | ||
494 | return 0; | ||
495 | |||
496 | mse = 2*intlog10(mse); | ||
497 | if (mse > c) { | ||
498 | /* Negative SNR, which is possible, but realisticly the | ||
499 | demod will lose lock before the signal gets this bad. The | ||
500 | API only allows for unsigned values, so just return 0 */ | ||
501 | return 0; | ||
502 | } | ||
503 | return 10*(c - mse); | ||
507 | } | 504 | } |
508 | 505 | ||
509 | static int or51132_read_signal_strength(struct dvb_frontend* fe, u16* strength) | 506 | static int or51132_read_snr(struct dvb_frontend* fe, u16* snr) |
510 | { | 507 | { |
511 | struct or51132_state* state = fe->demodulator_priv; | 508 | struct or51132_state* state = fe->demodulator_priv; |
512 | unsigned char rec_buf[2]; | 509 | u8 rec_buf[2]; |
513 | unsigned char snd_buf[2]; | 510 | u8 snd_buf[2]; |
514 | u8 rcvr_stat; | 511 | u32 noise; |
515 | u16 snr_equ; | 512 | u32 c; |
516 | u32 signal_strength; | 513 | u32 usK; |
517 | int usK; | ||
518 | 514 | ||
515 | /* Register is same for VSB or QAM firmware */ | ||
519 | snd_buf[0]=0x04; | 516 | snd_buf[0]=0x04; |
520 | snd_buf[1]=0x02; /* SNR after Equalizer */ | 517 | snd_buf[1]=0x02; /* SNR after Equalizer */ |
521 | msleep(30); /* 30ms */ | 518 | msleep(30); /* 30ms */ |
522 | if (i2c_writebytes(state,state->config->demod_address,snd_buf,2)) { | 519 | if (i2c_writebytes(state,state->config->demod_address,snd_buf,2)) { |
523 | printk(KERN_WARNING "or51132: read_status write error\n"); | 520 | printk(KERN_WARNING "or51132: snr write error\n"); |
524 | return -1; | 521 | return -EREMOTEIO; |
525 | } | 522 | } |
526 | msleep(30); /* 30ms */ | 523 | msleep(30); /* 30ms */ |
527 | if (i2c_readbytes(state,state->config->demod_address,rec_buf,2)) { | 524 | if (i2c_readbytes(state,state->config->demod_address,rec_buf,2)) { |
528 | printk(KERN_WARNING "or51132: read_status read error\n"); | 525 | printk(KERN_WARNING "or51132: snr read error\n"); |
529 | return -1; | 526 | return -EREMOTEIO; |
530 | } | 527 | } |
531 | snr_equ = rec_buf[0] | (rec_buf[1] << 8); | 528 | noise = rec_buf[0] | (rec_buf[1] << 8); |
532 | dprintk("read_signal_strength snr_equ %x %x (%i)\n",rec_buf[0],rec_buf[1],snr_equ); | 529 | dprintk("read_snr noise %x %x (%i)\n",rec_buf[0],rec_buf[1],noise); |
533 | 530 | ||
534 | /* Receiver Status */ | 531 | /* Read status, contains modulation type for QAM_AUTO and |
532 | NTSC filter for VSB */ | ||
535 | snd_buf[0]=0x04; | 533 | snd_buf[0]=0x04; |
536 | snd_buf[1]=0x00; | 534 | snd_buf[1]=0x00; /* Status register */ |
537 | msleep(30); /* 30ms */ | 535 | msleep(30); /* 30ms */ |
538 | if (i2c_writebytes(state,state->config->demod_address,snd_buf,2)) { | 536 | if (i2c_writebytes(state,state->config->demod_address,snd_buf,2)) { |
539 | printk(KERN_WARNING "or51132: read_signal_strength read_status write error\n"); | 537 | printk(KERN_WARNING "or51132: status write error\n"); |
540 | return -1; | 538 | return -EREMOTEIO; |
541 | } | 539 | } |
542 | msleep(30); /* 30ms */ | 540 | msleep(30); /* 30ms */ |
543 | if (i2c_readbytes(state,state->config->demod_address,rec_buf,2)) { | 541 | if (i2c_readbytes(state,state->config->demod_address,rec_buf,2)) { |
544 | printk(KERN_WARNING "or51132: read_signal_strength read_status read error\n"); | 542 | printk(KERN_WARNING "or51132: status read error\n"); |
545 | return -1; | 543 | return -EREMOTEIO; |
546 | } | 544 | } |
547 | dprintk("read_signal_strength read_status %x %x\n",rec_buf[0],rec_buf[1]); | ||
548 | rcvr_stat = rec_buf[1]; | ||
549 | usK = (rcvr_stat & 0x10) ? 3 : 0; | ||
550 | 545 | ||
551 | /* The value reported back from the frontend will be FFFF=100% 0000=0% */ | 546 | usK = 0; |
552 | signal_strength = (((8952 - i20Log10(snr_equ) - usK*100)/3+5)*65535)/1000; | 547 | switch (rec_buf[0]) { |
553 | if (signal_strength > 0xffff) | 548 | case 0x06: |
554 | *strength = 0xffff; | 549 | usK = (rec_buf[1] & 0x10) ? 0x03000000 : 0; |
555 | else | 550 | /* Fall through to QAM64 case */ |
556 | *strength = signal_strength; | 551 | case 0x43: |
557 | dprintk("read_signal_strength %i\n",*strength); | 552 | c = 150204167; |
553 | break; | ||
554 | case 0x45: | ||
555 | c = 150290396; | ||
556 | break; | ||
557 | default: | ||
558 | printk(KERN_ERR "or51132: unknown status 0x%02x\n", rec_buf[0]); | ||
559 | return -EREMOTEIO; | ||
560 | } | ||
561 | dprintk("%s: modulation %02x, NTSC rej O%s\n", __FUNCTION__, | ||
562 | rec_buf[0], rec_buf[1]&0x10?"n":"ff"); | ||
563 | |||
564 | /* Calculate SNR using noise, c, and NTSC rejection correction */ | ||
565 | state->snr = calculate_snr(noise, c) - usK; | ||
566 | *snr = (state->snr) >> 16; | ||
567 | |||
568 | dprintk("%s: noise = 0x%08x, snr = %d.%02d dB\n", __FUNCTION__, noise, | ||
569 | state->snr >> 24, (((state->snr>>8) & 0xffff) * 100) >> 16); | ||
558 | 570 | ||
559 | return 0; | 571 | return 0; |
560 | } | 572 | } |
561 | 573 | ||
562 | static int or51132_read_snr(struct dvb_frontend* fe, u16* snr) | 574 | static int or51132_read_signal_strength(struct dvb_frontend* fe, u16* strength) |
563 | { | 575 | { |
564 | struct or51132_state* state = fe->demodulator_priv; | 576 | /* Calculate Strength from SNR up to 35dB */ |
565 | unsigned char rec_buf[2]; | 577 | /* Even though the SNR can go higher than 35dB, there is some comfort */ |
566 | unsigned char snd_buf[2]; | 578 | /* factor in having a range of strong signals that can show at 100% */ |
567 | u16 snr_equ; | 579 | struct or51132_state* state = (struct or51132_state*) fe->demodulator_priv; |
568 | 580 | u16 snr; | |
569 | snd_buf[0]=0x04; | 581 | int ret; |
570 | snd_buf[1]=0x02; /* SNR after Equalizer */ | ||
571 | msleep(30); /* 30ms */ | ||
572 | if (i2c_writebytes(state,state->config->demod_address,snd_buf,2)) { | ||
573 | printk(KERN_WARNING "or51132: read_snr write error\n"); | ||
574 | return -1; | ||
575 | } | ||
576 | msleep(30); /* 30ms */ | ||
577 | if (i2c_readbytes(state,state->config->demod_address,rec_buf,2)) { | ||
578 | printk(KERN_WARNING "or51132: read_snr dvr read error\n"); | ||
579 | return -1; | ||
580 | } | ||
581 | snr_equ = rec_buf[0] | (rec_buf[1] << 8); | ||
582 | dprintk("read_snr snr_equ %x %x (%i)\n",rec_buf[0],rec_buf[1],snr_equ); | ||
583 | 582 | ||
584 | *snr = 0xFFFF - snr_equ; | 583 | ret = fe->ops.read_snr(fe, &snr); |
585 | dprintk("read_snr %i\n",*snr); | 584 | if (ret != 0) |
585 | return ret; | ||
586 | /* Rather than use the 8.8 value snr, use state->snr which is 8.24 */ | ||
587 | /* scale the range 0 - 35*2^24 into 0 - 65535 */ | ||
588 | if (state->snr >= 8960 * 0x10000) | ||
589 | *strength = 0xffff; | ||
590 | else | ||
591 | *strength = state->snr / 8960; | ||
586 | 592 | ||
587 | return 0; | 593 | return 0; |
588 | } | 594 | } |