diff options
author | Rusty Scott <rustys@ieee.org> | 2006-12-04 16:04:16 -0500 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@infradead.org> | 2006-12-10 06:22:53 -0500 |
commit | 1444e5f591b8c68d7a326f5b0ad6c63a984d56dd (patch) | |
tree | 3f30789f0142578a54f074736242da4299b360b5 /drivers/media | |
parent | b2fb7f55a1837e39a9f74e2fd7be990ccba90eb4 (diff) |
V4L/DVB (4940): Or51211: Changed SNR and signal strength calculations
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')
-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 | } |