diff options
-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 | } |