diff options
-rw-r--r-- | drivers/media/dvb/frontends/or51211.c | 124 |
1 files changed, 50 insertions, 74 deletions
diff --git a/drivers/media/dvb/frontends/or51211.c b/drivers/media/dvb/frontends/or51211.c index 2bf124b53689..048d7cfe12d3 100644 --- a/drivers/media/dvb/frontends/or51211.c +++ b/drivers/media/dvb/frontends/or51211.c | |||
@@ -39,6 +39,7 @@ | |||
39 | #include <linux/slab.h> | 39 | #include <linux/slab.h> |
40 | #include <asm/byteorder.h> | 40 | #include <asm/byteorder.h> |
41 | 41 | ||
42 | #include "dvb_math.h" | ||
42 | #include "dvb_frontend.h" | 43 | #include "dvb_frontend.h" |
43 | #include "or51211.h" | 44 | #include "or51211.h" |
44 | 45 | ||
@@ -63,6 +64,7 @@ struct or51211_state { | |||
63 | 64 | ||
64 | /* Demodulator private data */ | 65 | /* Demodulator private data */ |
65 | u8 initialized:1; | 66 | u8 initialized:1; |
67 | u32 snr; /* Result of last SNR claculation */ | ||
66 | 68 | ||
67 | /* Tuner private data */ | 69 | /* Tuner private data */ |
68 | u32 current_frequency; | 70 | u32 current_frequency; |
@@ -292,107 +294,81 @@ static int or51211_read_status(struct dvb_frontend* fe, fe_status_t* status) | |||
292 | return 0; | 294 | return 0; |
293 | } | 295 | } |
294 | 296 | ||
295 | /* log10-1 table at .5 increments from 1 to 100.5 */ | 297 | /* Calculate SNR estimation (scaled by 2^24) |
296 | static unsigned int i100x20log10[] = { | ||
297 | 0, 352, 602, 795, 954, 1088, 1204, 1306, 1397, 1480, | ||
298 | 1556, 1625, 1690, 1750, 1806, 1858, 1908, 1955, 2000, 2042, | ||
299 | 2082, 2121, 2158, 2193, 2227, 2260, 2292, 2322, 2352, 2380, | ||
300 | 2408, 2434, 2460, 2486, 2510, 2534, 2557, 2580, 2602, 2623, | ||
301 | 2644, 2664, 2684, 2704, 2723, 2742, 2760, 2778, 2795, 2813, | ||
302 | 2829, 2846, 2862, 2878, 2894, 2909, 2924, 2939, 2954, 2968, | ||
303 | 2982, 2996, 3010, 3023, 3037, 3050, 3062, 3075, 3088, 3100, | ||
304 | 3112, 3124, 3136, 3148, 3159, 3170, 3182, 3193, 3204, 3214, | ||
305 | 3225, 3236, 3246, 3256, 3266, 3276, 3286, 3296, 3306, 3316, | ||
306 | 3325, 3334, 3344, 3353, 3362, 3371, 3380, 3389, 3397, 3406, | ||
307 | 3415, 3423, 3432, 3440, 3448, 3456, 3464, 3472, 3480, 3488, | ||
308 | 3496, 3504, 3511, 3519, 3526, 3534, 3541, 3549, 3556, 3563, | ||
309 | 3570, 3577, 3584, 3591, 3598, 3605, 3612, 3619, 3625, 3632, | ||
310 | 3639, 3645, 3652, 3658, 3665, 3671, 3677, 3683, 3690, 3696, | ||
311 | 3702, 3708, 3714, 3720, 3726, 3732, 3738, 3744, 3750, 3755, | ||
312 | 3761, 3767, 3772, 3778, 3784, 3789, 3795, 3800, 3806, 3811, | ||
313 | 3816, 3822, 3827, 3832, 3838, 3843, 3848, 3853, 3858, 3863, | ||
314 | 3868, 3874, 3879, 3884, 3888, 3893, 3898, 3903, 3908, 3913, | ||
315 | 3918, 3922, 3927, 3932, 3936, 3941, 3946, 3950, 3955, 3960, | ||
316 | 3964, 3969, 3973, 3978, 3982, 3986, 3991, 3995, 4000, 4004, | ||
317 | }; | ||
318 | |||
319 | static unsigned int denom[] = {1,1,100,1000,10000,100000,1000000,10000000,100000000}; | ||
320 | 298 | ||
321 | static unsigned int i20Log10(unsigned short val) | 299 | 8-VSB SNR equation from Oren datasheets |
322 | { | ||
323 | unsigned int rntval = 100; | ||
324 | unsigned int tmp = val; | ||
325 | unsigned int exp = 1; | ||
326 | 300 | ||
327 | while(tmp > 100) {tmp /= 100; exp++;} | 301 | For 8-VSB: |
302 | SNR[dB] = 10 * log10(219037.9454 / MSE^2 ) | ||
328 | 303 | ||
329 | val = (2 * val)/denom[exp]; | 304 | We re-write the snr equation as: |
330 | if (exp > 1) rntval = 2000*exp; | 305 | SNR * 2^24 = 10*(c - 2*intlog10(MSE)) |
306 | Where for 8-VSB, c = log10(219037.9454) * 2^24 */ | ||
331 | 307 | ||
332 | rntval += i100x20log10[val]; | 308 | static u32 calculate_snr(u32 mse, u32 c) |
333 | return rntval; | 309 | { |
310 | if (mse == 0) /* No signal */ | ||
311 | return 0; | ||
312 | |||
313 | mse = 2*intlog10(mse); | ||
314 | if (mse > c) { | ||
315 | /* Negative SNR, which is possible, but realisticly the | ||
316 | demod will lose lock before the signal gets this bad. The | ||
317 | API only allows for unsigned values, so just return 0 */ | ||
318 | return 0; | ||
319 | } | ||
320 | return 10*(c - mse); | ||
334 | } | 321 | } |
335 | 322 | ||
336 | static int or51211_read_signal_strength(struct dvb_frontend* fe, u16* strength) | 323 | static int or51211_read_snr(struct dvb_frontend* fe, u16* snr) |
337 | { | 324 | { |
338 | struct or51211_state* state = fe->demodulator_priv; | 325 | struct or51211_state* state = fe->demodulator_priv; |
339 | u8 rec_buf[2]; | 326 | u8 rec_buf[2]; |
340 | u8 snd_buf[4]; | 327 | u8 snd_buf[3]; |
341 | u8 snr_equ; | ||
342 | u32 signal_strength; | ||
343 | 328 | ||
344 | /* SNR after Equalizer */ | 329 | /* SNR after Equalizer */ |
345 | snd_buf[0] = 0x04; | 330 | snd_buf[0] = 0x04; |
346 | snd_buf[1] = 0x00; | 331 | snd_buf[1] = 0x00; |
347 | snd_buf[2] = 0x04; | 332 | snd_buf[2] = 0x04; |
348 | snd_buf[3] = 0x00; | ||
349 | 333 | ||
350 | if (i2c_writebytes(state,state->config->demod_address,snd_buf,3)) { | 334 | if (i2c_writebytes(state,state->config->demod_address,snd_buf,3)) { |
351 | printk(KERN_WARNING "or51211: read_status write error\n"); | 335 | printk(KERN_WARNING "%s: error writing snr reg\n", |
336 | __FUNCTION__); | ||
352 | return -1; | 337 | return -1; |
353 | } | 338 | } |
354 | msleep(3); | ||
355 | if (i2c_readbytes(state,state->config->demod_address,rec_buf,2)) { | 339 | if (i2c_readbytes(state,state->config->demod_address,rec_buf,2)) { |
356 | printk(KERN_WARNING "or51211: read_status read error\n"); | 340 | printk(KERN_WARNING "%s: read_status read error\n", |
341 | __FUNCTION__); | ||
357 | return -1; | 342 | return -1; |
358 | } | 343 | } |
359 | snr_equ = rec_buf[0] & 0xff; | ||
360 | 344 | ||
361 | /* The value reported back from the frontend will be FFFF=100% 0000=0% */ | 345 | state->snr = calculate_snr(rec_buf[0], 89599047); |
362 | signal_strength = (((5334 - i20Log10(snr_equ))/3+5)*65535)/1000; | 346 | *snr = (state->snr) >> 16; |
363 | if (signal_strength > 0xffff) | 347 | |
364 | *strength = 0xffff; | 348 | dprintk("%s: noise = 0x%02x, snr = %d.%02d dB\n", __FUNCTION__, rec_buf[0], |
365 | else | 349 | state->snr >> 24, (((state->snr>>8) & 0xffff) * 100) >> 16); |
366 | *strength = signal_strength; | ||
367 | dprintk("read_signal_strength %i\n",*strength); | ||
368 | 350 | ||
369 | return 0; | 351 | return 0; |
370 | } | 352 | } |
371 | 353 | ||
372 | static int or51211_read_snr(struct dvb_frontend* fe, u16* snr) | 354 | static int or51211_read_signal_strength(struct dvb_frontend* fe, u16* strength) |
373 | { | 355 | { |
374 | struct or51211_state* state = fe->demodulator_priv; | 356 | /* Calculate Strength from SNR up to 35dB */ |
375 | u8 rec_buf[2]; | 357 | /* Even though the SNR can go higher than 35dB, there is some comfort */ |
376 | u8 snd_buf[4]; | 358 | /* factor in having a range of strong signals that can show at 100% */ |
377 | 359 | struct or51211_state* state = (struct or51211_state*)fe->demodulator_priv; | |
378 | /* SNR after Equalizer */ | 360 | u16 snr; |
379 | snd_buf[0] = 0x04; | 361 | int ret; |
380 | snd_buf[1] = 0x00; | 362 | |
381 | snd_buf[2] = 0x04; | 363 | ret = fe->ops.read_snr(fe, &snr); |
382 | snd_buf[3] = 0x00; | 364 | if (ret != 0) |
383 | 365 | return ret; | |
384 | if (i2c_writebytes(state,state->config->demod_address,snd_buf,3)) { | 366 | /* Rather than use the 8.8 value snr, use state->snr which is 8.24 */ |
385 | printk(KERN_WARNING "or51211: read_status write error\n"); | 367 | /* scale the range 0 - 35*2^24 into 0 - 65535 */ |
386 | return -1; | 368 | if (state->snr >= 8960 * 0x10000) |
387 | } | 369 | *strength = 0xffff; |
388 | msleep(3); | 370 | else |
389 | if (i2c_readbytes(state,state->config->demod_address,rec_buf,2)) { | 371 | *strength = state->snr / 8960; |
390 | printk(KERN_WARNING "or51211: read_status read error\n"); | ||
391 | return -1; | ||
392 | } | ||
393 | *snr = rec_buf[0] & 0xff; | ||
394 | |||
395 | dprintk("read_snr %i\n",*snr); | ||
396 | 372 | ||
397 | return 0; | 373 | return 0; |
398 | } | 374 | } |