fedora core 6 1.2949 + vserver 2.2.0
[linux-2.6.git] / drivers / media / dvb / frontends / or51211.c
index 7c3aed1..048d7cf 100644 (file)
@@ -39,6 +39,7 @@
 #include <linux/slab.h>
 #include <asm/byteorder.h>
 
+#include "dvb_math.h"
 #include "dvb_frontend.h"
 #include "or51211.h"
 
@@ -54,7 +55,6 @@ static u8 cmd_buf[] = {0x04,0x01,0x50,0x80,0x06}; // ATSC
 struct or51211_state {
 
        struct i2c_adapter* i2c;
-       struct dvb_frontend_ops ops;
 
        /* Configuration settings */
        const struct or51211_config* config;
@@ -64,6 +64,7 @@ struct or51211_state {
 
        /* Demodulator private data */
        u8 initialized:1;
+       u32 snr; /* Result of last SNR claculation */
 
        /* Tuner private data */
        u32 current_frequency;
@@ -293,107 +294,81 @@ static int or51211_read_status(struct dvb_frontend* fe, fe_status_t* status)
        return 0;
 }
 
-/* log10-1 table at .5 increments from 1 to 100.5 */
-static unsigned int i100x20log10[] = {
-               0,  352,  602,  795,  954, 1088, 1204, 1306, 1397, 1480,
-        1556, 1625, 1690, 1750, 1806, 1858, 1908, 1955, 2000, 2042,
-        2082, 2121, 2158, 2193, 2227, 2260, 2292, 2322, 2352, 2380,
-        2408, 2434, 2460, 2486, 2510, 2534, 2557, 2580, 2602, 2623,
-        2644, 2664, 2684, 2704, 2723, 2742, 2760, 2778, 2795, 2813,
-        2829, 2846, 2862, 2878, 2894, 2909, 2924, 2939, 2954, 2968,
-        2982, 2996, 3010, 3023, 3037, 3050, 3062, 3075, 3088, 3100,
-        3112, 3124, 3136, 3148, 3159, 3170, 3182, 3193, 3204, 3214,
-        3225, 3236, 3246, 3256, 3266, 3276, 3286, 3296, 3306, 3316,
-        3325, 3334, 3344, 3353, 3362, 3371, 3380, 3389, 3397, 3406,
-        3415, 3423, 3432, 3440, 3448, 3456, 3464, 3472, 3480, 3488,
-        3496, 3504, 3511, 3519, 3526, 3534, 3541, 3549, 3556, 3563,
-        3570, 3577, 3584, 3591, 3598, 3605, 3612, 3619, 3625, 3632,
-        3639, 3645, 3652, 3658, 3665, 3671, 3677, 3683, 3690, 3696,
-        3702, 3708, 3714, 3720, 3726, 3732, 3738, 3744, 3750, 3755,
-        3761, 3767, 3772, 3778, 3784, 3789, 3795, 3800, 3806, 3811,
-        3816, 3822, 3827, 3832, 3838, 3843, 3848, 3853, 3858, 3863,
-        3868, 3874, 3879, 3884, 3888, 3893, 3898, 3903, 3908, 3913,
-        3918, 3922, 3927, 3932, 3936, 3941, 3946, 3950, 3955, 3960,
-        3964, 3969, 3973, 3978, 3982, 3986, 3991, 3995, 4000, 4004,
-};
-
-static unsigned int denom[] = {1,1,100,1000,10000,100000,1000000,10000000,100000000};
+/* Calculate SNR estimation (scaled by 2^24)
 
-static unsigned int i20Log10(unsigned short val)
-{
-       unsigned int rntval = 100;
-       unsigned int tmp = val;
-       unsigned int exp = 1;
+   8-VSB SNR equation from Oren datasheets
 
-       while(tmp > 100) {tmp /= 100; exp++;}
+   For 8-VSB:
+     SNR[dB] = 10 * log10(219037.9454 / MSE^2 )
 
-       val = (2 * val)/denom[exp];
-       if (exp > 1) rntval = 2000*exp;
+   We re-write the snr equation as:
+     SNR * 2^24 = 10*(c - 2*intlog10(MSE))
+   Where for 8-VSB, c = log10(219037.9454) * 2^24 */
 
-       rntval += i100x20log10[val];
-       return rntval;
+static u32 calculate_snr(u32 mse, u32 c)
+{
+       if (mse == 0) /* No signal */
+               return 0;
+
+       mse = 2*intlog10(mse);
+       if (mse > c) {
+               /* Negative SNR, which is possible, but realisticly the
+               demod will lose lock before the signal gets this bad.  The
+               API only allows for unsigned values, so just return 0 */
+               return 0;
+       }
+       return 10*(c - mse);
 }
 
-static int or51211_read_signal_strength(struct dvb_frontend* fe, u16* strength)
+static int or51211_read_snr(struct dvb_frontend* fe, u16* snr)
 {
        struct or51211_state* state = fe->demodulator_priv;
        u8 rec_buf[2];
-       u8 snd_buf[4];
-       u8 snr_equ;
-       u32 signal_strength;
+       u8 snd_buf[3];
 
        /* SNR after Equalizer */
        snd_buf[0] = 0x04;
        snd_buf[1] = 0x00;
        snd_buf[2] = 0x04;
-       snd_buf[3] = 0x00;
 
        if (i2c_writebytes(state,state->config->demod_address,snd_buf,3)) {
-               printk(KERN_WARNING "or51211: read_status write error\n");
+               printk(KERN_WARNING "%s: error writing snr reg\n",
+                      __FUNCTION__);
                return -1;
        }
-       msleep(3);
        if (i2c_readbytes(state,state->config->demod_address,rec_buf,2)) {
-               printk(KERN_WARNING "or51211: read_status read error\n");
+               printk(KERN_WARNING "%s: read_status read error\n",
+                      __FUNCTION__);
                return -1;
        }
-       snr_equ = rec_buf[0] & 0xff;
 
-       /* The value reported back from the frontend will be FFFF=100% 0000=0% */
-       signal_strength = (((5334 - i20Log10(snr_equ))/3+5)*65535)/1000;
-       if (signal_strength > 0xffff)
-               *strength = 0xffff;
-       else
-               *strength = signal_strength;
-       dprintk("read_signal_strength %i\n",*strength);
+       state->snr = calculate_snr(rec_buf[0], 89599047);
+       *snr = (state->snr) >> 16;
+
+       dprintk("%s: noise = 0x%02x, snr = %d.%02d dB\n", __FUNCTION__, rec_buf[0],
+               state->snr >> 24, (((state->snr>>8) & 0xffff) * 100) >> 16);
 
        return 0;
 }
 
-static int or51211_read_snr(struct dvb_frontend* fe, u16* snr)
+static int or51211_read_signal_strength(struct dvb_frontend* fe, u16* strength)
 {
-       struct or51211_state* state = fe->demodulator_priv;
-       u8 rec_buf[2];
-       u8 snd_buf[4];
-
-       /* SNR after Equalizer */
-       snd_buf[0] = 0x04;
-       snd_buf[1] = 0x00;
-       snd_buf[2] = 0x04;
-       snd_buf[3] = 0x00;
-
-       if (i2c_writebytes(state,state->config->demod_address,snd_buf,3)) {
-               printk(KERN_WARNING "or51211: read_status write error\n");
-               return -1;
-       }
-       msleep(3);
-       if (i2c_readbytes(state,state->config->demod_address,rec_buf,2)) {
-               printk(KERN_WARNING "or51211: read_status read error\n");
-               return -1;
-       }
-       *snr = rec_buf[0] & 0xff;
-
-       dprintk("read_snr %i\n",*snr);
+       /* Calculate Strength from SNR up to 35dB */
+       /* Even though the SNR can go higher than 35dB, there is some comfort */
+       /* factor in having a range of strong signals that can show at 100%   */
+       struct or51211_state* state = (struct or51211_state*)fe->demodulator_priv;
+       u16 snr;
+       int ret;
+
+       ret = fe->ops.read_snr(fe, &snr);
+       if (ret != 0)
+               return ret;
+       /* Rather than use the 8.8 value snr, use state->snr which is 8.24 */
+       /* scale the range 0 - 35*2^24 into 0 - 65535 */
+       if (state->snr >= 8960 * 0x10000)
+               *strength = 0xffff;
+       else
+               *strength = state->snr / 8960;
 
        return 0;
 }
@@ -438,10 +413,10 @@ static int or51211_init(struct dvb_frontend* fe)
                }
 
                ret = or51211_load_firmware(fe, fw);
+               release_firmware(fw);
                if (ret) {
                        printk(KERN_WARNING "or51211: Writing firmware to "
                               "device failed!\n");
-                       release_firmware(fw);
                        return ret;
                }
                printk(KERN_INFO "or51211: Firmware upload complete.\n");
@@ -585,12 +560,11 @@ struct dvb_frontend* or51211_attach(const struct or51211_config* config,
        /* Setup the state */
        state->config = config;
        state->i2c = i2c;
-       memcpy(&state->ops, &or51211_ops, sizeof(struct dvb_frontend_ops));
        state->initialized = 0;
        state->current_frequency = 0;
 
        /* Create dvb_frontend */
-       state->frontend.ops = &state->ops;
+       memcpy(&state->frontend.ops, &or51211_ops, sizeof(struct dvb_frontend_ops));
        state->frontend.demodulator_priv = state;
        return &state->frontend;